|
|
|
@ -19,20 +19,23 @@ package light |
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"context" |
|
|
|
|
"errors" |
|
|
|
|
"math/big" |
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
|
"github.com/ethereum/go-ethereum/core" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/rawdb" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/types" |
|
|
|
|
"github.com/ethereum/go-ethereum/crypto" |
|
|
|
|
"github.com/ethereum/go-ethereum/rlp" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var sha3Nil = crypto.Keccak256Hash(nil) |
|
|
|
|
// errNonCanonicalHash is returned if the requested chain data doesn't belong
|
|
|
|
|
// to the canonical chain. ODR can only retrieve the canonical chain data covered
|
|
|
|
|
// by the CHT or Bloom trie for verification.
|
|
|
|
|
var errNonCanonicalHash = errors.New("hash is not currently canonical") |
|
|
|
|
|
|
|
|
|
// GetHeaderByNumber retrieves the canonical block header corresponding to the
|
|
|
|
|
// given number.
|
|
|
|
|
// given number. The returned header is proven by local CHT.
|
|
|
|
|
func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*types.Header, error) { |
|
|
|
|
// Try to find it in the local database first.
|
|
|
|
|
db := odr.Database() |
|
|
|
@ -63,25 +66,6 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ |
|
|
|
|
return r.Header, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetUntrustedHeaderByNumber retrieves specified block header without
|
|
|
|
|
// correctness checking. Note this function should only be used in light
|
|
|
|
|
// client checkpoint syncing.
|
|
|
|
|
func GetUntrustedHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64, peerId string) (*types.Header, error) { |
|
|
|
|
// todo(rjl493456442) it's a hack to retrieve headers which is not covered
|
|
|
|
|
// by CHT. Fix it in LES4
|
|
|
|
|
r := &ChtRequest{ |
|
|
|
|
BlockNum: number, |
|
|
|
|
ChtNum: number / odr.IndexerConfig().ChtSize, |
|
|
|
|
Untrusted: true, |
|
|
|
|
PeerId: peerId, |
|
|
|
|
Config: odr.IndexerConfig(), |
|
|
|
|
} |
|
|
|
|
if err := odr.Retrieve(ctx, r); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
return r.Header, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GetCanonicalHash retrieves the canonical block hash corresponding to the number.
|
|
|
|
|
func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { |
|
|
|
|
hash := rawdb.ReadCanonicalHash(odr.Database(), number) |
|
|
|
@ -102,10 +86,13 @@ func GetTd(ctx context.Context, odr OdrBackend, hash common.Hash, number uint64) |
|
|
|
|
if td != nil { |
|
|
|
|
return td, nil |
|
|
|
|
} |
|
|
|
|
_, err := GetHeaderByNumber(ctx, odr, number) |
|
|
|
|
header, err := GetHeaderByNumber(ctx, odr, number) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
if header.Hash() != hash { |
|
|
|
|
return nil, errNonCanonicalHash |
|
|
|
|
} |
|
|
|
|
// <hash, number> -> td mapping already be stored in db, get it.
|
|
|
|
|
return rawdb.ReadTd(odr.Database(), hash, number), nil |
|
|
|
|
} |
|
|
|
@ -120,6 +107,9 @@ func GetBodyRLP(ctx context.Context, odr OdrBackend, hash common.Hash, number ui |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, errNoHeader |
|
|
|
|
} |
|
|
|
|
if header.Hash() != hash { |
|
|
|
|
return nil, errNonCanonicalHash |
|
|
|
|
} |
|
|
|
|
r := &BlockRequest{Hash: hash, Number: number, Header: header} |
|
|
|
|
if err := odr.Retrieve(ctx, r); err != nil { |
|
|
|
|
return nil, err |
|
|
|
@ -167,6 +157,9 @@ func GetBlockReceipts(ctx context.Context, odr OdrBackend, hash common.Hash, num |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, errNoHeader |
|
|
|
|
} |
|
|
|
|
if header.Hash() != hash { |
|
|
|
|
return nil, errNonCanonicalHash |
|
|
|
|
} |
|
|
|
|
r := &ReceiptsRequest{Hash: hash, Number: number, Header: header} |
|
|
|
|
if err := odr.Retrieve(ctx, r); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|