github.com/digdeepmining/go-atheios@v1.5.13-0.20180902133602-d5687a2e6f43/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  	"bytes"
    23  	"encoding/binary"
    24  
    25  	"github.com/atheioschain/go-atheios/common"
    26  	"github.com/atheioschain/go-atheios/core"
    27  	"github.com/atheioschain/go-atheios/core/types"
    28  	"github.com/atheioschain/go-atheios/crypto"
    29  	"github.com/atheioschain/go-atheios/ethdb"
    30  	"github.com/atheioschain/go-atheios/light"
    31  	"github.com/atheioschain/go-atheios/logger"
    32  	"github.com/atheioschain/go-atheios/logger/glog"
    33  	"github.com/atheioschain/go-atheios/rlp"
    34  	"github.com/atheioschain/go-atheios/trie"
    35  )
    36  
    37  type LesOdrRequest interface {
    38  	GetCost(*peer) uint64
    39  	CanSend(*peer) bool
    40  	Request(uint64, *peer) error
    41  	Valid(ethdb.Database, *Msg) bool // if true, keeps the retrieved object
    42  }
    43  
    44  func LesRequest(req light.OdrRequest) LesOdrRequest {
    45  	switch r := req.(type) {
    46  	case *light.BlockRequest:
    47  		return (*BlockRequest)(r)
    48  	case *light.ReceiptsRequest:
    49  		return (*ReceiptsRequest)(r)
    50  	case *light.TrieRequest:
    51  		return (*TrieRequest)(r)
    52  	case *light.CodeRequest:
    53  		return (*CodeRequest)(r)
    54  	case *light.ChtRequest:
    55  		return (*ChtRequest)(r)
    56  	default:
    57  		return nil
    58  	}
    59  }
    60  
    61  // BlockRequest is the ODR request type for block bodies
    62  type BlockRequest light.BlockRequest
    63  
    64  // GetCost returns the cost of the given ODR request according to the serving
    65  // peer's cost table (implementation of LesOdrRequest)
    66  func (self *BlockRequest) GetCost(peer *peer) uint64 {
    67  	return peer.GetRequestCost(GetBlockBodiesMsg, 1)
    68  }
    69  
    70  // CanSend tells if a certain peer is suitable for serving the given request
    71  func (self *BlockRequest) CanSend(peer *peer) bool {
    72  	return peer.HasBlock(self.Hash, self.Number)
    73  }
    74  
    75  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
    76  func (self *BlockRequest) Request(reqID uint64, peer *peer) error {
    77  	glog.V(logger.Debug).Infof("ODR: requesting body of block %08x from peer %v", self.Hash[:4], peer.id)
    78  	return peer.RequestBodies(reqID, self.GetCost(peer), []common.Hash{self.Hash})
    79  }
    80  
    81  // Valid processes an ODR request reply message from the LES network
    82  // returns true and stores results in memory if the message was a valid reply
    83  // to the request (implementation of LesOdrRequest)
    84  func (self *BlockRequest) Valid(db ethdb.Database, msg *Msg) bool {
    85  	glog.V(logger.Debug).Infof("ODR: validating body of block %08x", self.Hash[:4])
    86  	if msg.MsgType != MsgBlockBodies {
    87  		glog.V(logger.Debug).Infof("ODR: invalid message type")
    88  		return false
    89  	}
    90  	bodies := msg.Obj.([]*types.Body)
    91  	if len(bodies) != 1 {
    92  		glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(bodies))
    93  		return false
    94  	}
    95  	body := bodies[0]
    96  	header := core.GetHeader(db, self.Hash, self.Number)
    97  	if header == nil {
    98  		glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
    99  		return false
   100  	}
   101  	txHash := types.DeriveSha(types.Transactions(body.Transactions))
   102  	if header.TxHash != txHash {
   103  		glog.V(logger.Debug).Infof("ODR: header.TxHash %08x does not match received txHash %08x", header.TxHash[:4], txHash[:4])
   104  		return false
   105  	}
   106  	uncleHash := types.CalcUncleHash(body.Uncles)
   107  	if header.UncleHash != uncleHash {
   108  		glog.V(logger.Debug).Infof("ODR: header.UncleHash %08x does not match received uncleHash %08x", header.UncleHash[:4], uncleHash[:4])
   109  		return false
   110  	}
   111  	data, err := rlp.EncodeToBytes(body)
   112  	if err != nil {
   113  		glog.V(logger.Debug).Infof("ODR: body RLP encode error: %v", err)
   114  		return false
   115  	}
   116  	self.Rlp = data
   117  	glog.V(logger.Debug).Infof("ODR: validation successful")
   118  	return true
   119  }
   120  
   121  // ReceiptsRequest is the ODR request type for block receipts by block hash
   122  type ReceiptsRequest light.ReceiptsRequest
   123  
   124  // GetCost returns the cost of the given ODR request according to the serving
   125  // peer's cost table (implementation of LesOdrRequest)
   126  func (self *ReceiptsRequest) GetCost(peer *peer) uint64 {
   127  	return peer.GetRequestCost(GetReceiptsMsg, 1)
   128  }
   129  
   130  // CanSend tells if a certain peer is suitable for serving the given request
   131  func (self *ReceiptsRequest) CanSend(peer *peer) bool {
   132  	return peer.HasBlock(self.Hash, self.Number)
   133  }
   134  
   135  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   136  func (self *ReceiptsRequest) Request(reqID uint64, peer *peer) error {
   137  	glog.V(logger.Debug).Infof("ODR: requesting receipts for block %08x from peer %v", self.Hash[:4], peer.id)
   138  	return peer.RequestReceipts(reqID, self.GetCost(peer), []common.Hash{self.Hash})
   139  }
   140  
   141  // Valid processes an ODR request reply message from the LES network
   142  // returns true and stores results in memory if the message was a valid reply
   143  // to the request (implementation of LesOdrRequest)
   144  func (self *ReceiptsRequest) Valid(db ethdb.Database, msg *Msg) bool {
   145  	glog.V(logger.Debug).Infof("ODR: validating receipts for block %08x", self.Hash[:4])
   146  	if msg.MsgType != MsgReceipts {
   147  		glog.V(logger.Debug).Infof("ODR: invalid message type")
   148  		return false
   149  	}
   150  	receipts := msg.Obj.([]types.Receipts)
   151  	if len(receipts) != 1 {
   152  		glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(receipts))
   153  		return false
   154  	}
   155  	hash := types.DeriveSha(receipts[0])
   156  	header := core.GetHeader(db, self.Hash, self.Number)
   157  	if header == nil {
   158  		glog.V(logger.Debug).Infof("ODR: header not found for block %08x", self.Hash[:4])
   159  		return false
   160  	}
   161  	if !bytes.Equal(header.ReceiptHash[:], hash[:]) {
   162  		glog.V(logger.Debug).Infof("ODR: header receipts hash %08x does not match calculated RLP hash %08x", header.ReceiptHash[:4], hash[:4])
   163  		return false
   164  	}
   165  	self.Receipts = receipts[0]
   166  	glog.V(logger.Debug).Infof("ODR: validation successful")
   167  	return true
   168  }
   169  
   170  type ProofReq struct {
   171  	BHash       common.Hash
   172  	AccKey, Key []byte
   173  	FromLevel   uint
   174  }
   175  
   176  // ODR request type for state/storage trie entries, see LesOdrRequest interface
   177  type TrieRequest light.TrieRequest
   178  
   179  // GetCost returns the cost of the given ODR request according to the serving
   180  // peer's cost table (implementation of LesOdrRequest)
   181  func (self *TrieRequest) GetCost(peer *peer) uint64 {
   182  	return peer.GetRequestCost(GetProofsMsg, 1)
   183  }
   184  
   185  // CanSend tells if a certain peer is suitable for serving the given request
   186  func (self *TrieRequest) CanSend(peer *peer) bool {
   187  	return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
   188  }
   189  
   190  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   191  func (self *TrieRequest) Request(reqID uint64, peer *peer) error {
   192  	glog.V(logger.Debug).Infof("ODR: requesting trie root %08x key %08x from peer %v", self.Id.Root[:4], self.Key[:4], peer.id)
   193  	req := &ProofReq{
   194  		BHash:  self.Id.BlockHash,
   195  		AccKey: self.Id.AccKey,
   196  		Key:    self.Key,
   197  	}
   198  	return peer.RequestProofs(reqID, self.GetCost(peer), []*ProofReq{req})
   199  }
   200  
   201  // Valid processes an ODR request reply message from the LES network
   202  // returns true and stores results in memory if the message was a valid reply
   203  // to the request (implementation of LesOdrRequest)
   204  func (self *TrieRequest) Valid(db ethdb.Database, msg *Msg) bool {
   205  	glog.V(logger.Debug).Infof("ODR: validating trie root %08x key %08x", self.Id.Root[:4], self.Key[:4])
   206  
   207  	if msg.MsgType != MsgProofs {
   208  		glog.V(logger.Debug).Infof("ODR: invalid message type")
   209  		return false
   210  	}
   211  	proofs := msg.Obj.([][]rlp.RawValue)
   212  	if len(proofs) != 1 {
   213  		glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
   214  		return false
   215  	}
   216  	_, err := trie.VerifyProof(self.Id.Root, self.Key, proofs[0])
   217  	if err != nil {
   218  		glog.V(logger.Debug).Infof("ODR: merkle proof verification error: %v", err)
   219  		return false
   220  	}
   221  	self.Proof = proofs[0]
   222  	glog.V(logger.Debug).Infof("ODR: validation successful")
   223  	return true
   224  }
   225  
   226  type CodeReq struct {
   227  	BHash  common.Hash
   228  	AccKey []byte
   229  }
   230  
   231  // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface
   232  type CodeRequest light.CodeRequest
   233  
   234  // GetCost returns the cost of the given ODR request according to the serving
   235  // peer's cost table (implementation of LesOdrRequest)
   236  func (self *CodeRequest) GetCost(peer *peer) uint64 {
   237  	return peer.GetRequestCost(GetCodeMsg, 1)
   238  }
   239  
   240  // CanSend tells if a certain peer is suitable for serving the given request
   241  func (self *CodeRequest) CanSend(peer *peer) bool {
   242  	return peer.HasBlock(self.Id.BlockHash, self.Id.BlockNumber)
   243  }
   244  
   245  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   246  func (self *CodeRequest) Request(reqID uint64, peer *peer) error {
   247  	glog.V(logger.Debug).Infof("ODR: requesting node data for hash %08x from peer %v", self.Hash[:4], peer.id)
   248  	req := &CodeReq{
   249  		BHash:  self.Id.BlockHash,
   250  		AccKey: self.Id.AccKey,
   251  	}
   252  	return peer.RequestCode(reqID, self.GetCost(peer), []*CodeReq{req})
   253  }
   254  
   255  // Valid processes an ODR request reply message from the LES network
   256  // returns true and stores results in memory if the message was a valid reply
   257  // to the request (implementation of LesOdrRequest)
   258  func (self *CodeRequest) Valid(db ethdb.Database, msg *Msg) bool {
   259  	glog.V(logger.Debug).Infof("ODR: validating node data for hash %08x", self.Hash[:4])
   260  	if msg.MsgType != MsgCode {
   261  		glog.V(logger.Debug).Infof("ODR: invalid message type")
   262  		return false
   263  	}
   264  	reply := msg.Obj.([][]byte)
   265  	if len(reply) != 1 {
   266  		glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(reply))
   267  		return false
   268  	}
   269  	data := reply[0]
   270  	if hash := crypto.Keccak256Hash(data); self.Hash != hash {
   271  		glog.V(logger.Debug).Infof("ODR: requested hash %08x does not match received data hash %08x", self.Hash[:4], hash[:4])
   272  		return false
   273  	}
   274  	self.Data = data
   275  	glog.V(logger.Debug).Infof("ODR: validation successful")
   276  	return true
   277  }
   278  
   279  type ChtReq struct {
   280  	ChtNum, BlockNum, FromLevel uint64
   281  }
   282  
   283  type ChtResp struct {
   284  	Header *types.Header
   285  	Proof  []rlp.RawValue
   286  }
   287  
   288  // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface
   289  type ChtRequest light.ChtRequest
   290  
   291  // GetCost returns the cost of the given ODR request according to the serving
   292  // peer's cost table (implementation of LesOdrRequest)
   293  func (self *ChtRequest) GetCost(peer *peer) uint64 {
   294  	return peer.GetRequestCost(GetHeaderProofsMsg, 1)
   295  }
   296  
   297  // CanSend tells if a certain peer is suitable for serving the given request
   298  func (self *ChtRequest) CanSend(peer *peer) bool {
   299  	peer.lock.RLock()
   300  	defer peer.lock.RUnlock()
   301  
   302  	return self.ChtNum <= (peer.headInfo.Number-light.ChtConfirmations)/light.ChtFrequency
   303  }
   304  
   305  // Request sends an ODR request to the LES network (implementation of LesOdrRequest)
   306  func (self *ChtRequest) Request(reqID uint64, peer *peer) error {
   307  	glog.V(logger.Debug).Infof("ODR: requesting CHT #%d block #%d from peer %v", self.ChtNum, self.BlockNum, peer.id)
   308  	req := &ChtReq{
   309  		ChtNum:   self.ChtNum,
   310  		BlockNum: self.BlockNum,
   311  	}
   312  	return peer.RequestHeaderProofs(reqID, self.GetCost(peer), []*ChtReq{req})
   313  }
   314  
   315  // Valid processes an ODR request reply message from the LES network
   316  // returns true and stores results in memory if the message was a valid reply
   317  // to the request (implementation of LesOdrRequest)
   318  func (self *ChtRequest) Valid(db ethdb.Database, msg *Msg) bool {
   319  	glog.V(logger.Debug).Infof("ODR: validating CHT #%d block #%d", self.ChtNum, self.BlockNum)
   320  
   321  	if msg.MsgType != MsgHeaderProofs {
   322  		glog.V(logger.Debug).Infof("ODR: invalid message type")
   323  		return false
   324  	}
   325  	proofs := msg.Obj.([]ChtResp)
   326  	if len(proofs) != 1 {
   327  		glog.V(logger.Debug).Infof("ODR: invalid number of entries: %d", len(proofs))
   328  		return false
   329  	}
   330  	proof := proofs[0]
   331  	var encNumber [8]byte
   332  	binary.BigEndian.PutUint64(encNumber[:], self.BlockNum)
   333  	value, err := trie.VerifyProof(self.ChtRoot, encNumber[:], proof.Proof)
   334  	if err != nil {
   335  		glog.V(logger.Debug).Infof("ODR: CHT merkle proof verification error: %v", err)
   336  		return false
   337  	}
   338  	var node light.ChtNode
   339  	if err := rlp.DecodeBytes(value, &node); err != nil {
   340  		glog.V(logger.Debug).Infof("ODR: error decoding CHT node: %v", err)
   341  		return false
   342  	}
   343  	if node.Hash != proof.Header.Hash() {
   344  		glog.V(logger.Debug).Infof("ODR: CHT header hash does not match")
   345  		return false
   346  	}
   347  
   348  	self.Proof = proof.Proof
   349  	self.Header = proof.Header
   350  	self.Td = node.Td
   351  	glog.V(logger.Debug).Infof("ODR: validation successful")
   352  	return true
   353  }