github.com/jimmyx0x/go-ethereum@v1.10.28/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/core" 25 "github.com/ethereum/go-ethereum/core/state" 26 "github.com/ethereum/go-ethereum/core/txpool" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/light" 29 "github.com/ethereum/go-ethereum/log" 30 "github.com/ethereum/go-ethereum/metrics" 31 "github.com/ethereum/go-ethereum/rlp" 32 "github.com/ethereum/go-ethereum/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 triedb := bc.StateCache().TrieDB() 307 308 account, err := getAccount(triedb, header.Root, common.BytesToHash(request.AccKey)) 309 if err != nil { 310 p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err) 311 p.bumpInvalid() 312 continue 313 } 314 code, err := bc.StateCache().ContractCode(common.BytesToHash(request.AccKey), common.BytesToHash(account.CodeHash)) 315 if err != nil { 316 p.Log().Warn("Failed to retrieve account code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "codehash", common.BytesToHash(account.CodeHash), "err", err) 317 continue 318 } 319 // Accumulate the code and abort if enough data was retrieved 320 data = append(data, code) 321 if bytes += len(code); bytes >= softResponseLimit { 322 break 323 } 324 } 325 return p.replyCode(r.ReqID, data) 326 }, r.ReqID, uint64(len(r.Reqs)), nil 327 } 328 329 // handleGetReceipts handles a block receipts request 330 func handleGetReceipts(msg Decoder) (serveRequestFn, uint64, uint64, error) { 331 var r GetReceiptsPacket 332 if err := msg.Decode(&r); err != nil { 333 return nil, 0, 0, err 334 } 335 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 336 var ( 337 bytes int 338 receipts []rlp.RawValue 339 ) 340 bc := backend.BlockChain() 341 for i, hash := range r.Hashes { 342 if i != 0 && !waitOrStop() { 343 return nil 344 } 345 if bytes >= softResponseLimit { 346 break 347 } 348 // Retrieve the requested block's receipts, skipping if unknown to us 349 results := bc.GetReceiptsByHash(hash) 350 if results == nil { 351 if header := bc.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { 352 p.bumpInvalid() 353 continue 354 } 355 } 356 // If known, encode and queue for response packet 357 if encoded, err := rlp.EncodeToBytes(results); err != nil { 358 log.Error("Failed to encode receipt", "err", err) 359 } else { 360 receipts = append(receipts, encoded) 361 bytes += len(encoded) 362 } 363 } 364 return p.replyReceiptsRLP(r.ReqID, receipts) 365 }, r.ReqID, uint64(len(r.Hashes)), nil 366 } 367 368 // handleGetProofs handles a proof request 369 func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) { 370 var r GetProofsPacket 371 if err := msg.Decode(&r); err != nil { 372 return nil, 0, 0, err 373 } 374 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 375 var ( 376 lastBHash common.Hash 377 root common.Hash 378 header *types.Header 379 err error 380 ) 381 bc := backend.BlockChain() 382 nodes := light.NewNodeSet() 383 384 for i, request := range r.Reqs { 385 if i != 0 && !waitOrStop() { 386 return nil 387 } 388 // Look up the root hash belonging to the request 389 if request.BHash != lastBHash { 390 root, lastBHash = common.Hash{}, request.BHash 391 392 if header = bc.GetHeaderByHash(request.BHash); header == nil { 393 p.Log().Warn("Failed to retrieve header for proof", "hash", request.BHash) 394 p.bumpInvalid() 395 continue 396 } 397 // Refuse to search stale state data in the database since looking for 398 // a non-exist key is kind of expensive. 399 local := bc.CurrentHeader().Number.Uint64() 400 if !backend.ArchiveMode() && header.Number.Uint64()+core.TriesInMemory <= local { 401 p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local) 402 p.bumpInvalid() 403 continue 404 } 405 root = header.Root 406 } 407 // If a header lookup failed (non existent), ignore subsequent requests for the same header 408 if root == (common.Hash{}) { 409 p.bumpInvalid() 410 continue 411 } 412 // Open the account or storage trie for the request 413 statedb := bc.StateCache() 414 415 var trie state.Trie 416 switch len(request.AccKey) { 417 case 0: 418 // No account key specified, open an account trie 419 trie, err = statedb.OpenTrie(root) 420 if trie == nil || err != nil { 421 p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err) 422 continue 423 } 424 default: 425 // Account key specified, open a storage trie 426 account, err := getAccount(statedb.TrieDB(), root, common.BytesToHash(request.AccKey)) 427 if err != nil { 428 p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err) 429 p.bumpInvalid() 430 continue 431 } 432 trie, err = statedb.OpenStorageTrie(root, common.BytesToHash(request.AccKey), 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", common.BytesToHash(request.AccKey), "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, request.FromLevel, 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, request.FromLevel, 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 addFn := backend.TxPool().AddRemotes 522 // Add txs synchronously for testing purpose 523 if backend.AddTxsSync() { 524 addFn = backend.TxPool().AddRemotesSync 525 } 526 if errs := addFn([]*types.Transaction{tx}); errs[0] != nil { 527 stats[i].Error = errs[0].Error() 528 continue 529 } 530 stats[i] = txStatus(backend, hash) 531 } 532 } 533 return p.replyTxStatus(r.ReqID, stats) 534 }, r.ReqID, amount, nil 535 } 536 537 // handleGetTxStatus handles a transaction status query 538 func handleGetTxStatus(msg Decoder) (serveRequestFn, uint64, uint64, error) { 539 var r GetTxStatusPacket 540 if err := msg.Decode(&r); err != nil { 541 return nil, 0, 0, err 542 } 543 return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply { 544 stats := make([]light.TxStatus, len(r.Hashes)) 545 for i, hash := range r.Hashes { 546 if i != 0 && !waitOrStop() { 547 return nil 548 } 549 stats[i] = txStatus(backend, hash) 550 } 551 return p.replyTxStatus(r.ReqID, stats) 552 }, r.ReqID, uint64(len(r.Hashes)), nil 553 } 554 555 // txStatus returns the status of a specified transaction. 556 func txStatus(b serverBackend, hash common.Hash) light.TxStatus { 557 var stat light.TxStatus 558 // Looking the transaction in txpool first. 559 stat.Status = b.TxPool().Status([]common.Hash{hash})[0] 560 561 // If the transaction is unknown to the pool, try looking it up locally. 562 if stat.Status == txpool.TxStatusUnknown { 563 lookup := b.BlockChain().GetTransactionLookup(hash) 564 if lookup != nil { 565 stat.Status = txpool.TxStatusIncluded 566 stat.Lookup = lookup 567 } 568 } 569 return stat 570 }