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