github.com/etherbanking/go-etherbanking@v1.7.1-0.20181009210156-cf649bca5aba/les/odr_requests.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package light implements on-demand retrieval capable state and chain objects
    18  // for the Ethereum Light Client.
    19  package les
    20  
    21  import (
    22  	"encoding/binary"
    23  	"errors"
    24  	"fmt"
    25  
    26  	"github.com/etherbanking/go-etherbanking/common"
    27  	"github.com/etherbanking/go-etherbanking/core"
    28  	"github.com/etherbanking/go-etherbanking/core/types"
    29  	"github.com/etherbanking/go-etherbanking/crypto"
    30  	"github.com/etherbanking/go-etherbanking/ethdb"
    31  	"github.com/etherbanking/go-etherbanking/light"
    32  	"github.com/etherbanking/go-etherbanking/log"
    33  	"github.com/etherbanking/go-etherbanking/rlp"
    34  	"github.com/etherbanking/go-etherbanking/trie"
    35  )
    36  
    37  var (
    38  	errInvalidMessageType  = errors.New("invalid message type")
    39  	errMultipleEntries     = errors.New("multiple response entries")
    40  	errHeaderUnavailable   = errors.New("header unavailable")
    41  	errTxHashMismatch      = errors.New("transaction hash mismatch")
    42  	errUncleHashMismatch   = errors.New("uncle hash mismatch")
    43  	errReceiptHashMismatch = errors.New("receipt hash mismatch")
    44  	errDataHashMismatch    = errors.New("data hash mismatch")
    45  	errCHTHashMismatch     = errors.New("cht hash mismatch")
    46  )
    47  
    48  type LesOdrRequest interface {
    49  	GetCost(*peer) uint64
    50  	CanSend(*peer) bool
    51  	Request(uint64, *peer) error
    52  	Validate(ethdb.Database, *Msg) error
    53  }
    54  
    55  func LesRequest(req light.OdrRequest) LesOdrRequest {
    56  	switch r := req.(type) {
    57  	case *light.BlockRequest:
    58  		return (*BlockRequest)(r)
    59  	case *light.ReceiptsRequest:
    60  		return (*ReceiptsRequest)(r)
    61  	case *light.TrieRequest:
    62  		return (*TrieRequest)(r)
    63  	case *light.CodeRequest:
    64  		return (*CodeRequest)(r)
    65  	case *light.ChtRequest:
    66  		return (*ChtRequest)(r)
    67  	default:
    68  		return nil
    69  	}
    70  }
    71  
    72  // BlockRequest is the ODR request type for block bodies
    73  type BlockRequest light.BlockRequest
    74  
    75  // GetCost returns the cost of the given ODR request according to the serving
    76  // peer's cost table (implementation of LesOdrRequest)
    77  func (r *BlockRequest) GetCost(peer *peer) uint64 {
    78  	return peer.GetRequestCost(GetBlockBodiesMsg, 1)
    79  }
    80  
    81  // CanSend tells if a certain peer is suitable for serving the given request
    82  func (r *BlockRequest) CanSend(peer *peer) bool {
    83  	return peer.HasBlock(r.Hash, r.Number)
    84  }
    85  
    86  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
    87  func (r *BlockRequest) Request(reqID uint64, peer *peer) error {
    88  	peer.Log().Debug("Requesting block body", "hash", r.Hash)
    89  	return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash})
    90  }
    91  
    92  // Valid processes an ODR request reply message from the LES network
    93  // returns true and stores results in memory if the message was a valid reply
    94  // to the request (implementation of LesOdrRequest)
    95  func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error {
    96  	log.Debug("Validating block body", "hash", r.Hash)
    97  
    98  	// Ensure we have a correct message with a single block body
    99  	if msg.MsgType != MsgBlockBodies {
   100  		return errInvalidMessageType
   101  	}
   102  	bodies := msg.Obj.([]*types.Body)
   103  	if len(bodies) != 1 {
   104  		return errMultipleEntries
   105  	}
   106  	body := bodies[0]
   107  
   108  	// Retrieve our stored header and validate block content against it
   109  	header := core.GetHeader(db, r.Hash, r.Number)
   110  	if header == nil {
   111  		return errHeaderUnavailable
   112  	}
   113  	if header.TxHash != types.DeriveSha(types.Transactions(body.Transactions)) {
   114  		return errTxHashMismatch
   115  	}
   116  	if header.UncleHash != types.CalcUncleHash(body.Uncles) {
   117  		return errUncleHashMismatch
   118  	}
   119  	// Validations passed, encode and store RLP
   120  	data, err := rlp.EncodeToBytes(body)
   121  	if err != nil {
   122  		return err
   123  	}
   124  	r.Rlp = data
   125  	return nil
   126  }
   127  
   128  // ReceiptsRequest is the ODR request type for block receipts by block hash
   129  type ReceiptsRequest light.ReceiptsRequest
   130  
   131  // GetCost returns the cost of the given ODR request according to the serving
   132  // peer's cost table (implementation of LesOdrRequest)
   133  func (r *ReceiptsRequest) GetCost(peer *peer) uint64 {
   134  	return peer.GetRequestCost(GetReceiptsMsg, 1)
   135  }
   136  
   137  // CanSend tells if a certain peer is suitable for serving the given request
   138  func (r *ReceiptsRequest) CanSend(peer *peer) bool {
   139  	return peer.HasBlock(r.Hash, r.Number)
   140  }
   141  
   142  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   143  func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
   144  	peer.Log().Debug("Requesting block receipts", "hash", r.Hash)
   145  	return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash})
   146  }
   147  
   148  // Valid processes an ODR request reply message from the LES network
   149  // returns true and stores results in memory if the message was a valid reply
   150  // to the request (implementation of LesOdrRequest)
   151  func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error {
   152  	log.Debug("Validating block receipts", "hash", r.Hash)
   153  
   154  	// Ensure we have a correct message with a single block receipt
   155  	if msg.MsgType != MsgReceipts {
   156  		return errInvalidMessageType
   157  	}
   158  	receipts := msg.Obj.([]types.Receipts)
   159  	if len(receipts) != 1 {
   160  		return errMultipleEntries
   161  	}
   162  	receipt := receipts[0]
   163  
   164  	// Retrieve our stored header and validate receipt content against it
   165  	header := core.GetHeader(db, r.Hash, r.Number)
   166  	if header == nil {
   167  		return errHeaderUnavailable
   168  	}
   169  	if header.ReceiptHash != types.DeriveSha(receipt) {
   170  		return errReceiptHashMismatch
   171  	}
   172  	// Validations passed, store and return
   173  	r.Receipts = receipt
   174  	return nil
   175  }
   176  
   177  type ProofReq struct {
   178  	BHash       common.Hash
   179  	AccKey, Key []byte
   180  	FromLevel   uint
   181  }
   182  
   183  // ODR request type for state/storage trie entries, see LesOdrRequest interface
   184  type TrieRequest light.TrieRequest
   185  
   186  // GetCost returns the cost of the given ODR request according to the serving
   187  // peer's cost table (implementation of LesOdrRequest)
   188  func (r *TrieRequest) GetCost(peer *peer) uint64 {
   189  	return peer.GetRequestCost(GetProofsMsg, 1)
   190  }
   191  
   192  // CanSend tells if a certain peer is suitable for serving the given request
   193  func (r *TrieRequest) CanSend(peer *peer) bool {
   194  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
   195  }
   196  
   197  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   198  func (r *TrieRequest) Request(reqID uint64, peer *peer) error {
   199  	peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key)
   200  	req := &ProofReq{
   201  		BHash:  r.Id.BlockHash,
   202  		AccKey: r.Id.AccKey,
   203  		Key:    r.Key,
   204  	}
   205  	return peer.RequestProofs(reqID, r.GetCost(peer), []*ProofReq{req})
   206  }
   207  
   208  // Valid processes an ODR request reply message from the LES network
   209  // returns true and stores results in memory if the message was a valid reply
   210  // to the request (implementation of LesOdrRequest)
   211  func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error {
   212  	log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key)
   213  
   214  	// Ensure we have a correct message with a single proof
   215  	if msg.MsgType != MsgProofs {
   216  		return errInvalidMessageType
   217  	}
   218  	proofs := msg.Obj.([][]rlp.RawValue)
   219  	if len(proofs) != 1 {
   220  		return errMultipleEntries
   221  	}
   222  	// Verify the proof and store if checks out
   223  	if _, err := trie.VerifyProof(r.Id.Root, r.Key, proofs[0]); err != nil {
   224  		return fmt.Errorf("merkle proof verification failed: %v", err)
   225  	}
   226  	r.Proof = proofs[0]
   227  	return nil
   228  }
   229  
   230  type CodeReq struct {
   231  	BHash  common.Hash
   232  	AccKey []byte
   233  }
   234  
   235  // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
   236  type CodeRequest light.CodeRequest
   237  
   238  // GetCost returns the cost of the given ODR request according to the serving
   239  // peer's cost table (implementation of LesOdrRequest)
   240  func (r *CodeRequest) GetCost(peer *peer) uint64 {
   241  	return peer.GetRequestCost(GetCodeMsg, 1)
   242  }
   243  
   244  // CanSend tells if a certain peer is suitable for serving the given request
   245  func (r *CodeRequest) CanSend(peer *peer) bool {
   246  	return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber)
   247  }
   248  
   249  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   250  func (r *CodeRequest) Request(reqID uint64, peer *peer) error {
   251  	peer.Log().Debug("Requesting code data", "hash", r.Hash)
   252  	req := &CodeReq{
   253  		BHash:  r.Id.BlockHash,
   254  		AccKey: r.Id.AccKey,
   255  	}
   256  	return peer.RequestCode(reqID, r.GetCost(peer), []*CodeReq{req})
   257  }
   258  
   259  // Valid processes an ODR request reply message from the LES network
   260  // returns true and stores results in memory if the message was a valid reply
   261  // to the request (implementation of LesOdrRequest)
   262  func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error {
   263  	log.Debug("Validating code data", "hash", r.Hash)
   264  
   265  	// Ensure we have a correct message with a single code element
   266  	if msg.MsgType != MsgCode {
   267  		return errInvalidMessageType
   268  	}
   269  	reply := msg.Obj.([][]byte)
   270  	if len(reply) != 1 {
   271  		return errMultipleEntries
   272  	}
   273  	data := reply[0]
   274  
   275  	// Verify the data and store if checks out
   276  	if hash := crypto.Keccak256Hash(data); r.Hash != hash {
   277  		return errDataHashMismatch
   278  	}
   279  	r.Data = data
   280  	return nil
   281  }
   282  
   283  type ChtReq struct {
   284  	ChtNum, BlockNum, FromLevel uint64
   285  }
   286  
   287  type ChtResp struct {
   288  	Header *types.Header
   289  	Proof  []rlp.RawValue
   290  }
   291  
   292  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   293  type ChtRequest light.ChtRequest
   294  
   295  // GetCost returns the cost of the given ODR request according to the serving
   296  // peer's cost table (implementation of LesOdrRequest)
   297  func (r *ChtRequest) GetCost(peer *peer) uint64 {
   298  	return peer.GetRequestCost(GetHeaderProofsMsg, 1)
   299  }
   300  
   301  // CanSend tells if a certain peer is suitable for serving the given request
   302  func (r *ChtRequest) CanSend(peer *peer) bool {
   303  	peer.lock.RLock()
   304  	defer peer.lock.RUnlock()
   305  
   306  	return r.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency
   307  }
   308  
   309  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   310  func (r *ChtRequest) Request(reqID uint64, peer *peer) error {
   311  	peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum)
   312  	req := &ChtReq{
   313  		ChtNum:   r.ChtNum,
   314  		BlockNum: r.BlockNum,
   315  	}
   316  	return peer.RequestHeaderProofs(reqID, r.GetCost(peer), []*ChtReq{req})
   317  }
   318  
   319  // Valid processes an ODR request reply message from the LES network
   320  // returns true and stores results in memory if the message was a valid reply
   321  // to the request (implementation of LesOdrRequest)
   322  func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error {
   323  	log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum)
   324  
   325  	// Ensure we have a correct message with a single proof element
   326  	if msg.MsgType != MsgHeaderProofs {
   327  		return errInvalidMessageType
   328  	}
   329  	proofs := msg.Obj.([]ChtResp)
   330  	if len(proofs) != 1 {
   331  		return errMultipleEntries
   332  	}
   333  	proof := proofs[0]
   334  
   335  	// Verify the CHT
   336  	var encNumber [8]byte
   337  	binary.BigEndian.PutUint64(encNumber[:], r.BlockNum)
   338  
   339  	value, err := trie.VerifyProof(r.ChtRoot, encNumber[:], proof.Proof)
   340  	if err != nil {
   341  		return err
   342  	}
   343  	var node light.ChtNode
   344  	if err := rlp.DecodeBytes(value, &node); err != nil {
   345  		return err
   346  	}
   347  	if node.Hash != proof.Header.Hash() {
   348  		return errCHTHashMismatch
   349  	}
   350  	// Verifications passed, store and return
   351  	r.Header = proof.Header
   352  	r.Proof = proof.Proof
   353  	r.Td = node.Td
   354  
   355  	return nil
   356  }