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 }