From e2516dc9ec3438325a4fc6c87ac6d58088419669 Mon Sep 17 00:00:00 2001 From: JukLee0ira Date: Fri, 19 Jul 2024 01:58:46 +0800 Subject: [PATCH] core, eth, les, light: avoid storing computable receipt metadata (19345) --- accounts/abi/bind/backends/simulated.go | 4 +- core/bench_test.go | 2 +- core/blockchain.go | 9 +-- core/blockchain_test.go | 9 +-- core/rawdb/accessors_chain.go | 7 ++ core/rawdb/accessors_chain_test.go | 94 +++++++++++++++++++++++++ core/rawdb/accessors_indexes.go | 24 +++++++ core/types/receipt.go | 43 ++++++++--- core/types/receipt_test.go | 12 ++++ eth/downloader/fakepeer.go | 3 +- eth/filters/filter_system_test.go | 2 +- les/handler.go | 2 +- les/handler_test.go | 5 +- les/odr_test.go | 11 ++- light/odr_test.go | 4 +- light/odr_util.go | 18 +++-- 16 files changed, 209 insertions(+), 40 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 08a7260d264f..3ed5b94982b4 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -252,7 +252,7 @@ func (b *SimulatedBackend) ForEachStorageAt(ctx context.Context, contract common // TransactionReceipt returns the receipt of a transaction. func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - receipt, _, _, _ := core.GetReceipt(b.database, txHash) + receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash, b.config) return receipt, nil } @@ -552,7 +552,7 @@ func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*t } func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { - return core.GetBlockReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash)), nil + return rawdb.ReadReceipts(fb.db, hash, core.GetBlockNumber(fb.db, hash), fb.bc.Config()), nil } func (fb *filterBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) { diff --git a/core/bench_test.go b/core/bench_test.go index 1129142b1af6..56e138f65514 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -294,7 +294,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if full { hash := header.Hash() GetBody(db, hash, n) - GetBlockReceipts(db, hash, n) + rawdb.ReadReceipts(db, hash, n, chain.Config()) } } diff --git a/core/blockchain.go b/core/blockchain.go index 6926d2286638..6b8f548dce13 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -815,7 +815,8 @@ func (bc *BlockChain) GetBlockByNumber(number uint64) *types.Block { // GetReceiptsByHash retrieves the receipts for all transactions in a given block. func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { - return GetBlockReceipts(bc.db, hash, GetBlockNumber(bc.db, hash)) + // return GetBlockReceipts(bc.db, hash, GetBlockNumber(bc.db, hash)) + return rawdb.ReadReceipts(bc.db, hash, GetBlockNumber(bc.db, hash), bc.chainConfig) } // GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. @@ -1116,8 +1117,8 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [ continue } // Compute all the non-consensus fields of the receipts - if err := SetReceiptsData(bc.chainConfig, block, receipts); err != nil { - return i, fmt.Errorf("failed to set receipts data: %v", err) + if err := receipts.DeriveFields(bc.chainConfig, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { + return i, fmt.Errorf("failed to derive receipts data: %v", err) } // Write all the data out into the database rawdb.WriteBody(batch, block.Hash(), block.NumberU64(), block.Body()) @@ -2155,7 +2156,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { // These logs are later announced as deleted. collectLogs = func(h common.Hash) { // Coalesce logs and set 'Removed'. - receipts := GetBlockReceipts(bc.db, h, bc.hc.GetBlockNumber(h)) + receipts := rawdb.ReadReceipts(bc.db, h, bc.hc.GetBlockNumber(h), bc.chainConfig) for _, receipt := range receipts { for _, log := range receipt.Logs { del := *log diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 87b58bf3ad0a..ce0308b058b7 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -32,6 +32,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/crypto" + "github.com/XinFinOrg/XDPoSChain/params" ) @@ -623,7 +624,7 @@ func TestFastVsFullChains(t *testing.T) { } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) { t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles()) } - if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { + if freceipts, areceipts := rawdb.ReadReceipts(fastDb, hash, *rawdb.ReadHeaderNumber(fastDb, hash), fast.Config()), rawdb.ReadReceipts(archiveDb, hash, *rawdb.ReadHeaderNumber(archiveDb, hash), archive.Config()); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts) } } @@ -808,7 +809,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt != nil { t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) } } @@ -817,7 +818,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("add %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil { t.Errorf("add %d: expected receipt to be found", i) } } @@ -826,7 +827,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("share %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.Config()); rcpt == nil { t.Errorf("share %d: expected receipt to be found", i) } } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 1d224c0d60f1..97ce46b293d3 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -135,6 +135,13 @@ func ReadBody(db ethdb.Reader, hash common.Hash, number uint64) *types.Body { return body } +// DeleteBody removes all block body data associated with a hash. +func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { + if err := db.Delete(blockBodyKey(number, hash)); err != nil { + log.Crit("Failed to delete block body", "err", err) + } +} + // WriteBody stores a block body into the database. func WriteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64, body *types.Body) { data, err := rlp.EncodeToBytes(body) diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index a514c5857fdc..cede6176f0de 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -19,6 +19,7 @@ package rawdb import ( "bytes" "encoding/hex" + "fmt" "io/ioutil" "math/big" "testing" @@ -237,3 +238,96 @@ func BenchmarkDecodeRLPLogs(b *testing.B) { } }) } + +// Tests that receipts associated with a single block can be stored and retrieved. +func TestBlockReceiptStorage(t *testing.T) { + db := NewMemoryDatabase() + + // Create a live block since we need metadata to reconstruct the receipt + tx1 := types.NewTransaction(1, common.HexToAddress("0x1"), big.NewInt(1), 1, big.NewInt(1), nil) + tx2 := types.NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil) + + body := &types.Body{Transactions: types.Transactions{tx1, tx2}} + + // Create the two receipts to manage afterwards + receipt1 := &types.Receipt{ + Status: types.ReceiptStatusFailed, + CumulativeGasUsed: 1, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x11})}, + {Address: common.BytesToAddress([]byte{0x01, 0x11})}, + }, + TxHash: tx1.Hash(), + ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), + GasUsed: 111111, + } + receipt1.Bloom = types.CreateBloom(types.Receipts{receipt1}) + + receipt2 := &types.Receipt{ + PostState: common.Hash{2}.Bytes(), + CumulativeGasUsed: 2, + Logs: []*types.Log{ + {Address: common.BytesToAddress([]byte{0x22})}, + {Address: common.BytesToAddress([]byte{0x02, 0x22})}, + }, + TxHash: tx2.Hash(), + ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), + GasUsed: 222222, + } + receipt2.Bloom = types.CreateBloom(types.Receipts{receipt2}) + receipts := []*types.Receipt{receipt1, receipt2} + + // Check that no receipt entries are in a pristine database + hash := common.BytesToHash([]byte{0x03, 0x14}) + if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { + t.Fatalf("non existent receipts returned: %v", rs) + } + // Insert the body that corresponds to the receipts + WriteBody(db, hash, 0, body) + + // Insert the receipt slice into the database and check presence + WriteReceipts(db, hash, 0, receipts) + if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) == 0 { + t.Fatalf("no receipts returned") + } else { + if err := checkReceiptsRLP(rs, receipts); err != nil { + t.Fatalf(err.Error()) + } + } + // Delete the body and ensure that the receipts are no longer returned (metadata can't be recomputed) + DeleteBody(db, hash, 0) + if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); rs != nil { + t.Fatalf("receipts returned when body was deleted: %v", rs) + } + // Ensure that receipts without metadata can be returned without the block body too + if err := checkReceiptsRLP(ReadRawReceipts(db, hash, 0), receipts); err != nil { + t.Fatalf(err.Error()) + } + // Sanity check that body alone without the receipt is a full purge + WriteBody(db, hash, 0, body) + + DeleteReceipts(db, hash, 0) + if rs := ReadReceipts(db, hash, 0, params.TestChainConfig); len(rs) != 0 { + t.Fatalf("deleted receipts returned: %v", rs) + } +} + +func checkReceiptsRLP(have, want types.Receipts) error { + if len(have) != len(want) { + return fmt.Errorf("receipts sizes mismatch: have %d, want %d", len(have), len(want)) + } + for i := 0; i < len(want); i++ { + rlpHave, err := rlp.EncodeToBytes(have[i]) + if err != nil { + return err + } + rlpWant, err := rlp.EncodeToBytes(want[i]) + if err != nil { + return err + } + if !bytes.Equal(rlpHave, rlpWant) { + return fmt.Errorf("receipt #%d: receipt mismatch: have %s, want %s", i, hex.EncodeToString(rlpHave), hex.EncodeToString(rlpWant)) + } + } + return nil +} diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index aa970bd2fa43..2b0c8317e2aa 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -21,6 +21,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/log" + "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rlp" ) @@ -82,3 +83,26 @@ func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, com log.Error("Transaction not found", "number", blockNumber, "hash", blockHash, "txhash", hash) return nil, common.Hash{}, 0, 0 } + +// ReadReceipt retrieves a specific transaction receipt from the database, along with +// its added positional metadata. +func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) { + // Retrieve the context of the receipt based on the transaction hash + blockHash := ReadTxLookupEntry(db, hash) + if blockHash == (common.Hash{}) { + return nil, common.Hash{}, 0, 0 + } + blockNumber := ReadHeaderNumber(db, blockHash) + if blockNumber == nil { + return nil, common.Hash{}, 0, 0 + } + // Read all the receipts from the block and return the one with the matching hash + receipts := ReadReceipts(db, blockHash, *blockNumber, config) + for receiptIndex, receipt := range receipts { + if receipt.TxHash == hash { + return receipt, blockHash, *blockNumber, uint64(receiptIndex) + } + } + log.Error("Receipt not found", "number", blockNumber, "hash", blockHash, "txhash", hash) + return nil, common.Hash{}, 0, 0 +} diff --git a/core/types/receipt.go b/core/types/receipt.go index 74236bb101ca..db580e055b7f 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -90,6 +90,13 @@ type receiptRLP struct { Logs []*Log } +// storedReceiptRLP is the storage encoding of a receipt. +type storedReceiptRLP struct { + PostStateOrStatus []byte + CumulativeGasUsed uint64 + Logs []*LogForStorage +} + // v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4. type v4StoredReceiptRLP struct { PostStateOrStatus []byte @@ -269,7 +276,6 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { TxHash: r.TxHash, ContractAddress: r.ContractAddress, Logs: make([]*LogForStorage, len(r.Logs)), - GasUsed: r.GasUsed, } for i, log := range r.Logs { enc.Logs[i] = (*LogForStorage)(log) @@ -288,31 +294,30 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { // Try decoding from the newest format for future proofness, then the older one // for old nodes that just upgraded. V4 was an intermediate unreleased format so // we do need to decode it, but it's not common (try last). + if err := decodeStoredReceiptRLP(r, blob); err == nil { + return nil + } if err := decodeV3StoredReceiptRLP(r, blob); err == nil { return nil } return decodeV4StoredReceiptRLP(r, blob) } -func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { - var stored v3StoredReceiptRLP +func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { + var stored storedReceiptRLP if err := rlp.DecodeBytes(blob, &stored); err != nil { return err } if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { return err } - // Assign the consensus fields r.CumulativeGasUsed = stored.CumulativeGasUsed - r.Bloom = stored.Bloom r.Logs = make([]*Log, len(stored.Logs)) for i, log := range stored.Logs { r.Logs[i] = (*Log)(log) } - // Assign the implementation fields - r.TxHash = stored.TxHash - r.ContractAddress = stored.ContractAddress - r.GasUsed = stored.GasUsed + r.Bloom = CreateBloom(Receipts{(*Receipt)(r)}) + return nil } @@ -337,6 +342,26 @@ func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { return nil } +func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { + var stored v3StoredReceiptRLP + if err := rlp.DecodeBytes(blob, &stored); err != nil { + return err + } + if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { + return err + } + r.CumulativeGasUsed = stored.CumulativeGasUsed + r.Bloom = stored.Bloom + r.TxHash = stored.TxHash + r.ContractAddress = stored.ContractAddress + r.GasUsed = stored.GasUsed + r.Logs = make([]*Log, len(stored.Logs)) + for i, log := range stored.Logs { + r.Logs[i] = (*Log)(log) + } + return nil +} + // Receipts implements DerivableList for receipts. type Receipts []*Receipt diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 1ca5a2864774..9f2d44d52317 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -113,6 +113,18 @@ func TestLegacyReceiptDecoding(t *testing.T) { } } +func encodeAsStoredReceiptRLP(want *Receipt) ([]byte, error) { + stored := &storedReceiptRLP{ + PostStateOrStatus: want.statusEncoding(), + CumulativeGasUsed: want.CumulativeGasUsed, + Logs: make([]*LogForStorage, len(want.Logs)), + } + for i, log := range want.Logs { + stored.Logs[i] = (*LogForStorage)(log) + } + return rlp.EncodeToBytes(stored) +} + func encodeAsV4StoredReceiptRLP(want *Receipt) ([]byte, error) { stored := &v4StoredReceiptRLP{ PostStateOrStatus: want.statusEncoding(), diff --git a/eth/downloader/fakepeer.go b/eth/downloader/fakepeer.go index 9d399795d06d..fc905174b8f4 100644 --- a/eth/downloader/fakepeer.go +++ b/eth/downloader/fakepeer.go @@ -21,6 +21,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core" + "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/ethdb" ) @@ -140,7 +141,7 @@ func (p *FakePeer) RequestBodies(hashes []common.Hash) error { func (p *FakePeer) RequestReceipts(hashes []common.Hash) error { var receipts [][]*types.Receipt for _, hash := range hashes { - receipts = append(receipts, core.GetBlockReceipts(p.db, hash, p.hc.GetBlockNumber(hash))) + receipts = append(receipts, rawdb.ReadRawReceipts(p.db, hash, p.hc.GetBlockNumber(hash))) } p.dl.DeliverReceipts(p.id, receipts) return nil diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 2610376d3bf3..1aaf463c66df 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -83,7 +83,7 @@ func (b *testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc. func (b *testBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) { number := core.GetBlockNumber(b.db, blockHash) - return core.GetBlockReceipts(b.db, blockHash, number), nil + return rawdb.ReadReceipts(b.db, blockHash, number, params.TestChainConfig), nil } func (b *testBackend) GetLogs(ctx context.Context, hash common.Hash, number uint64) ([][]*types.Log, error) { diff --git a/les/handler.go b/les/handler.go index 5382f9b014f7..71d85c0adfdb 100644 --- a/les/handler.go +++ b/les/handler.go @@ -664,7 +664,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { break } // Retrieve the requested block's receipts, skipping if unknown to us - results := core.GetBlockReceipts(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)) + results := rawdb.ReadRawReceipts(pm.chainDb, hash, core.GetBlockNumber(pm.chainDb, hash)) if results == nil { if header := pm.blockchain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { continue diff --git a/les/handler_test.go b/les/handler_test.go index 0c17cf965897..ce191a5a9f9a 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -18,12 +18,13 @@ package les import ( "encoding/binary" - "github.com/XinFinOrg/XDPoSChain/core/rawdb" "math/big" "math/rand" "testing" "time" + "github.com/XinFinOrg/XDPoSChain/core/rawdb" + "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core" @@ -304,7 +305,7 @@ func testGetReceipt(t *testing.T, protocol int) { block := bc.GetBlockByNumber(i) hashes = append(hashes, block.Hash()) - receipts = append(receipts, core.GetBlockReceipts(db, block.Hash(), block.NumberU64())) + receipts = append(receipts, rawdb.ReadRawReceipts(db, block.Hash(), block.NumberU64())) } // Send the hash request and verify the response cost := peer.GetRequestCost(GetReceiptsMsg, len(hashes)) diff --git a/les/odr_test.go b/les/odr_test.go index 1234bd28536b..a9a104e76e42 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -64,7 +64,7 @@ func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainCon func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte { var receipts types.Receipts if bc != nil { - receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) + receipts = rawdb.ReadReceipts(db, bhash, core.GetBlockNumber(db, bhash), config) } else { receipts, _ = light.GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) } @@ -189,6 +189,9 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { lpm.synchronise(lpeer) test := func(expFail uint64) { + // Mark this as a helper to put the failures at the correct lines + t.Helper() + for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { bhash := core.GetCanonicalHash(db, i) b1 := fn(light.NoOdr, db, pm.chainConfig, pm.blockchain.(*core.BlockChain), nil, bhash) @@ -200,10 +203,10 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { eq := bytes.Equal(b1, b2) exp := i < expFail if exp && !eq { - t.Errorf("odr mismatch") + t.Fatalf("odr mismatch: have %x, want %x", b2, b1) } if !exp && eq { - t.Errorf("unexpected odr match") + t.Fatalf("unexpected odr match") } } } @@ -213,6 +216,7 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { peers.Unregister(lpeer.id) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed test(expFail) + // expect all retrievals to pass peers.Register(lpeer) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed @@ -220,6 +224,7 @@ func testOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) { lpeer.hasBlock = func(common.Hash, uint64) bool { return true } lpeer.lock.Unlock() test(5) + // still expect all retrievals to pass, now data should be cached locally peers.Unregister(lpeer.id) time.Sleep(time.Millisecond * 10) // ensure that all peerSetNotify callbacks are executed diff --git a/light/odr_test.go b/light/odr_test.go index 83e1c807caf6..07c224501925 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -75,7 +75,7 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error { case *BlockRequest: req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) case *ReceiptsRequest: - req.Receipts = core.GetBlockReceipts(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) + req.Receipts = rawdb.ReadRawReceipts(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash)) case *TrieRequest: t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) nodes := NewNodeSet() @@ -111,7 +111,7 @@ func TestOdrGetReceiptsLes1(t *testing.T) { testChainOdr(t, 1, odrGetReceipts) } func odrGetReceipts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) { var receipts types.Receipts if bc != nil { - receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash)) + receipts = rawdb.ReadReceipts(db, bhash, core.GetBlockNumber(db, bhash), bc.Config()) } else { receipts, _ = GetBlockReceipts(ctx, lc.Odr(), bhash, core.GetBlockNumber(db, bhash)) } diff --git a/light/odr_util.go b/light/odr_util.go index d7ebd6739f75..a73795e5eeb5 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -22,6 +22,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core" + "github.com/XinFinOrg/XDPoSChain/core/rawdb" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/rlp" @@ -126,8 +127,8 @@ func GetBlock(ctx context.Context, odr OdrBackend, hash common.Hash, number uint // GetBlockReceipts retrieves the receipts generated by the transactions included // in a block given by its hash. Receipts will be filled in with context data. func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) (types.Receipts, error) { - // Retrieve the potentially incomplete receipts from disk or network - receipts := core.GetBlockReceipts(odr.Database(), hash, number) + // Assume receipts are already stored locally and attempt to retrieve. + receipts := rawdb.ReadRawReceipts(odr.Database(), hash, number) if receipts == nil { r := &ReceiptsRequest{Hash: hash, Number: number} if err := odr.Retrieve(ctx, r); err != nil { @@ -144,7 +145,7 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num genesis := core.GetCanonicalHash(odr.Database(), 0) config, _ := core.GetChainConfig(odr.Database(), genesis) - if err := core.SetReceiptsData(config, block, receipts); err != nil { + if err := receipts.DeriveFields(config, block.Hash(), block.NumberU64(), block.Transactions()); err != nil { return nil, err } core.WriteBlockReceipts(odr.Database(), hash, number, receipts) @@ -155,13 +156,10 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num // GetBlockLogs retrieves the logs generated by the transactions included in a // block given by its hash. Logs will be filled in with context data. func GetBlockLogs(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) ([][]*types.Log, error) { - receipts := core.GetBlockReceipts(odr.Database(), hash, number) - if receipts == nil { - r := &ReceiptsRequest{Hash: hash, Number: number} - if err := odr.Retrieve(ctx, r); err != nil { - return nil, err - } - receipts = r.Receipts + // Retrieve the potentially incomplete receipts from disk or network + receipts, err := GetBlockReceipts(ctx, odr, hash, number) + if err != nil { + return nil, err } // Return the logs without deriving any computed fields on the receipts logs := make([][]*types.Log, len(receipts))