github.com/cheng762/platon-go@v1.8.17-0.20190529111256-7deff2d7be26/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/PlatONnetwork/PlatON-Go/common" 27 "github.com/PlatONnetwork/PlatON-Go/core/rawdb" 28 "github.com/PlatONnetwork/PlatON-Go/core/types" 29 "github.com/PlatONnetwork/PlatON-Go/crypto" 30 "github.com/PlatONnetwork/PlatON-Go/ethdb" 31 "github.com/PlatONnetwork/PlatON-Go/light" 32 "github.com/PlatONnetwork/PlatON-Go/log" 33 "github.com/PlatONnetwork/PlatON-Go/rlp" 34 "github.com/PlatONnetwork/PlatON-Go/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 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 := 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) 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 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 case MsgHelperTrieProofs: 432 resp := msg.Obj.(HelperTrieResps) 433 if len(resp.AuxData) != 1 { 434 return errInvalidEntryCount 435 } 436 nodeSet := resp.Proofs.NodeSet() 437 headerEnc := resp.AuxData[0] 438 if len(headerEnc) == 0 { 439 return errHeaderUnavailable 440 } 441 header := new(types.Header) 442 if err := rlp.DecodeBytes(headerEnc, header); err != nil { 443 return errHeaderUnavailable 444 } 445 446 // Verify the CHT 447 var encNumber [8]byte 448 binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) 449 450 reads := &readTraceDB{db: nodeSet} 451 value, _, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) 452 if err != nil { 453 return fmt.Errorf("merkle proof verification failed: %v", err) 454 } 455 if len(reads.reads) != nodeSet.KeyCount() { 456 return errUselessNodes 457 } 458 459 var node light.ChtNode 460 if err := rlp.DecodeBytes(value, &node); err != nil { 461 return err 462 } 463 if node.Hash != header.Hash() { 464 return errCHTHashMismatch 465 } 466 if r.BlockNum != header.Number.Uint64() { 467 return errCHTNumberMismatch 468 } 469 // Verifications passed, store and return 470 r.Header = header 471 r.Proof = nodeSet 472 default: 473 return errInvalidMessageType 474 } 475 return nil 476 } 477 478 type BloomReq struct { 479 BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 480 } 481 482 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 483 type BloomRequest light.BloomRequest 484 485 // GetCost returns the cost of the given ODR request according to the serving 486 // peer's cost table (implementation of LesOdrRequest) 487 func (r *BloomRequest) GetCost(peer *peer) uint64 { 488 return peer.GetRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList)) 489 } 490 491 // CanSend tells if a certain peer is suitable for serving the given request 492 func (r *BloomRequest) CanSend(peer *peer) bool { 493 peer.lock.RLock() 494 defer peer.lock.RUnlock() 495 496 if peer.version < lpv2 { 497 return false 498 } 499 return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize 500 } 501 502 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 503 func (r *BloomRequest) Request(reqID uint64, peer *peer) error { 504 peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 505 reqs := make([]HelperTrieReq, len(r.SectionIndexList)) 506 507 var encNumber [10]byte 508 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 509 510 for i, sectionIdx := range r.SectionIndexList { 511 binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) 512 reqs[i] = HelperTrieReq{ 513 Type: htBloomBits, 514 TrieIdx: r.BloomTrieNum, 515 Key: common.CopyBytes(encNumber[:]), 516 } 517 } 518 return peer.RequestHelperTrieProofs(reqID, r.GetCost(peer), reqs) 519 } 520 521 // Valid processes an ODR request reply message from the LES network 522 // returns true and stores results in memory if the message was a valid reply 523 // to the request (implementation of LesOdrRequest) 524 func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { 525 log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 526 527 // Ensure we have a correct message with a single proof element 528 if msg.MsgType != MsgHelperTrieProofs { 529 return errInvalidMessageType 530 } 531 resps := msg.Obj.(HelperTrieResps) 532 proofs := resps.Proofs 533 nodeSet := proofs.NodeSet() 534 reads := &readTraceDB{db: nodeSet} 535 536 r.BloomBits = make([][]byte, len(r.SectionIndexList)) 537 538 // Verify the proofs 539 var encNumber [10]byte 540 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 541 542 for i, idx := range r.SectionIndexList { 543 binary.BigEndian.PutUint64(encNumber[2:], idx) 544 value, _, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) 545 if err != nil { 546 return err 547 } 548 r.BloomBits[i] = value 549 } 550 551 if len(reads.reads) != nodeSet.KeyCount() { 552 return errUselessNodes 553 } 554 r.Proofs = nodeSet 555 return nil 556 } 557 558 // readTraceDB stores the keys of database reads. We use this to check that received node 559 // sets contain only the trie nodes necessary to make proofs pass. 560 type readTraceDB struct { 561 db trie.DatabaseReader 562 reads map[string]struct{} 563 } 564 565 // Get returns a stored node 566 func (db *readTraceDB) Get(k []byte) ([]byte, error) { 567 if db.reads == nil { 568 db.reads = make(map[string]struct{}) 569 } 570 db.reads[string(k)] = struct{}{} 571 return db.db.Get(k) 572 } 573 574 // Has returns true if the node set contains the given key 575 func (db *readTraceDB) Has(key []byte) (bool, error) { 576 _, err := db.Get(key) 577 return err == nil, nil 578 }