github.com/theQRL/go-zond@v0.1.1/les/server_requests.go (about) 1 // Copyright 2021 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 "encoding/json" 22 23 "github.com/theQRL/go-zond/common" 24 "github.com/theQRL/go-zond/core" 25 "github.com/theQRL/go-zond/core/state" 26 "github.com/theQRL/go-zond/core/txpool" 27 "github.com/theQRL/go-zond/core/types" 28 "github.com/theQRL/go-zond/light" 29 "github.com/theQRL/go-zond/log" 30 "github.com/theQRL/go-zond/metrics" 31 "github.com/theQRL/go-zond/rlp" 32 "github.com/theQRL/go-zond/trie" 33 ) 34 35 // serverBackend defines the backend functions needed for serving LES requests 36 type serverBackend interface { 37 ArchiveMode() bool 38 AddTxsSync() bool 39 BlockChain() *core.BlockChain 40 TxPool() *txpool.TxPool 41 GetHelperTrie(typ uint, index uint64) *trie.Trie 42 } 43 44 // Decoder is implemented by the messages passed to the handler functions 45 type Decoder interface { 46 Decode(val interface{}) error 47 } 48 49 // RequestType is a static struct that describes an LES request type and references 50 // its handler function. 51 type RequestType struct { 52 Name string 53 MaxCount uint64 54 InPacketsMeter, InTrafficMeter, OutPacketsMeter, OutTrafficMeter metrics.Meter 55 ServingTimeMeter metrics.Timer 56 Handle func(msg Decoder) (serve serveRequestFn, reqID, amount uint64, err error) 57 } 58 59 // serveRequestFn is returned by the request handler functions after decoding the request. 60 // This function does the actual request serving using the supplied backend. waitOrStop is 61 // called between serving individual request items and may block if the serving process 62 // needs to be throttled. If it returns false then the process is terminated. 63 // The reply is not sent by this function yet. The flow control feedback value is supplied 64 // by the protocol handler when calling the send function of the returned reply struct. 65 type serveRequestFn func(backend serverBackend, peer *clientPeer, waitOrStop func() bool) *reply 66 67 // Les3 contains the request types supported by les/2 and les/3 68 var Les3 = map[uint64]RequestType{ 69 GetBlockHeadersMsg: { 70 Name: "block header request", 71 MaxCount: MaxHeaderFetch, 72 InPacketsMeter: miscInHeaderPacketsMeter, 73 InTrafficMeter: miscInHeaderTrafficMeter, 74 OutPacketsMeter: miscOutHeaderPacketsMeter, 75 OutTrafficMeter: miscOutHeaderTrafficMeter, 76 ServingTimeMeter: miscServingTimeHeaderTimer, 77 Handle: handleGetBlockHeaders, 78 }, 79 GetBlockBodiesMsg: { 80 Name: "block bodies request", 81 MaxCount: MaxBodyFetch, 82 InPacketsMeter: miscInBodyPacketsMeter, 83 InTrafficMeter: miscInBodyTrafficMeter, 84 OutPacketsMeter: miscOutBodyPacketsMeter, 85 OutTrafficMeter: miscOutBodyTrafficMeter, 86 ServingTimeMeter: miscServingTimeBodyTimer, 87 Handle: handleGetBlockBodies, 88 }, 89 GetCodeMsg: { 90 Name: "code request", 91 MaxCount: MaxCodeFetch, 92 InPacketsMeter: miscInCodePacketsMeter, 93 InTrafficMeter: miscInCodeTrafficMeter, 94 OutPacketsMeter: miscOutCodePacketsMeter, 95 OutTrafficMeter: miscOutCodeTrafficMeter, 96 ServingTimeMeter: miscServingTimeCodeTimer, 97 Handle: handleGetCode, 98 }, 99 GetReceiptsMsg: { 100 Name: "receipts request", 101 MaxCount: MaxReceiptFetch, 102 InPacketsMeter: miscInReceiptPacketsMeter, 103 InTrafficMeter: miscInReceiptTrafficMeter, 104 OutPacketsMeter: miscOutReceiptPacketsMeter, 105 OutTrafficMeter: miscOutReceiptTrafficMeter, 106 ServingTimeMeter: miscServingTimeReceiptTimer, 107 Handle: handleGetReceipts, 108 }, 109 GetProofsV2Msg: { 110 Name: "les/2 proofs request", 111 MaxCount: MaxProofsFetch, 112 InPacketsMeter: miscInTrieProofPacketsMeter, 113 InTrafficMeter: miscInTrieProofTrafficMeter, 114 OutPacketsMeter: miscOutTrieProofPacketsMeter, 115 OutTrafficMeter: miscOutTrieProofTrafficMeter, 116 ServingTimeMeter: miscServingTimeTrieProofTimer, 117 Handle: handleGetProofs, 118 }, 119 GetHelperTrieProofsMsg: { 120 Name: "helper trie proof request", 121 MaxCount: MaxHelperTrieProofsFetch, 122 InPacketsMeter: miscInHelperTriePacketsMeter, 123 InTrafficMeter: miscInHelperTrieTrafficMeter, 124 OutPacketsMeter: miscOutHelperTriePacketsMeter, 125 OutTrafficMeter: miscOutHelperTrieTrafficMeter, 126 ServingTimeMeter: miscServingTimeHelperTrieTimer, 127 Handle: handleGetHelperTrieProofs, 128 }, 129 SendTxV2Msg: { 130 Name: "new transactions", 131 MaxCount: MaxTxSend, 132 InPacketsMeter: miscInTxsPacketsMeter, 133 InTrafficMeter: miscInTxsTrafficMeter, 134 OutPacketsMeter: miscOutTxsPacketsMeter, 135 OutTrafficMeter: miscOutTxsTrafficMeter, 136 ServingTimeMeter: miscServingTimeTxTimer, 137 Handle: handleSendTx, 138 }, 139 GetTxStatusMsg: { 140 Name: "transaction status query request", 141 MaxCount: MaxTxStatus, 142 InPacketsMeter: miscInTxStatusPacketsMeter, 143 InTrafficMeter: miscInTxStatusTrafficMeter, 144 OutPacketsMeter: miscOutTxStatusPacketsMeter, 145 OutTrafficMeter: miscOutTxStatusTrafficMeter, 146 ServingTimeMeter: miscServingTimeTxStatusTimer, 147 Handle: handleGetTxStatus, 148 }, 149 } 150 151 // handleGetBlockHeaders handles a block header request 152 func handleGetBlockHeaders(msg Decoder) (serveRequestFn, uint64, uint64, error) { 153 var r GetBlockHeadersPacket 154 if err := msg.Decode(&r); err != nil { 155 return nil, 0, 0, err 156 } 157 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 158 // Gather headers until the fetch or network limits is reached 159 var ( 160 bc = backend.BlockChain() 161 hashMode = r.Query.Origin.Hash != (common.Hash{}) 162 first = true 163 maxNonCanonical = uint64(100) 164 bytes common.StorageSize 165 headers []*types.Header 166 unknown bool 167 ) 168 for !unknown && len(headers) < int(r.Query.Amount) && bytes < softResponseLimit { 169 if !first && !waitOrStop() { 170 return nil 171 } 172 // Retrieve the next header satisfying the r 173 var origin *types.Header 174 if hashMode { 175 if first { 176 origin = bc.GetHeaderByHash(r.Query.Origin.Hash) 177 if origin != nil { 178 r.Query.Origin.Number = origin.Number.Uint64() 179 } 180 } else { 181 origin = bc.GetHeader(r.Query.Origin.Hash, r.Query.Origin.Number) 182 } 183 } else { 184 origin = bc.GetHeaderByNumber(r.Query.Origin.Number) 185 } 186 if origin == nil { 187 break 188 } 189 headers = append(headers, origin) 190 bytes += estHeaderRlpSize 191 192 // Advance to the next header of the r 193 switch { 194 case hashMode && r.Query.Reverse: 195 // Hash based traversal towards the genesis block 196 ancestor := r.Query.Skip + 1 197 if ancestor == 0 { 198 unknown = true 199 } else { 200 r.Query.Origin.Hash, r.Query.Origin.Number = bc.GetAncestor(r.Query.Origin.Hash, r.Query.Origin.Number, ancestor, &maxNonCanonical) 201 unknown = r.Query.Origin.Hash == common.Hash{} 202 } 203 case hashMode && !r.Query.Reverse: 204 // Hash based traversal towards the leaf block 205 var ( 206 current = origin.Number.Uint64() 207 next = current + r.Query.Skip + 1 208 ) 209 if next <= current { 210 infos, _ := json.Marshal(p.Peer.Info()) 211 p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", r.Query.Skip, "next", next, "attacker", string(infos)) 212 unknown = true 213 } else { 214 if header := bc.GetHeaderByNumber(next); header != nil { 215 nextHash := header.Hash() 216 expOldHash, _ := bc.GetAncestor(nextHash, next, r.Query.Skip+1, &maxNonCanonical) 217 if expOldHash == r.Query.Origin.Hash { 218 r.Query.Origin.Hash, r.Query.Origin.Number = nextHash, next 219 } else { 220 unknown = true 221 } 222 } else { 223 unknown = true 224 } 225 } 226 case r.Query.Reverse: 227 // Number based traversal towards the genesis block 228 if r.Query.Origin.Number >= r.Query.Skip+1 { 229 r.Query.Origin.Number -= r.Query.Skip + 1 230 } else { 231 unknown = true 232 } 233 234 case !r.Query.Reverse: 235 // Number based traversal towards the leaf block 236 r.Query.Origin.Number += r.Query.Skip + 1 237 } 238 first = false 239 } 240 return p.replyBlockHeaders(r.ReqID, headers) 241 }, r.ReqID, r.Query.Amount, nil 242 } 243 244 // handleGetBlockBodies handles a block body request 245 func handleGetBlockBodies(msg Decoder) (serveRequestFn, uint64, uint64, error) { 246 var r GetBlockBodiesPacket 247 if err := msg.Decode(&r); err != nil { 248 return nil, 0, 0, err 249 } 250 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 251 var ( 252 bytes int 253 bodies []rlp.RawValue 254 ) 255 bc := backend.BlockChain() 256 for i, hash := range r.Hashes { 257 if i != 0 && !waitOrStop() { 258 return nil 259 } 260 if bytes >= softResponseLimit { 261 break 262 } 263 body := bc.GetBodyRLP(hash) 264 if body == nil { 265 p.bumpInvalid() 266 continue 267 } 268 bodies = append(bodies, body) 269 bytes += len(body) 270 } 271 return p.replyBlockBodiesRLP(r.ReqID, bodies) 272 }, r.ReqID, uint64(len(r.Hashes)), nil 273 } 274 275 // handleGetCode handles a contract code request 276 func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) { 277 var r GetCodePacket 278 if err := msg.Decode(&r); err != nil { 279 return nil, 0, 0, err 280 } 281 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 282 var ( 283 bytes int 284 data [][]byte 285 ) 286 bc := backend.BlockChain() 287 for i, request := range r.Reqs { 288 if i != 0 && !waitOrStop() { 289 return nil 290 } 291 // Look up the root hash belonging to the request 292 header := bc.GetHeaderByHash(request.BHash) 293 if header == nil { 294 p.Log().Warn("Failed to retrieve associate header for code", "hash", request.BHash) 295 p.bumpInvalid() 296 continue 297 } 298 // Refuse to search stale state data in the database since looking for 299 // a non-exist key is kind of expensive. 300 local := bc.CurrentHeader().Number.Uint64() 301 if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { 302 p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local) 303 p.bumpInvalid() 304 continue 305 } 306 address := common.BytesToAddress(request.AccountAddress) 307 account, err := getAccount(bc.TrieDB(), header.Root, address) 308 if err != nil { 309 p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", address, "err", err) 310 p.bumpInvalid() 311 continue 312 } 313 code, err := bc.StateCache().ContractCode(address, common.BytesToHash(account.CodeHash)) 314 if err != nil { 315 p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", address, "codehash", common.BytesToHash(account.CodeHash), "err", err) 316 continue 317 } 318 // Accumulate the code and abort if enough data was retrieved 319 data = append(data, code) 320 if bytes += len(code); bytes >= softResponseLimit { 321 break 322 } 323 } 324 return p.replyCode(r.ReqID, data) 325 }, r.ReqID, uint64(len(r.Reqs)), nil 326 } 327 328 // handleGetReceipts handles a block receipts request 329 func handleGetReceipts(msg Decoder) (serveRequestFn, uint64, uint64, error) { 330 var r GetReceiptsPacket 331 if err := msg.Decode(&r); err != nil { 332 return nil, 0, 0, err 333 } 334 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 335 var ( 336 bytes int 337 receipts []rlp.RawValue 338 ) 339 bc := backend.BlockChain() 340 for i, hash := range r.Hashes { 341 if i != 0 && !waitOrStop() { 342 return nil 343 } 344 if bytes >= softResponseLimit { 345 break 346 } 347 // Retrieve the requested block's receipts, skipping if unknown to us 348 results := bc.GetReceiptsByHash(hash) 349 if results == nil { 350 if header := bc.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyReceiptsHash { 351 p.bumpInvalid() 352 continue 353 } 354 } 355 // If known, encode and queue for response packet 356 if encoded, err := rlp.EncodeToBytes(results); err != nil { 357 log.Error("Failed to encode receipt", "err", err) 358 } else { 359 receipts = append(receipts, encoded) 360 bytes += len(encoded) 361 } 362 } 363 return p.replyReceiptsRLP(r.ReqID, receipts) 364 }, r.ReqID, uint64(len(r.Hashes)), nil 365 } 366 367 // handleGetProofs handles a proof request 368 func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { 369 var r GetProofsPacket 370 if err := msg.Decode(&r); err != nil { 371 return nil, 0, 0, err 372 } 373 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 374 var ( 375 lastBHash common.Hash 376 root common.Hash 377 header *types.Header 378 err error 379 ) 380 bc := backend.BlockChain() 381 nodes := light.NewNodeSet() 382 383 for i, request := range r.Reqs { 384 if i != 0 && !waitOrStop() { 385 return nil 386 } 387 // Look up the root hash belonging to the request 388 if request.BHash != lastBHash { 389 root, lastBHash = common.Hash{}, request.BHash 390 391 if header = bc.GetHeaderByHash(request.BHash); header == nil { 392 p.Log().Warn("Failed to retrieve header for proof", "hash", request.BHash) 393 p.bumpInvalid() 394 continue 395 } 396 // Refuse to search stale state data in the database since looking for 397 // a non-exist key is kind of expensive. 398 local := bc.CurrentHeader().Number.Uint64() 399 if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { 400 p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local) 401 p.bumpInvalid() 402 continue 403 } 404 root = header.Root 405 } 406 // If a header lookup failed (non existent), ignore subsequent requests for the same header 407 if root == (common.Hash{}) { 408 p.bumpInvalid() 409 continue 410 } 411 // Open the account or storage trie for the request 412 statedb := bc.StateCache() 413 414 var trie state.Trie 415 switch len(request.AccountAddress) { 416 case 0: 417 // No account key specified, open an account trie 418 trie, err = statedb.OpenTrie(root) 419 if trie == nil || err != nil { 420 p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err) 421 continue 422 } 423 default: 424 // Account key specified, open a storage trie 425 address := common.BytesToAddress(request.AccountAddress) 426 account, err := getAccount(bc.TrieDB(), root, address) 427 if err != nil { 428 p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", address, "err", err) 429 p.bumpInvalid() 430 continue 431 } 432 trie, err = statedb.OpenStorageTrie(root, address, account.Root) 433 if trie == nil || err != nil { 434 p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "account", address, "root", account.Root, "err", err) 435 continue 436 } 437 } 438 // Prove the user's request from the account or storage trie 439 if err := trie.Prove(request.Key, nodes); err != nil { 440 p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err) 441 continue 442 } 443 if nodes.DataSize() >= softResponseLimit { 444 break 445 } 446 } 447 return p.replyProofsV2(r.ReqID, nodes.NodeList()) 448 }, r.ReqID, uint64(len(r.Reqs)), nil 449 } 450 451 // handleGetHelperTrieProofs handles a helper trie proof request 452 func handleGetHelperTrieProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { 453 var r GetHelperTrieProofsPacket 454 if err := msg.Decode(&r); err != nil { 455 return nil, 0, 0, err 456 } 457 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 458 var ( 459 lastIdx uint64 460 lastType uint 461 auxTrie *trie.Trie 462 auxBytes int 463 auxData [][]byte 464 ) 465 bc := backend.BlockChain() 466 nodes := light.NewNodeSet() 467 for i, request := range r.Reqs { 468 if i != 0 && !waitOrStop() { 469 return nil 470 } 471 if auxTrie == nil || request.Type != lastType || request.TrieIdx != lastIdx { 472 lastType, lastIdx = request.Type, request.TrieIdx 473 auxTrie = backend.GetHelperTrie(request.Type, request.TrieIdx) 474 } 475 if auxTrie == nil { 476 return nil 477 } 478 // TODO(rjl493456442) short circuit if the proving is failed. 479 // The original client side code has a dirty hack to retrieve 480 // the headers with no valid proof. Keep the compatibility for 481 // legacy les protocol and drop this hack when the les2/3 are 482 // not supported. 483 err := auxTrie.Prove(request.Key, nodes) 484 if p.version >= lpv4 && err != nil { 485 return nil 486 } 487 if request.Type == htCanonical && request.AuxReq == htAuxHeader && len(request.Key) == 8 { 488 header := bc.GetHeaderByNumber(binary.BigEndian.Uint64(request.Key)) 489 data, err := rlp.EncodeToBytes(header) 490 if err != nil { 491 log.Error("Failed to encode header", "err", err) 492 return nil 493 } 494 auxData = append(auxData, data) 495 auxBytes += len(data) 496 } 497 if nodes.DataSize()+auxBytes >= softResponseLimit { 498 break 499 } 500 } 501 return p.replyHelperTrieProofs(r.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData}) 502 }, r.ReqID, uint64(len(r.Reqs)), nil 503 } 504 505 // handleSendTx handles a transaction propagation request 506 func handleSendTx(msg Decoder) (serveRequestFn, uint64, uint64, error) { 507 var r SendTxPacket 508 if err := msg.Decode(&r); err != nil { 509 return nil, 0, 0, err 510 } 511 amount := uint64(len(r.Txs)) 512 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 513 stats := make([]light.TxStatus, len(r.Txs)) 514 for i, tx := range r.Txs { 515 if i != 0 && !waitOrStop() { 516 return nil 517 } 518 hash := tx.Hash() 519 stats[i] = txStatus(backend, hash) 520 if stats[i].Status == txpool.TxStatusUnknown { 521 if errs := backend.TxPool().Add([]*types.Transaction{tx}, false, backend.AddTxsSync()); errs[0] != nil { 522 stats[i].Error = errs[0].Error() 523 continue 524 } 525 stats[i] = txStatus(backend, hash) 526 } 527 } 528 return p.replyTxStatus(r.ReqID, stats) 529 }, r.ReqID, amount, nil 530 } 531 532 // handleGetTxStatus handles a transaction status query 533 func handleGetTxStatus(msg Decoder) (serveRequestFn, uint64, uint64, error) { 534 var r GetTxStatusPacket 535 if err := msg.Decode(&r); err != nil { 536 return nil, 0, 0, err 537 } 538 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 539 stats := make([]light.TxStatus, len(r.Hashes)) 540 for i, hash := range r.Hashes { 541 if i != 0 && !waitOrStop() { 542 return nil 543 } 544 stats[i] = txStatus(backend, hash) 545 } 546 return p.replyTxStatus(r.ReqID, stats) 547 }, r.ReqID, uint64(len(r.Hashes)), nil 548 } 549 550 // txStatus returns the status of a specified transaction. 551 func txStatus(b serverBackend, hash common.Hash) light.TxStatus { 552 var stat light.TxStatus 553 // Looking the transaction in txpool first. 554 stat.Status = b.TxPool().Status(hash) 555 556 // If the transaction is unknown to the pool, try looking it up locally. 557 if stat.Status == txpool.TxStatusUnknown { 558 lookup := b.BlockChain().GetTransactionLookup(hash) 559 if lookup != nil { 560 stat.Status = txpool.TxStatusIncluded 561 stat.Lookup = lookup 562 } 563 } 564 return stat 565 }