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