Skip to content

Commit 7bcafec

Browse files
committed
core/rawdb: add lightweight types for block logs
1 parent ffa02d0 commit 7bcafec

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

core/rawdb/accessors_chain.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package rawdb
1919
import (
2020
"bytes"
2121
"encoding/binary"
22+
"errors"
2223
"fmt"
2324
"math/big"
2425
"sort"
@@ -663,6 +664,54 @@ func DeleteReceipts(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
663664
}
664665
}
665666

667+
// storedReceiptRLP is the storage encoding of a receipt.
668+
// Re-definition in core/types/receipt.go.
669+
type storedReceiptRLP struct {
670+
PostStateOrStatus []byte
671+
CumulativeGasUsed uint64
672+
Logs []*types.LogForStorage
673+
}
674+
675+
// ReceiptLogs is a barebone version of ReceiptForStorage which only keeps
676+
// the list of logs.
677+
type receiptLogs struct {
678+
Logs []*types.Log
679+
}
680+
681+
// DecodeRLP implements rlp.Decoder.
682+
func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error {
683+
var stored storedReceiptRLP
684+
if err := s.Decode(&stored); err != nil {
685+
return err
686+
}
687+
r.Logs = make([]*types.Log, len(stored.Logs))
688+
for i, log := range stored.Logs {
689+
r.Logs[i] = (*types.Log)(log)
690+
}
691+
return nil
692+
}
693+
694+
// DeriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc.
695+
func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error {
696+
logIndex := uint(0)
697+
if len(txs) != len(receipts) {
698+
return errors.New("transaction and receipt count mismatch")
699+
}
700+
for i := 0; i < len(receipts); i++ {
701+
txHash := txs[i].Hash()
702+
// The derived log fields can simply be set from the block and transaction
703+
for j := 0; j < len(receipts[i].Logs); j++ {
704+
receipts[i].Logs[j].BlockNumber = number
705+
receipts[i].Logs[j].BlockHash = hash
706+
receipts[i].Logs[j].TxHash = txHash
707+
receipts[i].Logs[j].TxIndex = uint(i)
708+
receipts[i].Logs[j].Index = logIndex
709+
logIndex++
710+
}
711+
}
712+
return nil
713+
}
714+
666715
// ReadBlock retrieves an entire block corresponding to the hash, assembling it
667716
// back from the stored header and body. If either the header or body could not
668717
// be retrieved nil is returned.

core/rawdb/accessors_chain_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,3 +670,82 @@ func makeTestReceipts(n int, nPerBlock int) []types.Receipts {
670670
}
671671
return allReceipts
672672
}
673+
674+
func TestDeriveLogFields(t *testing.T) {
675+
// Create a few transactions to have receipts for
676+
to2 := common.HexToAddress("0x2")
677+
to3 := common.HexToAddress("0x3")
678+
txs := types.Transactions{
679+
types.NewTx(&types.LegacyTx{
680+
Nonce: 1,
681+
Value: big.NewInt(1),
682+
Gas: 1,
683+
GasPrice: big.NewInt(1),
684+
}),
685+
types.NewTx(&types.LegacyTx{
686+
To: &to2,
687+
Nonce: 2,
688+
Value: big.NewInt(2),
689+
Gas: 2,
690+
GasPrice: big.NewInt(2),
691+
}),
692+
types.NewTx(&types.AccessListTx{
693+
To: &to3,
694+
Nonce: 3,
695+
Value: big.NewInt(3),
696+
Gas: 3,
697+
GasPrice: big.NewInt(3),
698+
}),
699+
}
700+
// Create the corresponding receipts
701+
receipts := []*receiptLogs{
702+
{
703+
Logs: []*types.Log{
704+
{Address: common.BytesToAddress([]byte{0x11})},
705+
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
706+
},
707+
},
708+
{
709+
Logs: []*types.Log{
710+
{Address: common.BytesToAddress([]byte{0x22})},
711+
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
712+
},
713+
},
714+
{
715+
Logs: []*types.Log{
716+
{Address: common.BytesToAddress([]byte{0x33})},
717+
{Address: common.BytesToAddress([]byte{0x03, 0x33})},
718+
},
719+
},
720+
}
721+
722+
// Derive log metadata fields
723+
number := big.NewInt(1)
724+
hash := common.BytesToHash([]byte{0x03, 0x14})
725+
if err := deriveLogFields(receipts, hash, number.Uint64(), txs); err != nil {
726+
t.Fatal(err)
727+
}
728+
729+
// Iterate over all the computed fields and check that they're correct
730+
logIndex := uint(0)
731+
for i := range receipts {
732+
for j := range receipts[i].Logs {
733+
if receipts[i].Logs[j].BlockNumber != number.Uint64() {
734+
t.Errorf("receipts[%d].Logs[%d].BlockNumber = %d, want %d", i, j, receipts[i].Logs[j].BlockNumber, number.Uint64())
735+
}
736+
if receipts[i].Logs[j].BlockHash != hash {
737+
t.Errorf("receipts[%d].Logs[%d].BlockHash = %s, want %s", i, j, receipts[i].Logs[j].BlockHash.String(), hash.String())
738+
}
739+
if receipts[i].Logs[j].TxHash != txs[i].Hash() {
740+
t.Errorf("receipts[%d].Logs[%d].TxHash = %s, want %s", i, j, receipts[i].Logs[j].TxHash.String(), txs[i].Hash().String())
741+
}
742+
if receipts[i].Logs[j].TxIndex != uint(i) {
743+
t.Errorf("receipts[%d].Logs[%d].TransactionIndex = %d, want %d", i, j, receipts[i].Logs[j].TxIndex, i)
744+
}
745+
if receipts[i].Logs[j].Index != logIndex {
746+
t.Errorf("receipts[%d].Logs[%d].Index = %d, want %d", i, j, receipts[i].Logs[j].Index, logIndex)
747+
}
748+
logIndex++
749+
}
750+
}
751+
}

0 commit comments

Comments
 (0)