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