github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/les/odr_requests.go (about) 1 // Copyright 2016 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum 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/SmartMeshFoundation/Spectrum/common" 27 "github.com/SmartMeshFoundation/Spectrum/core" 28 "github.com/SmartMeshFoundation/Spectrum/core/types" 29 "github.com/SmartMeshFoundation/Spectrum/crypto" 30 "github.com/SmartMeshFoundation/Spectrum/ethdb" 31 "github.com/SmartMeshFoundation/Spectrum/light" 32 "github.com/SmartMeshFoundation/Spectrum/log" 33 "github.com/SmartMeshFoundation/Spectrum/rlp" 34 "github.com/SmartMeshFoundation/Spectrum/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) 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 := core.GetHeader(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) 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 := core.GetHeader(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) 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) 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 HelperTrieType 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 >= light.HelperTrieConfirmations && r.ChtNum <= (peer.headInfo.Number-light.HelperTrieConfirmations)/light.ChtFrequency 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 HelperTrieType: htCanonical, 378 TrieIdx: r.ChtNum, 379 Key: encNum[:], 380 AuxReq: auxHeader, 381 } 382 return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), []HelperTrieReq{req}) 383 } 384 385 // Valid processes an ODR request reply message from the LES network 386 // returns true and stores results in memory if the message was a valid reply 387 // to the request (implementation of LesOdrRequest) 388 func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { 389 log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum) 390 391 switch msg.MsgType { 392 case MsgHeaderProofs: // LES/1 backwards compatibility 393 proofs := msg.Obj.([]ChtResp) 394 if len(proofs) != 1 { 395 return errInvalidEntryCount 396 } 397 proof := proofs[0] 398 399 // Verify the CHT 400 var encNumber [8]byte 401 binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) 402 403 value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], light.NodeList(proof.Proof).NodeSet()) 404 if err != nil { 405 return err 406 } 407 var node light.ChtNode 408 if err := rlp.DecodeBytes(value, &node); err != nil { 409 return err 410 } 411 if node.Hash != proof.Header.Hash() { 412 return errCHTHashMismatch 413 } 414 // Verifications passed, store and return 415 r.Header = proof.Header 416 r.Proof = light.NodeList(proof.Proof).NodeSet() 417 r.Td = node.Td 418 case MsgHelperTrieProofs: 419 resp := msg.Obj.(HelperTrieResps) 420 if len(resp.AuxData) != 1 { 421 return errInvalidEntryCount 422 } 423 nodeSet := resp.Proofs.NodeSet() 424 headerEnc := resp.AuxData[0] 425 if len(headerEnc) == 0 { 426 return errHeaderUnavailable 427 } 428 header := new(types.Header) 429 if err := rlp.DecodeBytes(headerEnc, header); err != nil { 430 return errHeaderUnavailable 431 } 432 433 // Verify the CHT 434 var encNumber [8]byte 435 binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) 436 437 reads := &readTraceDB{db: nodeSet} 438 value, err, _ := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) 439 if err != nil { 440 return fmt.Errorf("merkle proof verification failed: %v", err) 441 } 442 if len(reads.reads) != nodeSet.KeyCount() { 443 return errUselessNodes 444 } 445 446 var node light.ChtNode 447 if err := rlp.DecodeBytes(value, &node); err != nil { 448 return err 449 } 450 if node.Hash != header.Hash() { 451 return errCHTHashMismatch 452 } 453 if r.BlockNum != header.Number.Uint64() { 454 return errCHTNumberMismatch 455 } 456 // Verifications passed, store and return 457 r.Header = header 458 r.Proof = nodeSet 459 r.Td = node.Td 460 default: 461 return errInvalidMessageType 462 } 463 return nil 464 } 465 466 type BloomReq struct { 467 BloomTrieNum, BitIdx, SectionIdx, FromLevel uint64 468 } 469 470 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 471 type BloomRequest light.BloomRequest 472 473 // GetCost returns the cost of the given ODR request according to the serving 474 // peer's cost table (implementation of LesOdrRequest) 475 func (r *BloomRequest) GetCost(peer *peer) uint64 { 476 return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIdxList)) 477 } 478 479 // CanSend tells if a certain peer is suitable for serving the given request 480 func (r *BloomRequest) CanSend(peer *peer) bool { 481 peer.lock.RLock() 482 defer peer.lock.RUnlock() 483 484 if peer.version < lpv2 { 485 return false 486 } 487 return peer.headInfo.Number >= light.HelperTrieConfirmations && r.BloomTrieNum <= (peer.headInfo.Number-light.HelperTrieConfirmations)/light.BloomTrieFrequency 488 } 489 490 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 491 func (r *BloomRequest) Request(reqID uint64, peer *peer) error { 492 peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) 493 reqs := make([]HelperTrieReq, len(r.SectionIdxList)) 494 495 var encNumber [10]byte 496 binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) 497 498 for i, sectionIdx := range r.SectionIdxList { 499 binary.BigEndian.PutUint64(encNumber[2:10], sectionIdx) 500 reqs[i] = HelperTrieReq{ 501 HelperTrieType: htBloomBits, 502 TrieIdx: r.BloomTrieNum, 503 Key: common.CopyBytes(encNumber[:]), 504 } 505 } 506 return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs) 507 } 508 509 // Valid processes an ODR request reply message from the LES network 510 // returns true and stores results in memory if the message was a valid reply 511 // to the request (implementation of LesOdrRequest) 512 func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { 513 log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIdxList) 514 515 // Ensure we have a correct message with a single proof element 516 if msg.MsgType != MsgHelperTrieProofs { 517 return errInvalidMessageType 518 } 519 resps := msg.Obj.(HelperTrieResps) 520 proofs := resps.Proofs 521 nodeSet := proofs.NodeSet() 522 reads := &readTraceDB{db: nodeSet} 523 524 r.BloomBits = make([][]byte, len(r.SectionIdxList)) 525 526 // Verify the proofs 527 var encNumber [10]byte 528 binary.BigEndian.PutUint16(encNumber[0:2], uint16(r.BitIdx)) 529 530 for i, idx := range r.SectionIdxList { 531 binary.BigEndian.PutUint64(encNumber[2:10], idx) 532 value, err, _ := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) 533 if err != nil { 534 return err 535 } 536 r.BloomBits[i] = value 537 } 538 539 if len(reads.reads) != nodeSet.KeyCount() { 540 return errUselessNodes 541 } 542 r.Proofs = nodeSet 543 return nil 544 } 545 546 // readTraceDB stores the keys of database reads. We use this to check that received node 547 // sets contain only the trie nodes necessary to make proofs pass. 548 type readTraceDB struct { 549 db trie.DatabaseReader 550 reads map[string]struct{} 551 } 552 553 // Get returns a stored node 554 func (db *readTraceDB) Get(k []byte) ([]byte, error) { 555 if db.reads == nil { 556 db.reads = make(map[string]struct{}) 557 } 558 db.reads[string(k)] = struct{}{} 559 return db.db.Get(k) 560 } 561 562 // Has returns true if the node set contains the given key 563 func (db *readTraceDB) Has(key []byte) (bool, error) { 564 _, err := db.Get(key) 565 return err == nil, nil 566 }