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