Skip to content

Commit 1ea7608

Browse files
committed
core/rawdb,eth: use lightweight accessor for log filtering
1 parent 7bcafec commit 1ea7608

File tree

3 files changed

+146
-6
lines changed

3 files changed

+146
-6
lines changed

core/rawdb/accessors_chain.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,37 @@ func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, t
712712
return nil
713713
}
714714

715+
// ReadLogs retrieves the logs for all transactions in a block. The log fields
716+
// are populated with metadata. In case the receipts or the block body
717+
// are not found, a nil is returned.
718+
func ReadLogs(db ethdb.Reader, hash common.Hash, number uint64) [][]*types.Log {
719+
// Retrieve the flattened receipt slice
720+
data := ReadReceiptsRLP(db, hash, number)
721+
if len(data) == 0 {
722+
return nil
723+
}
724+
receipts := []*receiptLogs{}
725+
if err := rlp.DecodeBytes(data, &receipts); err != nil {
726+
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
727+
return nil
728+
}
729+
730+
body := ReadBody(db, hash, number)
731+
if body == nil {
732+
log.Error("Missing body but have receipt", "hash", hash, "number", number)
733+
return nil
734+
}
735+
if err := deriveLogFields(receipts, hash, number, body.Transactions); err != nil {
736+
log.Error("Failed to derive block receipts fields", "hash", hash, "number", number, "err", err)
737+
return nil
738+
}
739+
logs := make([][]*types.Log, len(receipts))
740+
for i, receipt := range receipts {
741+
logs[i] = receipt.Logs
742+
}
743+
return logs
744+
}
745+
715746
// ReadBlock retrieves an entire block corresponding to the hash, assembling it
716747
// back from the stored header and body. If either the header or body could not
717748
// be retrieved nil is returned.

core/rawdb/accessors_chain_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,114 @@ func makeTestReceipts(n int, nPerBlock int) []types.Receipts {
671671
return allReceipts
672672
}
673673

674+
type fullLogRLP struct {
675+
Address common.Address
676+
Topics []common.Hash
677+
Data []byte
678+
BlockNumber uint64
679+
TxHash common.Hash
680+
TxIndex uint
681+
BlockHash common.Hash
682+
Index uint
683+
}
684+
685+
func newFullLogRLP(l *types.Log) *fullLogRLP {
686+
return &fullLogRLP{
687+
Address: l.Address,
688+
Topics: l.Topics,
689+
Data: l.Data,
690+
BlockNumber: l.BlockNumber,
691+
TxHash: l.TxHash,
692+
TxIndex: l.TxIndex,
693+
BlockHash: l.BlockHash,
694+
Index: l.Index,
695+
}
696+
}
697+
698+
// Tests that logs associated with a single block can be retrieved.
699+
func TestReadLogs(t *testing.T) {
700+
db := NewMemoryDatabase()
701+
702+
// Create a live block since we need metadata to reconstruct the receipt
703+
tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil)
704+
tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil)
705+
706+
body := &types.Body{Transactions: types.Transactions{tx1, tx2}}
707+
708+
// Create the two receipts to manage afterwards
709+
receipt1 := &types.Receipt{
710+
Status: types.ReceiptStatusFailed,
711+
CumulativeGasUsed: 1,
712+
Logs: []*types.Log{
713+
{Address: common.BytesToAddress([]byte{0x11})},
714+
{Address: common.BytesToAddress([]byte{0x01, 0x11})},
715+
},
716+
TxHash: tx1.Hash(),
717+
ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
718+
GasUsed: 111111,
719+
}
720+
receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1})
721+
722+
receipt2 := &types.Receipt{
723+
PostState: common.Hash{2}.Bytes(),
724+
CumulativeGasUsed: 2,
725+
Logs: []*types.Log{
726+
{Address: common.BytesToAddress([]byte{0x22})},
727+
{Address: common.BytesToAddress([]byte{0x02, 0x22})},
728+
},
729+
TxHash: tx2.Hash(),
730+
ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
731+
GasUsed: 222222,
732+
}
733+
receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2})
734+
receipts := []*types.Receipt{receipt1, receipt2}
735+
736+
hash := common.BytesToHash([]byte{0x03, 0x14})
737+
// Check that no receipt entries are in a pristine database
738+
if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 {
739+
t.Fatalf("non existent receipts returned: %v", rs)
740+
}
741+
// Insert the body that corresponds to the receipts
742+
WriteBody(db, hash, 0, body)
743+
744+
// Insert the receipt slice into the database and check presence
745+
WriteReceipts(db, hash, 0, receipts)
746+
747+
logs := ReadLogs(db, hash, 0)
748+
if len(logs) == 0 {
749+
t.Fatalf("no logs returned")
750+
}
751+
if have, want := len(logs), 2; have != want {
752+
t.Fatalf("unexpected number of logs returned, have %d want %d", have, want)
753+
}
754+
if have, want := len(logs[0]), 2; have != want {
755+
t.Fatalf("unexpected number of logs[0] returned, have %d want %d", have, want)
756+
}
757+
if have, want := len(logs[1]), 2; have != want {
758+
t.Fatalf("unexpected number of logs[1] returned, have %d want %d", have, want)
759+
}
760+
761+
// Fill in log fields so we can compare their rlp encoding
762+
if err := types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, 0, body.Transactions); err != nil {
763+
t.Fatal(err)
764+
}
765+
for i, pr := range receipts {
766+
for j, pl := range pr.Logs {
767+
rlpHave, err := rlp.EncodeToBytes(newFullLogRLP(logs[i][j]))
768+
if err != nil {
769+
t.Fatal(err)
770+
}
771+
rlpWant, err := rlp.EncodeToBytes(newFullLogRLP(pl))
772+
if err != nil {
773+
t.Fatal(err)
774+
}
775+
if !bytes.Equal(rlpHave, rlpWant) {
776+
t.Fatalf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant))
777+
}
778+
}
779+
}
780+
}
781+
674782
func TestDeriveLogFields(t *testing.T) {
675783
// Create a few transactions to have receipts for
676784
to2 := common.HexToAddress("0x2")

eth/api_backend.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -181,13 +181,14 @@ func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (type
181181
}
182182

183183
func (b *EthAPIBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
184-
receipts := b.eth.blockchain.GetReceiptsByHash(hash)
185-
if receipts == nil {
186-
return nil, nil
184+
db := b.eth.ChainDb()
185+
number := rawdb.ReadHeaderNumber(db, hash)
186+
if number == nil {
187+
return nil, errors.New("failed to get block number from hash")
187188
}
188-
logs := make([][]*types.Log, len(receipts))
189-
for i, receipt := range receipts {
190-
logs[i] = receipt.Logs
189+
logs := rawdb.ReadLogs(db, hash, *number)
190+
if logs == nil {
191+
return nil, errors.New("failed to get logs for block")
191192
}
192193
return logs, nil
193194
}

0 commit comments

Comments
 (0)