github.com/cryptogateway/go-paymex@v0.0.0-20210204174735-96277fb1e602/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/cryptogateway/go-paymex/common" 25 "github.com/cryptogateway/go-paymex/core/rawdb" 26 "github.com/cryptogateway/go-paymex/core/types" 27 "github.com/cryptogateway/go-paymex/crypto" 28 "github.com/cryptogateway/go-paymex/ethdb" 29 "github.com/cryptogateway/go-paymex/light" 30 "github.com/cryptogateway/go-paymex/log" 31 "github.com/cryptogateway/go-paymex/rlp" 32 "github.com/cryptogateway/go-paymex/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 // helper trie auxiliary types 299 // htAuxNone = 1 ; deprecated number, used in les2/3 previously. 300 htAuxHeader = 2 // applicable for htCanonical, requests for relevant headers 301 ) 302 303 type HelperTrieReq struct { 304 Type uint 305 TrieIdx uint64 306 Key []byte 307 FromLevel, AuxReq uint 308 } 309 310 type HelperTrieResps struct { // describes all responses, not just a single one 311 Proofs light.NodeList 312 AuxData [][]byte 313 } 314 315 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 316 type ChtRequest light.ChtRequest 317 318 // GetCost returns the cost of the given ODR request according to the serving 319 // peer's cost table (implementation of LesOdrRequest) 320 func (r *ChtRequest) GetCost(peer *serverPeer) uint64 { 321 return peer.getRequestCost(GetHelperTrieProofsMsg, 1) 322 } 323 324 // CanSend tells if a certain peer is suitable for serving the given request 325 func (r *ChtRequest) CanSend(peer *serverPeer) bool { 326 peer.lock.RLock() 327 defer peer.lock.RUnlock() 328 329 return peer.headInfo.Number >= r.Config.ChtConfirms && r.ChtNum <= (peer.headInfo.Number-r.Config.ChtConfirms)/r.Config.ChtSize 330 } 331 332 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 333 func (r *ChtRequest) Request(reqID uint64, peer *serverPeer) error { 334 peer.Log().Debug("Requesting CHT", "cht", r.ChtNum, "block", r.BlockNum) 335 var encNum [8]byte 336 binary.BigEndian.PutUint64(encNum[:], r.BlockNum) 337 req := HelperTrieReq{ 338 Type: htCanonical, 339 TrieIdx: r.ChtNum, 340 Key: encNum[:], 341 AuxReq: htAuxHeader, 342 } 343 return peer.requestHelperTrieProofs(reqID, []HelperTrieReq{req}) 344 } 345 346 // Valid processes an ODR request reply message from the LES network 347 // returns true and stores results in memory if the message was a valid reply 348 // to the request (implementation of LesOdrRequest) 349 func (r *ChtRequest) Validate(db ethdb.Database, msg *Msg) error { 350 log.Debug("Validating CHT", "cht", r.ChtNum, "block", r.BlockNum) 351 352 if msg.MsgType != MsgHelperTrieProofs { 353 return errInvalidMessageType 354 } 355 resp := msg.Obj.(HelperTrieResps) 356 if len(resp.AuxData) != 1 { 357 return errInvalidEntryCount 358 } 359 nodeSet := resp.Proofs.NodeSet() 360 headerEnc := resp.AuxData[0] 361 if len(headerEnc) == 0 { 362 return errHeaderUnavailable 363 } 364 header := new(types.Header) 365 if err := rlp.DecodeBytes(headerEnc, header); err != nil { 366 return errHeaderUnavailable 367 } 368 // Verify the CHT 369 var ( 370 node light.ChtNode 371 encNumber [8]byte 372 ) 373 binary.BigEndian.PutUint64(encNumber[:], r.BlockNum) 374 375 reads := &readTraceDB{db: nodeSet} 376 value, err := trie.VerifyProof(r.ChtRoot, encNumber[:], reads) 377 if err != nil { 378 return fmt.Errorf("merkle proof verification failed: %v", err) 379 } 380 if len(reads.reads) != nodeSet.KeyCount() { 381 return errUselessNodes 382 } 383 if err := rlp.DecodeBytes(value, &node); err != nil { 384 return err 385 } 386 if node.Hash != header.Hash() { 387 return errCHTHashMismatch 388 } 389 if r.BlockNum != header.Number.Uint64() { 390 return errCHTNumberMismatch 391 } 392 // Verifications passed, store and return 393 r.Header = header 394 r.Proof = nodeSet 395 r.Td = node.Td 396 return nil 397 } 398 399 type BloomReq struct { 400 BloomTrieNum, BitIdx, SectionIndex, FromLevel uint64 401 } 402 403 // ODR request type for requesting headers by Canonical Hash Trie, see LesOdrRequest interface 404 type BloomRequest light.BloomRequest 405 406 // GetCost returns the cost of the given ODR request according to the serving 407 // peer's cost table (implementation of LesOdrRequest) 408 func (r *BloomRequest) GetCost(peer *serverPeer) uint64 { 409 return peer.getRequestCost(GetHelperTrieProofsMsg, len(r.SectionIndexList)) 410 } 411 412 // CanSend tells if a certain peer is suitable for serving the given request 413 func (r *BloomRequest) CanSend(peer *serverPeer) bool { 414 peer.lock.RLock() 415 defer peer.lock.RUnlock() 416 417 if peer.version < lpv2 { 418 return false 419 } 420 return peer.headInfo.Number >= r.Config.BloomTrieConfirms && r.BloomTrieNum <= (peer.headInfo.Number-r.Config.BloomTrieConfirms)/r.Config.BloomTrieSize 421 } 422 423 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 424 func (r *BloomRequest) Request(reqID uint64, peer *serverPeer) error { 425 peer.Log().Debug("Requesting BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 426 reqs := make([]HelperTrieReq, len(r.SectionIndexList)) 427 428 var encNumber [10]byte 429 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 430 431 for i, sectionIdx := range r.SectionIndexList { 432 binary.BigEndian.PutUint64(encNumber[2:], sectionIdx) 433 reqs[i] = HelperTrieReq{ 434 Type: htBloomBits, 435 TrieIdx: r.BloomTrieNum, 436 Key: common.CopyBytes(encNumber[:]), 437 } 438 } 439 return peer.requestHelperTrieProofs(reqID, reqs) 440 } 441 442 // Valid processes an ODR request reply message from the LES network 443 // returns true and stores results in memory if the message was a valid reply 444 // to the request (implementation of LesOdrRequest) 445 func (r *BloomRequest) Validate(db ethdb.Database, msg *Msg) error { 446 log.Debug("Validating BloomBits", "bloomTrie", r.BloomTrieNum, "bitIdx", r.BitIdx, "sections", r.SectionIndexList) 447 448 // Ensure we have a correct message with a single proof element 449 if msg.MsgType != MsgHelperTrieProofs { 450 return errInvalidMessageType 451 } 452 resps := msg.Obj.(HelperTrieResps) 453 proofs := resps.Proofs 454 nodeSet := proofs.NodeSet() 455 reads := &readTraceDB{db: nodeSet} 456 457 r.BloomBits = make([][]byte, len(r.SectionIndexList)) 458 459 // Verify the proofs 460 var encNumber [10]byte 461 binary.BigEndian.PutUint16(encNumber[:2], uint16(r.BitIdx)) 462 463 for i, idx := range r.SectionIndexList { 464 binary.BigEndian.PutUint64(encNumber[2:], idx) 465 value, err := trie.VerifyProof(r.BloomTrieRoot, encNumber[:], reads) 466 if err != nil { 467 return err 468 } 469 r.BloomBits[i] = value 470 } 471 472 if len(reads.reads) != nodeSet.KeyCount() { 473 return errUselessNodes 474 } 475 r.Proofs = nodeSet 476 return nil 477 } 478 479 // TxStatusRequest is the ODR request type for transaction status 480 type TxStatusRequest light.TxStatusRequest 481 482 // GetCost returns the cost of the given ODR request according to the serving 483 // peer's cost table (implementation of LesOdrRequest) 484 func (r *TxStatusRequest) GetCost(peer *serverPeer) uint64 { 485 return peer.getRequestCost(GetTxStatusMsg, len(r.Hashes)) 486 } 487 488 // CanSend tells if a certain peer is suitable for serving the given request 489 func (r *TxStatusRequest) CanSend(peer *serverPeer) bool { 490 return peer.serveTxLookup 491 } 492 493 // Request sends an ODR request to the LES network (implementation of LesOdrRequest) 494 func (r *TxStatusRequest) Request(reqID uint64, peer *serverPeer) error { 495 peer.Log().Debug("Requesting transaction status", "count", len(r.Hashes)) 496 return peer.requestTxStatus(reqID, r.Hashes) 497 } 498 499 // Valid processes an ODR request reply message from the LES network 500 // returns true and stores results in memory if the message was a valid reply 501 // to the request (implementation of LesOdrRequest) 502 func (r *TxStatusRequest) Validate(db ethdb.Database, msg *Msg) error { 503 log.Debug("Validating transaction status", "count", len(r.Hashes)) 504 505 // Ensure we have a correct message with a single block body 506 if msg.MsgType != MsgTxStatus { 507 return errInvalidMessageType 508 } 509 status := msg.Obj.([]light.TxStatus) 510 if len(status) != len(r.Hashes) { 511 return errInvalidEntryCount 512 } 513 r.Status = status 514 return nil 515 } 516 517 // readTraceDB stores the keys of database reads. We use this to check that received node 518 // sets contain only the trie nodes necessary to make proofs pass. 519 type readTraceDB struct { 520 db ethdb.KeyValueReader 521 reads map[string]struct{} 522 } 523 524 // Get returns a stored node 525 func (db *readTraceDB) Get(k []byte) ([]byte, error) { 526 if db.reads == nil { 527 db.reads = make(map[string]struct{}) 528 } 529 db.reads[string(k)] = struct{}{} 530 return db.db.Get(k) 531 } 532 533 // Has returns true if the node set contains the given key 534 func (db *readTraceDB) Has(key []byte) (bool, error) { 535 _, err := db.Get(key) 536 return err == nil, nil 537 }