mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 01:43:47 +00:00
les, light: fix receipt reconstruction in client
This commit is contained in:
parent
724a915470
commit
861a38398b
5 changed files with 36 additions and 23 deletions
|
|
@ -140,20 +140,20 @@ func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
|
||||||
|
|
||||||
// CanSend tells if a certain peer is suitable for serving the given request
|
// CanSend tells if a certain peer is suitable for serving the given request
|
||||||
func (r *ReceiptsRequest) CanSend(peer *peer) bool {
|
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)
|
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
|
||||||
func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
|
func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
|
||||||
peer.Log().Debug("Requesting block receipts", "hash", r.Hash)
|
peer.Log().Debug("Requesting block receipts", "hash", r.Block.Hash())
|
||||||
return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash})
|
return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Block.Hash()})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid processes an ODR request reply message from the LES network
|
// 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
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
// to the request (implementation of LesOdrRequest)
|
// to the request (implementation of LesOdrRequest)
|
||||||
func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
|
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
|
// Ensure we have a correct message with a single block receipt
|
||||||
if msg.MsgType != MsgReceipts {
|
if msg.MsgType != MsgReceipts {
|
||||||
|
|
@ -166,14 +166,12 @@ func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
|
||||||
receipt := receipts[0]
|
receipt := receipts[0]
|
||||||
|
|
||||||
// Retrieve our stored header and validate receipt content against it
|
// Retrieve our stored header and validate receipt content against it
|
||||||
header := core.GetHeader(db, r.Hash, r.Number)
|
if r.Block.ReceiptHash() != types.DeriveSha(receipt) {
|
||||||
if header == nil {
|
|
||||||
return errHeaderUnavailable
|
|
||||||
}
|
|
||||||
if header.ReceiptHash != types.DeriveSha(receipt) {
|
|
||||||
return errReceiptHashMismatch
|
return errReceiptHashMismatch
|
||||||
}
|
}
|
||||||
// Validations passed, store and return
|
// Validations passed, store and return
|
||||||
|
core.SetReceiptsData(r.Config, r.Block, receipt)
|
||||||
|
|
||||||
r.Receipts = receipt
|
r.Receipts = receipt
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,13 @@ func secAddr(addr common.Address) []byte {
|
||||||
return crypto.Keccak256(addr[:])
|
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 TestBlockAccessLes1(t *testing.T) { testAccess(t, 1, tfBlockAccess) }
|
||||||
|
|
||||||
func TestBlockAccessLes2(t *testing.T) { testAccess(t, 2, 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}
|
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 TestReceiptsAccessLes2(t *testing.T) { testAccess(t, 2, tfReceiptsAccess) }
|
||||||
|
|
||||||
func tfReceiptsAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
|
func tfReceiptsAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest {
|
||||||
return &light.ReceiptsRequest{Hash: bhash, Number: number}
|
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 TestTrieEntryAccessLes1(t *testing.T) { testAccess(t, 1, tfTrieEntryAccess) }
|
||||||
|
|
||||||
func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) }
|
func TestTrieEntryAccessLes2(t *testing.T) { testAccess(t, 2, tfTrieEntryAccess) }
|
||||||
|
|
||||||
func tfTrieEntryAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
|
func tfTrieEntryAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest {
|
||||||
return &light.TrieRequest{Id: light.StateTrieID(core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash))), Key: testBankSecureTrieKey}
|
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 TestCodeAccessLes1(t *testing.T) { testAccess(t, 1, tfCodeAccess) }
|
||||||
|
|
||||||
func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) }
|
func TestCodeAccessLes2(t *testing.T) { testAccess(t, 2, tfCodeAccess) }
|
||||||
|
|
||||||
func tfCodeAccess(db ethdb.Database, bhash common.Hash, number uint64) light.OdrRequest {
|
func tfCodeAccess(odr *LesOdr, bhash common.Hash, number uint64) light.OdrRequest {
|
||||||
header := core.GetHeader(db, bhash, core.GetBlockNumber(db, bhash))
|
header := core.GetHeader(odr.Database(), bhash, core.GetBlockNumber(odr.Database(), bhash))
|
||||||
if header.Number.Uint64() < testContractDeployed {
|
if header.Number.Uint64() < testContractDeployed {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -100,7 +106,7 @@ func testAccess(t *testing.T, protocol int, fn accessTestFn) {
|
||||||
test := func(expFail uint64) {
|
test := func(expFail uint64) {
|
||||||
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
|
for i := uint64(0); i <= pm.blockchain.CurrentHeader().Number.Uint64(); i++ {
|
||||||
bhash := core.GetCanonicalHash(db, 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)
|
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"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
|
// 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
|
// ReceiptsRequest is the ODR request type for retrieving block bodies
|
||||||
type ReceiptsRequest struct {
|
type ReceiptsRequest struct {
|
||||||
OdrRequest
|
OdrRequest
|
||||||
Hash common.Hash
|
Config *params.ChainConfig
|
||||||
Number uint64
|
Block *types.Block
|
||||||
Receipts types.Receipts
|
Receipts types.Receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreResult stores the retrieved data in local database
|
// StoreResult stores the retrieved data in local database
|
||||||
func (req *ReceiptsRequest) StoreResult(db ethdb.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
|
// ChtRequest is the ODR request type for state/storage trie entries
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ func (odr *testOdr) Retrieve(ctx context.Context, req OdrRequest) error {
|
||||||
case *BlockRequest:
|
case *BlockRequest:
|
||||||
req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash))
|
req.Rlp = core.GetBodyRLP(odr.sdb, req.Hash, core.GetBlockNumber(odr.sdb, req.Hash))
|
||||||
case *ReceiptsRequest:
|
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:
|
case *TrieRequest:
|
||||||
t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb))
|
t, _ := trie.New(req.Id.Root, trie.NewDatabase(odr.sdb))
|
||||||
nodes := NewNodeSet()
|
nodes := NewNodeSet()
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,15 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num
|
||||||
if receipts != nil {
|
if receipts != nil {
|
||||||
return 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 {
|
if err := odr.Retrieve(ctx, r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue