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