github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/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 les 18 19 import ( 20 "encoding/binary" 21 "errors" 22 "fmt" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/core/rawdb" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/crypto" 28 "github.com/ethereum/go-ethereum/ethdb" 29 "github.com/ethereum/go-ethereum/light" 30 "github.com/ethereum/go-ethereum/log" 31 "github.com/ethereum/go-ethereum/rlp" 32 "github.com/ethereum/go-ethereum/trie" 33 ) 34 35 var ( 36 errInvalidMessageType = errors.New("invalid message type") 37 errInvalidEntryCount = errors.New("invalid number of response entries") 38 errHeaderUnavailable = errors.New("header unavailable") 39 errTxHashMismatch = errors.New("transaction hash mismatch") 40 errUncleHashMismatch = errors.New("uncle hash mismatch") 41 errReceiptHashMismatch = errors.New("receipt hash mismatch") 42 errDataHashMismatch = errors.New("data hash mismatch") 43 errCHTHashMismatch = errors.New("cht hash mismatch") 44 errCHTNumberMismatch = errors.New("cht number mismatch") 45 errUselessNodes = errors.New("useless nodes in merkle proof nodeset") 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 case *light.BloomRequest: 68 return (*BloomRequest)(r) 69 default: 70 return nil 71 } 72 } 73 74 // BlockRequest is the ODR request type for block bodies 75 type BlockRequest light.BlockRequest 76 77 // GetCost returns the cost of the given ODR request according to the serving 78 // peer's cost table (implementation of LesOdrRequest) 79 func (r *BlockRequest) GetCost(peer *peer) uint64 { 80 return peer.GetRequestCost(GetBlockBodiesMsg, 1) 81 } 82 83 // CanSend tells if a certain peer is suitable for serving the given request 84 func (r *BlockRequest) CanSend(peer *peer) bool { 85 return peer.HasBlock(r.Hash, r.Number, false) 86 } 87 88 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 89 func (r *BlockRequest) Request(reqID uint64, peer *peer) error { 90 peer.Log().Debug("Requesting block body", "hash", r.Hash) 91 return peer.RequestBodies(reqID, r.GetCost(peer), []common.Hash{r.Hash}) 92 } 93 94 // Valid processes an ODR request reply message from the LES network 95 // returns true and stores results in memory if the message was a valid reply 96 // to the request (implementation of LesOdrRequest) 97 func (r *BlockRequest) Validate(db ethdb.Database, msg *Msg) error { 98 log.Debug("Validating block body", "hash", r.Hash) 99 100 // Ensure we have a correct message with a single block body 101 if msg.MsgType != MsgBlockBodies { 102 return errInvalidMessageType 103 } 104 bodies := msg.Obj.([]*types.Body) 105 if len(bodies) != 1 { 106 return errInvalidEntryCount 107 } 108 body := bodies[0] 109 110 // Retrieve our stored header and validate block content against it 111 header := rawdb.ReadHeader(db, r.Hash, r.Number) 112 if header == nil { 113 return errHeaderUnavailable 114 } 115 if header.TxHash != types.DeriveSha(types.Transactions(body.Transactions)) { 116 return errTxHashMismatch 117 } 118 if header.UncleHash != types.CalcUncleHash(body.Uncles) { 119 return errUncleHashMismatch 120 } 121 // Validations passed, encode and store RLP 122 data, err := rlp.EncodeToBytes(body) 123 if err != nil { 124 return err 125 } 126 r.Rlp = data 127 return nil 128 } 129 130 // ReceiptsRequest is the ODR request type for block receipts by block hash 131 type ReceiptsRequest light.ReceiptsRequest 132 133 // GetCost returns the cost of the given ODR request according to the serving 134 // peer's cost table (implementation of LesOdrRequest) 135 func (r *ReceiptsRequest) GetCost(peer *peer) uint64 { 136 return peer.GetRequestCost(GetReceiptsMsg, 1) 137 } 138 139 // CanSend tells if a certain peer is suitable for serving the given request 140 func (r *ReceiptsRequest) CanSend(peer *peer) bool { 141 return peer.HasBlock(r.Hash, r.Number, false) 142 } 143 144 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 145 func (r *ReceiptsRequest) Request(reqID uint64, peer *peer) error { 146 peer.Log().Debug("Requesting block receipts", "hash", r.Hash) 147 return peer.RequestReceipts(reqID, r.GetCost(peer), []common.Hash{r.Hash}) 148 } 149 150 // Valid processes an ODR request reply message from the LES network 151 // returns true and stores results in memory if the message was a valid reply 152 // to the request (implementation of LesOdrRequest) 153 func (r *ReceiptsRequest) Validate(db ethdb.Database, msg *Msg) error { 154 log.Debug("Validating block receipts", "hash", r.Hash) 155 156 // Ensure we have a correct message with a single block receipt 157 if msg.MsgType != MsgReceipts { 158 return errInvalidMessageType 159 } 160 receipts := msg.Obj.([]types.Receipts) 161 if len(receipts) != 1 { 162 return errInvalidEntryCount 163 } 164 receipt := receipts[0] 165 166 // Retrieve our stored header and validate receipt content against it 167 header := rawdb.ReadHeader(db, r.Hash, r.Number) 168 if header == nil { 169 return errHeaderUnavailable 170 } 171 if header.ReceiptHash != types.DeriveSha(receipt) { 172 return errReceiptHashMismatch 173 } 174 // Validations passed, store and return 175 r.Receipts = receipt 176 return nil 177 } 178 179 type ProofReq struct { 180 BHash common.Hash 181 AccKey, Key []byte 182 FromLevel uint 183 } 184 185 // ODR request type for state/storage trie entries, see LesOdrRequest interface 186 type TrieRequest light.TrieRequest 187 188 // GetCost returns the cost of the given ODR request according to the serving 189 // peer's cost table (implementation of LesOdrRequest) 190 func (r *TrieRequest) GetCost(peer *peer) uint64 { 191 return peer.GetRequestCost(GetProofsV2Msg, 1) 192 } 193 194 // CanSend tells if a certain peer is suitable for serving the given request 195 func (r *TrieRequest) CanSend(peer *peer) bool { 196 return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true) 197 } 198 199 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 200 func (r *TrieRequest) Request(reqID uint64, peer *peer) error { 201 peer.Log().Debug("Requesting trie proof", "root", r.Id.Root, "key", r.Key) 202 req := ProofReq{ 203 BHash: r.Id.BlockHash, 204 AccKey: r.Id.AccKey, 205 Key: r.Key, 206 } 207 return peer.RequestProofs(reqID, r.GetCost(peer), []ProofReq{req}) 208 } 209 210 // Valid processes an ODR request reply message from the LES network 211 // returns true and stores results in memory if the message was a valid reply 212 // to the request (implementation of LesOdrRequest) 213 func (r *TrieRequest) Validate(db ethdb.Database, msg *Msg) error { 214 log.Debug("Validating trie proof", "root", r.Id.Root, "key", r.Key) 215 216 if msg.MsgType != MsgProofsV2 { 217 return errInvalidMessageType 218 } 219 proofs := msg.Obj.(light.NodeList) 220 // Verify the proof and store if checks out 221 nodeSet := proofs.NodeSet() 222 reads := &readTraceDB{db: nodeSet} 223 if _, _, err := trie.VerifyProof(r.Id.Root, r.Key, reads); err != nil { 224 return fmt.Errorf("merkle proof verification failed: %v", err) 225 } 226 // check if all nodes have been read by VerifyProof 227 if len(reads.reads) != nodeSet.KeyCount() { 228 return errUselessNodes 229 } 230 r.Proof = nodeSet 231 return nil 232 } 233 234 type CodeReq struct { 235 BHash common.Hash 236 AccKey []byte 237 } 238 239 // ODR request type for node data (used for retrieving contract code), see LesOdrRequest interface 240 type CodeRequest light.CodeRequest 241 242 // GetCost returns the cost of the given ODR request according to the serving 243 // peer's cost table (implementation of LesOdrRequest) 244 func (r *CodeRequest) GetCost(peer *peer) uint64 { 245 return peer.GetRequestCost(GetCodeMsg, 1) 246 } 247 248 // CanSend tells if a certain peer is suitable for serving the given request 249 func (r *CodeRequest) CanSend(peer *peer) bool { 250 return peer.HasBlock(r.Id.BlockHash, r.Id.BlockNumber, true) 251 } 252 253 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 254 func (r *CodeRequest) Request(reqID uint64, peer *peer) error { 255 peer.Log().Debug("Requesting code data", "hash", r.Hash) 256 req := CodeReq{ 257 BHash: r.Id.BlockHash, 258 AccKey: r.Id.AccKey, 259 } 260 return peer.RequestCode(reqID, r.GetCost(peer), []CodeReq{req}) 261 } 262 263 // Valid processes an ODR request reply message from the LES network 264 // returns true and stores results in memory if the message was a valid reply 265 // to the request (implementation of LesOdrRequest) 266 func (r *CodeRequest) Validate(db ethdb.Database, msg *Msg) error { 267 log.Debug("Validating code data", "hash", r.Hash) 268 269 // Ensure we have a correct message with a single code element 270 if msg.MsgType != MsgCode { 271 return errInvalidMessageType 272 } 273 reply := msg.Obj.([][]byte) 274 if len(reply) != 1 { 275 return errInvalidEntryCount 276 } 277 data := reply[0] 278 279 // Verify the data and store if checks out 280 if hash := crypto.Keccak256Hash(data); r.Hash != hash { 281 return errDataHashMismatch 282 } 283 r.Data = data 284 return nil 285 } 286 287 const ( 288 // helper trie type constants 289 htCanonical = iota // Canonical hash trie 290 htBloomBits // BloomBits trie 291 292 // applicable for all helper trie requests 293 auxRoot = 1 294 // applicable for htCanonical 295 auxHeader = 2 296 ) 297 298 type HelperTrieReq struct { 299 Type uint 300 TrieIdx uint64 301 Key []byte 302 FromLevel, AuxReq uint 303 } 304 305 type HelperTrieResps struct { // describes all responses, not just a single one 306 Proofs light.NodeList 307 AuxData [][]byte 308 } 309 310 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 311 type ChtRequest light.ChtRequest 312 313 // GetCost returns the cost of the given ODR request according to the serving 314 // peer's cost table (implementation of LesOdrRequest) 315 func (r *ChtRequest) GetCost(peer *peer) uint64 { 316 return peer.GetRequestCost(GetHelperTrieProofsMsg, 1) 317 } 318 319 // CanSend tells if a certain peer is suitable for serving the given request 320 func (r *ChtRequest) CanSend(peer *peer) bool { 321 peer.lock.RLock() 322 defer peer.lock.RUnlock() 323 324 return peer.headInfo.Number >= r.Config.ChtConfirms && r.ChtNum <= (peer.headInfo.Number-r.Config.ChtConfirms)/r.Config.ChtSize 325 } 326 327 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 328 func (r *ChtRequest) Request(reqID uint64, peer *peer) error { 329 peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum) 330 var encNum [8]byte 331 binary.BigEndian.PutUint64(encNum[:], r.BlockNum) 332 req := HelperTrieReq{ 333 Type: htCanonical, 334 TrieIdx: r.ChtNum, 335 Key: encNum[:], 336 AuxReq: auxHeader, 337 } 338 return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req}) 339 } 340 341 // Valid processes an ODR request reply message from the LES network 342 // returns true and stores results in memory if the message was a valid reply 343 // to the request (implementation of LesOdrRequest) 344 func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { 345 log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum) 346 347 if msg.MsgType != MsgHelperTrieProofs { 348 return errInvalidMessageType 349 } 350 resp := msg.Obj.(HelperTrieResps) 351 if len(resp.AuxData) != 1 { 352 return errInvalidEntryCount 353 } 354 nodeSet := resp.Proofs.NodeSet() 355 headerEnc := resp.AuxData[0] 356 if len(headerEnc) == 0 { 357 return errHeaderUnavailable 358 } 359 header := new(types.Header) 360 if err := rlp.DecodeBytes(headerEnc, header); err != nil { 361 return errHeaderUnavailable 362 } 363 364 // Verify the CHT 365 var encNumber [8]byte 366 binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) 367 368 reads := &readTraceDB{db: nodeSet} 369 value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) 370 if err != nil { 371 return fmt.Errorf("merkle proof verification failed: %v", err) 372 } 373 if len(reads.reads) != nodeSet.KeyCount() { 374 return errUselessNodes 375 } 376 377 var node light.ChtNode 378 if err := rlp.DecodeBytes(value, &node); err != nil { 379 return err 380 } 381 if node.Hash != header.Hash() { 382 return errCHTHashMismatch 383 } 384 if r.BlockNum != header.Number.Uint64() { 385 return errCHTNumberMismatch 386 } 387 // Verifications passed, store and return 388 r.Header = header 389 r.Proof = nodeSet 390 r.Td = node.Td 391 return nil 392 } 393 394 type BloomReq struct { 395 BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 396 } 397 398 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 399 type BloomRequest light.BloomRequest 400 401 // GetCost returns the cost of the given ODR request according to the serving 402 // peer's cost table (implementation of LesOdrRequest) 403 func (r *BloomRequest) GetCost(peer *peer) uint64 { 404 return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList)) 405 } 406 407 // CanSend tells if a certain peer is suitable for serving the given request 408 func (r *BloomRequest) CanSend(peer *peer) bool { 409 peer.lock.RLock() 410 defer peer.lock.RUnlock() 411 412 if peer.version < lpv2 { 413 return false 414 } 415 return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize 416 } 417 418 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 419 func (r *BloomRequest) Request(reqID uint64, peer *peer) error { 420 peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 421 reqs := make([]HelperTrieReq, len(r.SectionIndexList)) 422 423 var encNumber [10]byte 424 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 425 426 for i, sectionIdx := range r.SectionIndexList { 427 binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) 428 reqs[i] = HelperTrieReq{ 429 Type: htBloomBits, 430 TrieIdx: r.BloomTrieNum, 431 Key: common.CopyBytes(encNumber[:]), 432 } 433 } 434 return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs) 435 } 436 437 // Valid processes an ODR request reply message from the LES network 438 // returns true and stores results in memory if the message was a valid reply 439 // to the request (implementation of LesOdrRequest) 440 func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { 441 log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 442 443 // Ensure we have a correct message with a single proof element 444 if msg.MsgType != MsgHelperTrieProofs { 445 return errInvalidMessageType 446 } 447 resps := msg.Obj.(HelperTrieResps) 448 proofs := resps.Proofs 449 nodeSet := proofs.NodeSet() 450 reads := &readTraceDB{db: nodeSet} 451 452 r.BloomBits = make([][]byte, len(r.SectionIndexList)) 453 454 // Verify the proofs 455 var encNumber [10]byte 456 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 457 458 for i, idx := range r.SectionIndexList { 459 binary.BigEndian.PutUint64(encNumber[2:], idx) 460 value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) 461 if err != nil { 462 return err 463 } 464 r.BloomBits[i] = value 465 } 466 467 if len(reads.reads) != nodeSet.KeyCount() { 468 return errUselessNodes 469 } 470 r.Proofs = nodeSet 471 return nil 472 } 473 474 // readTraceDB stores the keys of database reads. We use this to check that received node 475 // sets contain only the trie nodes necessary to make proofs pass. 476 type readTraceDB struct { 477 db ethdb.Reader 478 reads map[string]struct{} 479 } 480 481 // Get returns a stored node 482 func (db *readTraceDB) Get(k []byte) ([]byte, error) { 483 if db.reads == nil { 484 db.reads = make(map[string]struct{}) 485 } 486 db.reads[string(k)] = struct{}{} 487 return db.db.Get(k) 488 } 489 490 // Has returns true if the node set contains the given key 491 func (db *readTraceDB) Has(key []byte) (bool, error) { 492 _, err := db.Get(key) 493 return err == nil, nil 494 }