les, light: redef cht request

This commit is contained in:
rjl493456442 2018-07-15 15:20:50 +08:00
parent dfe765f3f5
commit 14e65b5d0e
3 changed files with 34 additions and 29 deletions

View file

@ -353,9 +353,9 @@ type ChtRequest light.ChtRequest
func (r *ChtRequest) GetCost(peer *peer) uint64 { func (r *ChtRequest) GetCost(peer *peer) uint64 {
switch peer.version { switch peer.version {
case lpv1: case lpv1:
return peer.GetRequestCost(GetHeaderProofsMsg, len(r.BlockNum)) return peer.GetRequestCost(GetHeaderProofsMsg, len(r.Numbers))
case lpv2: case lpv2:
return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.BlockNum)) return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.Numbers))
default: default:
panic(nil) panic(nil)
} }
@ -371,17 +371,17 @@ func (r *ChtRequest) CanSend(peer *peer, config *light.IndexerConfig) bool {
// 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 *ChtRequest) Request(reqID uint64, peer *peer, config *light.IndexerConfig) error { func (r *ChtRequest) Request(reqID uint64, peer *peer, config *light.IndexerConfig) error {
peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum) peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.Numbers)
var ( var (
encNum [8]byte encNum [8]byte
reqs []HelperTrieReq reqs = make([]HelperTrieReq, 0, len(r.Numbers))
) )
for _, num := range r.BlockNum { for _, num := range r.Numbers {
binary.BigEndian.PutUint64(encNum[:], num) binary.BigEndian.PutUint64(encNum[:], num)
reqs = append(reqs, HelperTrieReq{ reqs = append(reqs, HelperTrieReq{
Type: htCanonical, Type: htCanonical,
TrieIdx: r.ChtNum, TrieIdx: r.ChtNum,
Key: encNum[:], Key: common.CopyBytes(encNum[:]),
AuxReq: auxHeader, AuxReq: auxHeader,
}) })
} }
@ -408,22 +408,21 @@ func (r *ChtRequest) Request(reqID uint64, peer *peer, config *light.IndexerConf
// 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 *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum) log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.Numbers)
switch msg.MsgType { switch msg.MsgType {
case MsgHeaderProofs: // LES/1 backwards compatibility case MsgHeaderProofs: // LES/1 backwards compatibility
resps := msg.Obj.([]ChtResp) resps := msg.Obj.([]ChtResp)
if len(resps) != len(r.BlockNum) { if len(resps) != len(r.Numbers) {
return errInvalidEntryCount return errInvalidEntryCount
} }
var ( var (
headers []*types.Header headers []*types.Header
tds []*big.Int tds []*big.Int
encNumber [8]byte encNumber [8]byte
node light.ChtNode
nodeset = light.NewNodeSet() nodeset = light.NewNodeSet()
) )
for i, num := range r.BlockNum { for i, num := range r.Numbers {
resp := resps[i] resp := resps[i]
// Verify the CHT // Verify the CHT
binary.BigEndian.PutUint64(encNumber[:], num) binary.BigEndian.PutUint64(encNumber[:], num)
@ -431,6 +430,7 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
if err != nil { if err != nil {
return err return err
} }
var node light.ChtNode
if err := rlp.DecodeBytes(value, &node); err != nil { if err := rlp.DecodeBytes(value, &node); err != nil {
return err return err
} }
@ -445,24 +445,24 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
tds = append(tds, node.Td) tds = append(tds, node.Td)
light.NodeList(resp.Proof).Store(nodeset) light.NodeList(resp.Proof).Store(nodeset)
} }
r.Header = headers r.Headers = headers
r.Td = tds r.Tds = tds
r.Proof = nodeset r.Proof = nodeset
case MsgHelperTrieProofs: case MsgHelperTrieProofs:
// Check if the number of items in the response is the same as we requested. // Check if the number of items in the response is the same as we requested.
resp := msg.Obj.(HelperTrieResps) resp := msg.Obj.(HelperTrieResps)
if len(resp.AuxData) != len(r.BlockNum) { if len(resp.AuxData) != len(r.Numbers) {
return errInvalidEntryCount return errInvalidEntryCount
} }
var ( var (
headers []*types.Header headers []*types.Header
tds []*big.Int tds []*big.Int
encNumber [8]byte encNumber [8]byte
node light.ChtNode
nodeSet = resp.Proofs.NodeSet() nodeSet = resp.Proofs.NodeSet()
reads = &readTraceDB{db: nodeSet}
) )
for i, num := range r.BlockNum { for i, num := range r.Numbers {
enc := resp.AuxData[i] enc := resp.AuxData[i]
if len(enc) == 0 { if len(enc) == 0 {
return errHeaderUnavailable return errHeaderUnavailable
@ -473,10 +473,11 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
} }
// Verify the CHT // Verify the CHT
binary.BigEndian.PutUint64(encNumber[:], num) binary.BigEndian.PutUint64(encNumber[:], num)
value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], nodeSet) value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads)
if err != nil { if err != nil {
return fmt.Errorf("merkle proof verification failed: %v", err) return fmt.Errorf("merkle proof verification failed: %v", err)
} }
var node light.ChtNode
if err := rlp.DecodeBytes(value, &node); err != nil { if err := rlp.DecodeBytes(value, &node); err != nil {
return err return err
} }
@ -490,8 +491,12 @@ func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
headers = append(headers, header) headers = append(headers, header)
tds = append(tds, node.Td) tds = append(tds, node.Td)
} }
r.Header = headers if len(reads.reads) != nodeSet.KeyCount() {
r.Td = tds return errUselessNodes
}
r.Headers = headers
r.Tds = tds
r.Proof = nodeSet r.Proof = nodeSet
default: default:

View file

@ -135,9 +135,9 @@ type ChtRequest struct {
OdrRequest OdrRequest
ChtNum uint64 ChtNum uint64
ChtRoot common.Hash ChtRoot common.Hash
BlockNum []uint64 Numbers []uint64
Header []*types.Header Headers []*types.Header
Td []*big.Int Tds []*big.Int
Proof *NodeSet Proof *NodeSet
} }
@ -145,12 +145,12 @@ type ChtRequest struct {
func (req *ChtRequest) StoreResult(db ethdb.Database, config *IndexerConfig) { func (req *ChtRequest) StoreResult(db ethdb.Database, config *IndexerConfig) {
// The block number, header, td, proof length consistency has been verified // The block number, header, td, proof length consistency has been verified
// in the validation phase. // in the validation phase.
for index := range req.BlockNum { for index := range req.Numbers {
header := req.Header[index] header := req.Headers[index]
hash, num := header.Hash(), header.Number.Uint64() hash, num := header.Hash(), header.Number.Uint64()
rawdb.WriteHeader(db, header) rawdb.WriteHeader(db, header)
rawdb.WriteTd(db, hash, num, req.Td[index]) rawdb.WriteTd(db, hash, num, req.Tds[index])
rawdb.WriteCanonicalHash(db, hash, num) rawdb.WriteCanonicalHash(db, hash, num)
} }
} }

View file

@ -62,12 +62,12 @@ func GetHeaderByNumber(ctx context.Context, odr OdrBackend, number uint64) (*typ
if number >= chtCount*odr.IndexerConfig().ChtSize { if number >= chtCount*odr.IndexerConfig().ChtSize {
return nil, ErrNoTrustedCht return nil, ErrNoTrustedCht
} }
r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, BlockNum: []uint64{number}} r := &ChtRequest{ChtRoot: GetChtRoot(db, chtCount-1, sectionHead), ChtNum: chtCount - 1, Numbers: []uint64{number}}
if err := odr.Retrieve(ctx, r); err != nil { if err := odr.Retrieve(ctx, r); err != nil {
return nil, err return nil, err
} }
// Response item number has been checked in validation stage, no extra checking needed. // Response item number has been checked in validation stage, no extra checking needed.
return r.Header[0], nil return r.Headers[0], nil
} }
func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) { func GetCanonicalHash(ctx context.Context, odr OdrBackend, number uint64) (common.Hash, error) {