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