diff --git a/les/odr_requests.go b/les/odr_requests.go index 34d759dd2a..c91f836e2e 100644 --- a/les/odr_requests.go +++ b/les/odr_requests.go @@ -140,20 +140,20 @@ func (r *ReceiptsRequest) GetCost(peer *peer) uint64 { // CanSend tells if a certain peer is suitable for serving the given request func (r *ReceiptsRequest) CanSend(peer *peer) bool { - return peer.HasBlock(r.Hash, r.Number) + return peer.HasBlock(r.Block.Hash(), r.Block.NumberU64()) } // Request sends an ODR request to the LES network (implementation of LesOdrRequest) func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error { - peer.Log().Debug("Requesting block receipts", "hash", r.Hash) - return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash}) + peer.Log().Debug("Requesting block receipts", "hash", r.Block.Hash()) + return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Block.Hash()}) } // Valid processes an ODR request reply message from the LES network // returns true and stores results in memory if the message was a valid reply // to the request (implementation of LesOdrRequest) func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { - log.Debug("Validating block receipts", "hash", r.Hash) + log.Debug("Validating block receipts", "hash", r.Block.Hash()) // Ensure we have a correct message with a single block receipt if msg.MsgType != MsgReceipts { @@ -166,14 +166,12 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { receipt := receipts[0] // Retrieve our stored header and validate receipt content against it - header := core.GetHeader(db, r.Hash, r.Number) - if header == nil { - return errHeaderUnavailable - } - if header.ReceiptHash != types.DeriveSha(receipt) { + if r.Block.ReceiptHash() != types.DeriveSha(receipt) { return errReceiptHashMismatch } // Validations passed, store and return + core.SetReceiptsData(r.Config, r.Block, receipt) + r.Receipts = receipt return nil } diff --git a/les/request_test.go b/les/request_test.go index c13625de8e..5fcdbcfef4 100644 --- a/les/request_test.go +++ b/les/request_test.go @@ -35,13 +35,13 @@ func secAddr(addr common.Address) []byte { return crypto.Keccak256(addr[:]) } -type accessTestFn func(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest +type accessTestFn func(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest func TestBlockAccessLes1(t *testing.T) { testAccess(t, 1, tfBlockAccess) } func TestBlockAccessLes2(t *testing.T) { testAccess(t, 2, tfBlockAccess) } -func tfBlockAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { +func tfBlockAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest { return &light.BlockRequest{Hash: bhash, Number: number} } @@ -49,24 +49,30 @@ func TestReceiptsAccessLes1(t *testing.T) { testAccess(t, 1, tfReceiptsAccess) } func TestReceiptsAccessLes2(t *testing.T) { testAccess(t, 2, tfReceiptsAccess) } -func tfReceiptsAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { - return &light.ReceiptsRequest{Hash: bhash, Number: number} +func tfReceiptsAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest { + odr.Retrieve(context.TODO(), &light.BlockRequest{Hash: bhash, Number: number}) + + block := core.GetBlock(odr.Database(), bhash, number) + genesis := core.GetCanonicalHash(odr.Database(), 0) + config, _ := core.GetChainConfig(odr.Database(), genesis) + + return &light.ReceiptsRequest{Config: config, Block: block} } func TestTrieEntryAccessLes1(t *testing.T) { testAccess(t, 1, tfTrieEntryAccess) } func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) } -func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { - return &light.TrieRequest{Id: light.StateTrieID(core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash))), Key: testBankSecureTrieKey} +func tfTrieEntryAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest { + return &light.TrieRequest{Id: light.StateTrieID(core.GetHeader(odr.Database(), bhash, core.GetBlockNumber(odr.Database(), bhash))), Key: testBankSecureTrieKey} } func TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) } func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) } -func tfCodeAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest { - header := core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash)) +func tfCodeAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest { + header := core.GetHeader(odr.Database(), bhash, core.GetBlockNumber(odr.Database(), bhash)) if header.Number.Uint64() < testContractDeployed { return nil } @@ -100,7 +106,7 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) { test := func(expFail uint64) { for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ { bhash := core.GetCanonicalHash(db, i) - if req := fn(ldb, bhash, i); req != nil { + if req := fn(odr, bhash, i); req != nil { ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond) defer cancel() diff --git a/light/odr.go b/light/odr.go index e2c3d9c5a4..4989d339a9 100644 --- a/light/odr.go +++ b/light/odr.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" ) // NoOdr is the default context passed to an ODR capable function when the ODR @@ -118,14 +119,14 @@ func (req *BlockRequest) StoreResult(db ethdb.Database) { // ReceiptsRequest is the ODR request type for retrieving block bodies type ReceiptsRequest struct { OdrRequest - Hash common.Hash - Number uint64 + Config *params.ChainConfig + Block *types.Block Receipts types.Receipts } // StoreResult stores the retrieved data in local database func (req *ReceiptsRequest) StoreResult(db ethdb.Database) { - core.WriteBlockReceipts(db, req.Hash, req.Number, req.Receipts) + core.WriteBlockReceipts(db, req.Block.Hash(), req.Block.NumberU64(), req.Receipts) } // ChtRequest is the ODR request type for state/storage trie entries diff --git a/light/odr_test.go b/light/odr_test.go index d3f9374fd8..323c0fb470 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -72,7 +72,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 = core.GetBlockReceipts(odr.sdb, req.Block.Hash(), req.Block.NumberU64()) case *TrieRequest: t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb)) nodes := NewNodeSet() diff --git a/light/odr_util.go b/light/odr_util.go index 8f92d64426..a5dbb1d19b 100644 --- a/light/odr_util.go +++ b/light/odr_util.go @@ -130,7 +130,15 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num if receipts != nil { return receipts, nil } - r := &ReceiptsRequest{Hash: hash, Number: number} + // Receipts unavailable locally, we need the full block to reconstruct + block, err := GetBlock(ctx, odr, hash, number) + if err != nil { + return nil, err + } + genesis := core.GetCanonicalHash(odr.Database(), 0) + config, _ := core.GetChainConfig(odr.Database(), genesis) + + r := &ReceiptsRequest{Config: config, Block: block} if err := odr.Retrieve(ctx, r); err != nil { return nil, err }