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