mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
* Merge qa to master (#750) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * params, packaging/templates: update bor version --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * core, miner: add sub-spans for tracing (#753) * core, miner: add sub-spans for tracing * fix linters * core: add logs for debugging * core: add more logs to print tdd while reorg * fix linters * core: minor fix * core: remove debug logs * core: use different span for write block and set head * core: use internal context for sending traces (#755) * core: add : impossible reorg block dump (#754) * add : impossible reorg block dump * chg : 3 seperate files for impossoble reorg dump * add : use exportBlocks method and RLP blocks before writing * chg : small changes * bump : go version from 1.19 to 1.20.1 (#761) * Revert "bump : go version from 1.19 to 1.20.1 (#761)" This reverts commit4561012af9. * core/vm: use optimized bigint (#26021) * Add holiman/big * Fix linter * Bump version to v0.3.5 * fix lints from develop (few lints decided to appear from code that was untouched, weird) * upgrade crypto lib version (#770) * bump dep : github.com/Masterminds/goutils to v1.1.1 (#769) * mardizzone/pos-1313: bump crypto dependency (#772) * dev: chg: bumd net dependency * dev: chg: bump crypto dependency * dev: chg: bump crypto dependency * bump dep : golang.org/x/net to v0.8.0 (#771) * Verify validator set against local contract on receiving an end-of-sprint block (#768) * Verify validator set against local contract on receiving an end-of-sprint block * Fix tests * Respect error returned by ParseValidators * Keep going back until a parent block presents * core/txpool: implement DoS defenses from geth (#778) * Hotfixes and deps bump (#776) * dev: chg: bump deps * internal/cli/server, rpc: lower down http readtimeout to 10s * dev: chg: get p2p adapter * dev: chg: lower down jsonrpc readtimeout to 10s * cherry-pick txpool optimisation changes * add check for empty lists in txpool (#704) * add check * linters * core, miner: add empty instrumentation name for tracing --------- Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danilenko <6655321@bk.ru> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * packaging,params: bump to v0.3.6 (#782) * v0.3.6 fix (#787) * Fix get validator set in header verifier * chg : commit tx logs from info to debug (#673) * chg : commit tx logs from info to debug * fix : minor changes * chg : miner : commitTransactions-stats moved from info to debug * lint : fix linters * refactor logging * miner : chg : UnauthorizedSignerError to debug * lint : fix lint * fix : log.Logger interface compatibility --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Remove unnecessary sorting of valset from header in verification * dev: chg: version bump --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> * core: improve locks in txpool (#807) * added a write lock to the txs.filter method and a read lock to the txs.reheap method - both of which are called by Filter during reorg adjustments to txpool * txpool reorg locks * more locks * locks * linters * params, packaging: update version for v0.3.8-beta release * core: add logs in reheap --------- Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Merge qa to master (#808) * Added checks to RPC requests and introduced new flags to customise the parameters (#657) * added a check to reject rpc requests with batch size > the one set using a newly added flag (rpcbatchlimit) * added a check to reject rpc requests whose result size > the one set using a newly added flag (rpcreturndatalimit) * updated the config files and docs * chg : trieTimeout from 60 to 10 mins (#692) * chg : trieTimeout from 60 to 10 mins * chg : cache.timout to 10m from 1h in configs * internal/cli/server : fix : added triesInMemory in config (#691) * changed version from 0.3.0 to 0.3.4-beta (#693) * fix nil state-sync issue, increase grpc limit (#695) * Increase grpc message size limit in pprof * consensus/bor/bor.go : stateSyncs init fixed [Fix #686] * eth/filters: handle nil state-sync before notify * eth/filters: update check Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> * core, tests/bor: add more tests for state-sync validation (#710) * core: add get state sync function for tests * tests/bor: add validation for state sync events post consensus * Arpit/temp bor sync (#701) * Increase grpc message size limit in pprof * ReadBorReceipts improvements * use internal function * fix tests * fetch geth upstread for ReadBorReceiptRLP * Only query bor receipt when the query index is equal to # tx in block body This change reduces the frequency of calling ReadBorReceipt and ReadBorTransaction, which are CPU and db intensive. * Revert "fetch geth upstread for ReadBorReceiptRLP" This reverts commit 2e838a6b1313d26674f3a8df4b044e35dcbf35a0. * Restore ReadBorReceiptRLP * fix bor receipts * remove unused * fix lints --------- Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> * Revert "chg : trieTimeout from 60 to 10 mins (#692)" (#720) This reverts commit241843c7e7. * Arpit/add execution pool 2 (#719) * initial * linters * linters * remove timeout * update pool * change pool size function * check nil * check nil * fix tests * Use execution pool from server in all handlers * simplify things * test fix * add support for cli, config * add to cli and config * merge base branch * debug statements * fix bug * atomic pointer timeout * add apis * update workerpool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * fix tests * mutex * refactor flag and value names * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * debug statements * fix bug * update workerpool * atomic pointer timeout * add apis * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * fix issues * change params * fix issues * fix ipc issue * remove execution pool from IPC * revert * merge base branch * Merge branch 'add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * mutex * fix tests * Merge branch 'arpit/add-execution-pool' of github.com:maticnetwork/bor into arpit/add-execution-pool * Change default size of execution pool to 40 * refactor flag and value names * fix merge conflicts * ordering fix * refactor flag and value names * update default ep size to 40 * fix bor start issues * revert file changes * fix linters * fix go.mod * change sec to ms * change default value for ep timeout * fix node api calls * comment setter for ep timeout --------- Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Manav Darji <manavdarji.india@gmail.com> * version change (#721) * Event based pprof (#732) * feature * Save pprof to /tmp --------- Co-authored-by: Jerry <jerrycgh@gmail.com> * Cherry-pick changes from develop (#738) * Check if block is nil to prevent panic (#736) * miner: use env for tracing instead of block object (#728) --------- Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * add max code init size check in txpool (#739) * Revert "Event based pprof" and update version (#742) * Revert "Event based pprof (#732)" This reverts commit22fa4033e8. * params: update version to 0.3.4-beta3 * packaging/templates: update bor version * internal/ethapi :: Fix : newRPCTransactionFromBlockIndex * fix: remove assignment for bor receipt --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> * Setting up bor to use hosted 18.04 runner as ubuntu provided 18.04 runner is end of life --------- Co-authored-by: SHIVAM SHARMA <shivam691999@gmail.com> Co-authored-by: Pratik Patil <pratikspatil024@gmail.com> Co-authored-by: Jerry <jerrycgh@gmail.com> Co-authored-by: Daniil <daniil.melnik@chainstack.com> Co-authored-by: Arpit Temani <temaniarpit27@gmail.com> Co-authored-by: Evgeny Danienko <6655321@bk.ru> Co-authored-by: Dmitry <46797839+dkeysil@users.noreply.github.com> Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: marcello33 <marcelloardizzone@hotmail.it> Co-authored-by: Raneet Debnath <raneetdebnath10@gmail.com> Co-authored-by: Raneet Debnath <35629432+Raneet10@users.noreply.github.com> Co-authored-by: Alex <dalexwatts@gmail.com> Co-authored-by: Daniel Jones <djones@polygon.technology>
583 lines
20 KiB
Go
583 lines
20 KiB
Go
// Copyright 2021 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package les
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/core"
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
"github.com/ethereum/go-ethereum/light"
|
|
"github.com/ethereum/go-ethereum/log"
|
|
"github.com/ethereum/go-ethereum/metrics"
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
"github.com/ethereum/go-ethereum/trie"
|
|
)
|
|
|
|
// serverBackend defines the backend functions needed for serving LES requests
|
|
type serverBackend interface {
|
|
ArchiveMode() bool
|
|
AddTxsSync() bool
|
|
BlockChain() *core.BlockChain
|
|
TxPool() *core.TxPool
|
|
GetHelperTrie(typ uint, index uint64) *trie.Trie
|
|
}
|
|
|
|
// Decoder is implemented by the messages passed to the handler functions
|
|
type Decoder interface {
|
|
Decode(val interface{}) error
|
|
}
|
|
|
|
// RequestType is a static struct that describes an LES request type and references
|
|
// its handler function.
|
|
type RequestType struct {
|
|
Name string
|
|
MaxCount uint64
|
|
InPacketsMeter, InTrafficMeter, OutPacketsMeter, OutTrafficMeter metrics.Meter
|
|
ServingTimeMeter metrics.Timer
|
|
Handle func(msg Decoder) (serve serveRequestFn, reqID, amount uint64, err error)
|
|
}
|
|
|
|
// serveRequestFn is returned by the request handler functions after decoding the request.
|
|
// This function does the actual request serving using the supplied backend. waitOrStop is
|
|
// called between serving individual request items and may block if the serving process
|
|
// needs to be throttled. If it returns false then the process is terminated.
|
|
// The reply is not sent by this function yet. The flow control feedback value is supplied
|
|
// by the protocol handler when calling the send function of the returned reply struct.
|
|
type serveRequestFn func(backend serverBackend, peer *clientPeer, waitOrStop func() bool) *reply
|
|
|
|
// Les3 contains the request types supported by les/2 and les/3
|
|
var Les3 = map[uint64]RequestType{
|
|
GetBlockHeadersMsg: {
|
|
Name: "block header request",
|
|
MaxCount: MaxHeaderFetch,
|
|
InPacketsMeter: miscInHeaderPacketsMeter,
|
|
InTrafficMeter: miscInHeaderTrafficMeter,
|
|
OutPacketsMeter: miscOutHeaderPacketsMeter,
|
|
OutTrafficMeter: miscOutHeaderTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeHeaderTimer,
|
|
Handle: handleGetBlockHeaders,
|
|
},
|
|
GetBlockBodiesMsg: {
|
|
Name: "block bodies request",
|
|
MaxCount: MaxBodyFetch,
|
|
InPacketsMeter: miscInBodyPacketsMeter,
|
|
InTrafficMeter: miscInBodyTrafficMeter,
|
|
OutPacketsMeter: miscOutBodyPacketsMeter,
|
|
OutTrafficMeter: miscOutBodyTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeBodyTimer,
|
|
Handle: handleGetBlockBodies,
|
|
},
|
|
GetCodeMsg: {
|
|
Name: "code request",
|
|
MaxCount: MaxCodeFetch,
|
|
InPacketsMeter: miscInCodePacketsMeter,
|
|
InTrafficMeter: miscInCodeTrafficMeter,
|
|
OutPacketsMeter: miscOutCodePacketsMeter,
|
|
OutTrafficMeter: miscOutCodeTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeCodeTimer,
|
|
Handle: handleGetCode,
|
|
},
|
|
GetReceiptsMsg: {
|
|
Name: "receipts request",
|
|
MaxCount: MaxReceiptFetch,
|
|
InPacketsMeter: miscInReceiptPacketsMeter,
|
|
InTrafficMeter: miscInReceiptTrafficMeter,
|
|
OutPacketsMeter: miscOutReceiptPacketsMeter,
|
|
OutTrafficMeter: miscOutReceiptTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeReceiptTimer,
|
|
Handle: handleGetReceipts,
|
|
},
|
|
GetProofsV2Msg: {
|
|
Name: "les/2 proofs request",
|
|
MaxCount: MaxProofsFetch,
|
|
InPacketsMeter: miscInTrieProofPacketsMeter,
|
|
InTrafficMeter: miscInTrieProofTrafficMeter,
|
|
OutPacketsMeter: miscOutTrieProofPacketsMeter,
|
|
OutTrafficMeter: miscOutTrieProofTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeTrieProofTimer,
|
|
Handle: handleGetProofs,
|
|
},
|
|
GetHelperTrieProofsMsg: {
|
|
Name: "helper trie proof request",
|
|
MaxCount: MaxHelperTrieProofsFetch,
|
|
InPacketsMeter: miscInHelperTriePacketsMeter,
|
|
InTrafficMeter: miscInHelperTrieTrafficMeter,
|
|
OutPacketsMeter: miscOutHelperTriePacketsMeter,
|
|
OutTrafficMeter: miscOutHelperTrieTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeHelperTrieTimer,
|
|
Handle: handleGetHelperTrieProofs,
|
|
},
|
|
SendTxV2Msg: {
|
|
Name: "new transactions",
|
|
MaxCount: MaxTxSend,
|
|
InPacketsMeter: miscInTxsPacketsMeter,
|
|
InTrafficMeter: miscInTxsTrafficMeter,
|
|
OutPacketsMeter: miscOutTxsPacketsMeter,
|
|
OutTrafficMeter: miscOutTxsTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeTxTimer,
|
|
Handle: handleSendTx,
|
|
},
|
|
GetTxStatusMsg: {
|
|
Name: "transaction status query request",
|
|
MaxCount: MaxTxStatus,
|
|
InPacketsMeter: miscInTxStatusPacketsMeter,
|
|
InTrafficMeter: miscInTxStatusTrafficMeter,
|
|
OutPacketsMeter: miscOutTxStatusPacketsMeter,
|
|
OutTrafficMeter: miscOutTxStatusTrafficMeter,
|
|
ServingTimeMeter: miscServingTimeTxStatusTimer,
|
|
Handle: handleGetTxStatus,
|
|
},
|
|
}
|
|
|
|
// handleGetBlockHeaders handles a block header request
|
|
func handleGetBlockHeaders(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetBlockHeadersPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
// Gather headers until the fetch or network limits is reached
|
|
var (
|
|
bc = backend.BlockChain()
|
|
hashMode = r.Query.Origin.Hash != (common.Hash{})
|
|
first = true
|
|
maxNonCanonical = uint64(100)
|
|
bytes common.StorageSize
|
|
headers []*types.Header
|
|
unknown bool
|
|
)
|
|
for !unknown && len(headers) < int(r.Query.Amount) && bytes < softResponseLimit {
|
|
if !first && !waitOrStop() {
|
|
return nil
|
|
}
|
|
// Retrieve the next header satisfying the r
|
|
var origin *types.Header
|
|
if hashMode {
|
|
if first {
|
|
origin = bc.GetHeaderByHash(r.Query.Origin.Hash)
|
|
if origin != nil {
|
|
r.Query.Origin.Number = origin.Number.Uint64()
|
|
}
|
|
} else {
|
|
origin = bc.GetHeader(r.Query.Origin.Hash, r.Query.Origin.Number)
|
|
}
|
|
} else {
|
|
origin = bc.GetHeaderByNumber(r.Query.Origin.Number)
|
|
}
|
|
if origin == nil {
|
|
break
|
|
}
|
|
headers = append(headers, origin)
|
|
bytes += estHeaderRlpSize
|
|
|
|
// Advance to the next header of the r
|
|
switch {
|
|
case hashMode && r.Query.Reverse:
|
|
// Hash based traversal towards the genesis block
|
|
ancestor := r.Query.Skip + 1
|
|
if ancestor == 0 {
|
|
unknown = true
|
|
} else {
|
|
r.Query.Origin.Hash, r.Query.Origin.Number = bc.GetAncestor(r.Query.Origin.Hash, r.Query.Origin.Number, ancestor, &maxNonCanonical)
|
|
unknown = r.Query.Origin.Hash == common.Hash{}
|
|
}
|
|
case hashMode && !r.Query.Reverse:
|
|
// Hash based traversal towards the leaf block
|
|
var (
|
|
current = origin.Number.Uint64()
|
|
next = current + r.Query.Skip + 1
|
|
)
|
|
if next <= current {
|
|
infos, _ := json.Marshal(p.Peer.Info())
|
|
p.Log().Warn("GetBlockHeaders skip overflow attack", "current", current, "skip", r.Query.Skip, "next", next, "attacker", string(infos))
|
|
unknown = true
|
|
} else {
|
|
if header := bc.GetHeaderByNumber(next); header != nil {
|
|
nextHash := header.Hash()
|
|
expOldHash, _ := bc.GetAncestor(nextHash, next, r.Query.Skip+1, &maxNonCanonical)
|
|
if expOldHash == r.Query.Origin.Hash {
|
|
r.Query.Origin.Hash, r.Query.Origin.Number = nextHash, next
|
|
} else {
|
|
unknown = true
|
|
}
|
|
} else {
|
|
unknown = true
|
|
}
|
|
}
|
|
case r.Query.Reverse:
|
|
// Number based traversal towards the genesis block
|
|
if r.Query.Origin.Number >= r.Query.Skip+1 {
|
|
r.Query.Origin.Number -= r.Query.Skip + 1
|
|
} else {
|
|
unknown = true
|
|
}
|
|
|
|
case !r.Query.Reverse:
|
|
// Number based traversal towards the leaf block
|
|
r.Query.Origin.Number += r.Query.Skip + 1
|
|
}
|
|
first = false
|
|
}
|
|
return p.replyBlockHeaders(r.ReqID, headers)
|
|
}, r.ReqID, r.Query.Amount, nil
|
|
}
|
|
|
|
// handleGetBlockBodies handles a block body request
|
|
func handleGetBlockBodies(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetBlockBodiesPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
var (
|
|
bytes int
|
|
bodies []rlp.RawValue
|
|
)
|
|
bc := backend.BlockChain()
|
|
for i, hash := range r.Hashes {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
if bytes >= softResponseLimit {
|
|
break
|
|
}
|
|
body := bc.GetBodyRLP(hash)
|
|
if body == nil {
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
bodies = append(bodies, body)
|
|
bytes += len(body)
|
|
}
|
|
return p.replyBlockBodiesRLP(r.ReqID, bodies)
|
|
}, r.ReqID, uint64(len(r.Hashes)), nil
|
|
}
|
|
|
|
// handleGetCode handles a contract code request
|
|
func handleGetCode(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetCodePacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
var (
|
|
bytes int
|
|
data [][]byte
|
|
)
|
|
bc := backend.BlockChain()
|
|
for i, request := range r.Reqs {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
// Look up the root hash belonging to the request
|
|
header := bc.GetHeaderByHash(request.BHash)
|
|
if header == nil {
|
|
p.Log().Warn("Failed to retrieve associate header for code", "hash", request.BHash)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
// Refuse to search stale state data in the database since looking for
|
|
// a non-exist key is kind of expensive.
|
|
local := bc.CurrentHeader().Number.Uint64()
|
|
if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local {
|
|
p.Log().Debug("Reject stale code request", "number", header.Number.Uint64(), "head", local)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
triedb := bc.StateCache().TrieDB()
|
|
|
|
account, err := getAccount(triedb, header.Root, common.BytesToHash(request.AccKey))
|
|
if err != nil {
|
|
p.Log().Warn("Failed to retrieve account for code", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
code, err := bc.StateCache().ContractCode(common.BytesToHash(request.AccKey), common.BytesToHash(account.CodeHash))
|
|
if err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
// Accumulate the code and abort if enough data was retrieved
|
|
data = append(data, code)
|
|
if bytes += len(code); bytes >= softResponseLimit {
|
|
break
|
|
}
|
|
}
|
|
return p.replyCode(r.ReqID, data)
|
|
}, r.ReqID, uint64(len(r.Reqs)), nil
|
|
}
|
|
|
|
// handleGetReceipts handles a block receipts request
|
|
func handleGetReceipts(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetReceiptsPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
var (
|
|
bytes int
|
|
receipts []rlp.RawValue
|
|
)
|
|
bc := backend.BlockChain()
|
|
for i, hash := range r.Hashes {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
if bytes >= softResponseLimit {
|
|
break
|
|
}
|
|
// Retrieve the requested block's receipts, skipping if unknown to us
|
|
results := bc.GetReceiptsByHash(hash)
|
|
if results == nil {
|
|
if header := bc.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
}
|
|
// If known, encode and queue for response packet
|
|
if encoded, err := rlp.EncodeToBytes(results); err != nil {
|
|
log.Error("Failed to encode receipt", "err", err)
|
|
} else {
|
|
receipts = append(receipts, encoded)
|
|
bytes += len(encoded)
|
|
}
|
|
}
|
|
return p.replyReceiptsRLP(r.ReqID, receipts)
|
|
}, r.ReqID, uint64(len(r.Hashes)), nil
|
|
}
|
|
|
|
// handleGetProofs handles a proof request
|
|
func handleGetProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetProofsPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
var (
|
|
lastBHash common.Hash
|
|
root common.Hash
|
|
header *types.Header
|
|
err error
|
|
)
|
|
bc := backend.BlockChain()
|
|
nodes := light.NewNodeSet()
|
|
|
|
for i, request := range r.Reqs {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
// Look up the root hash belonging to the request
|
|
if request.BHash != lastBHash {
|
|
root, lastBHash = common.Hash{}, request.BHash
|
|
|
|
if header = bc.GetHeaderByHash(request.BHash); header == nil {
|
|
p.Log().Warn("Failed to retrieve header for proof", "hash", request.BHash)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
// Refuse to search stale state data in the database since looking for
|
|
// a non-exist key is kind of expensive.
|
|
local := bc.CurrentHeader().Number.Uint64()
|
|
if !backend.ArchiveMode() && header.Number.Uint64()+core.DefaultCacheConfig.TriesInMemory <= local {
|
|
p.Log().Debug("Reject stale trie request", "number", header.Number.Uint64(), "head", local)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
root = header.Root
|
|
}
|
|
// If a header lookup failed (non existent), ignore subsequent requests for the same header
|
|
if root == (common.Hash{}) {
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
// Open the account or storage trie for the request
|
|
statedb := bc.StateCache()
|
|
|
|
var trie state.Trie
|
|
switch len(request.AccKey) {
|
|
case 0:
|
|
// No account key specified, open an account trie
|
|
trie, err = statedb.OpenTrie(root)
|
|
if trie == nil || err != nil {
|
|
p.Log().Warn("Failed to open storage trie for proof", "block", header.Number, "hash", header.Hash(), "root", root, "err", err)
|
|
continue
|
|
}
|
|
default:
|
|
// Account key specified, open a storage trie
|
|
account, err := getAccount(statedb.TrieDB(), root, common.BytesToHash(request.AccKey))
|
|
if err != nil {
|
|
p.Log().Warn("Failed to retrieve account for proof", "block", header.Number, "hash", header.Hash(), "account", common.BytesToHash(request.AccKey), "err", err)
|
|
p.bumpInvalid()
|
|
continue
|
|
}
|
|
trie, err = statedb.OpenStorageTrie(common.BytesToHash(request.AccKey), account.Root)
|
|
if trie == nil || err != nil {
|
|
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)
|
|
continue
|
|
}
|
|
}
|
|
// Prove the user's request from the account or stroage trie
|
|
if err := trie.Prove(request.Key, request.FromLevel, nodes); err != nil {
|
|
p.Log().Warn("Failed to prove state request", "block", header.Number, "hash", header.Hash(), "err", err)
|
|
continue
|
|
}
|
|
if nodes.DataSize() >= softResponseLimit {
|
|
break
|
|
}
|
|
}
|
|
return p.replyProofsV2(r.ReqID, nodes.NodeList())
|
|
}, r.ReqID, uint64(len(r.Reqs)), nil
|
|
}
|
|
|
|
// handleGetHelperTrieProofs handles a helper trie proof request
|
|
func handleGetHelperTrieProofs(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetHelperTrieProofsPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
var (
|
|
lastIdx uint64
|
|
lastType uint
|
|
auxTrie *trie.Trie
|
|
auxBytes int
|
|
auxData [][]byte
|
|
)
|
|
bc := backend.BlockChain()
|
|
nodes := light.NewNodeSet()
|
|
for i, request := range r.Reqs {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
if auxTrie == nil || request.Type != lastType || request.TrieIdx != lastIdx {
|
|
lastType, lastIdx = request.Type, request.TrieIdx
|
|
auxTrie = backend.GetHelperTrie(request.Type, request.TrieIdx)
|
|
}
|
|
if auxTrie == nil {
|
|
return nil
|
|
}
|
|
// TODO(rjl493456442) short circuit if the proving is failed.
|
|
// The original client side code has a dirty hack to retrieve
|
|
// the headers with no valid proof. Keep the compatibility for
|
|
// legacy les protocol and drop this hack when the les2/3 are
|
|
// not supported.
|
|
err := auxTrie.Prove(request.Key, request.FromLevel, nodes)
|
|
if p.version >= lpv4 && err != nil {
|
|
return nil
|
|
}
|
|
if request.Type == htCanonical && request.AuxReq == htAuxHeader && len(request.Key) == 8 {
|
|
header := bc.GetHeaderByNumber(binary.BigEndian.Uint64(request.Key))
|
|
data, err := rlp.EncodeToBytes(header)
|
|
if err != nil {
|
|
log.Error("Failed to encode header", "err", err)
|
|
return nil
|
|
}
|
|
auxData = append(auxData, data)
|
|
auxBytes += len(data)
|
|
}
|
|
if nodes.DataSize()+auxBytes >= softResponseLimit {
|
|
break
|
|
}
|
|
}
|
|
return p.replyHelperTrieProofs(r.ReqID, HelperTrieResps{Proofs: nodes.NodeList(), AuxData: auxData})
|
|
}, r.ReqID, uint64(len(r.Reqs)), nil
|
|
}
|
|
|
|
// handleSendTx handles a transaction propagation request
|
|
func handleSendTx(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r SendTxPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
|
|
amount := uint64(len(r.Txs))
|
|
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
stats := make([]light.TxStatus, len(r.Txs))
|
|
|
|
var (
|
|
err error
|
|
addFn func(transaction *types.Transaction) error
|
|
)
|
|
|
|
for i, tx := range r.Txs {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
|
|
hash := tx.Hash()
|
|
stats[i] = txStatus(backend, hash)
|
|
|
|
if stats[i].Status == core.TxStatusUnknown {
|
|
addFn = backend.TxPool().AddRemote
|
|
|
|
// Add txs synchronously for testing purpose
|
|
if backend.AddTxsSync() {
|
|
addFn = backend.TxPool().AddRemoteSync
|
|
}
|
|
|
|
if err = addFn(tx); err != nil {
|
|
stats[i].Error = err.Error()
|
|
|
|
continue
|
|
}
|
|
|
|
stats[i] = txStatus(backend, hash)
|
|
}
|
|
}
|
|
return p.replyTxStatus(r.ReqID, stats)
|
|
}, r.ReqID, amount, nil
|
|
}
|
|
|
|
// handleGetTxStatus handles a transaction status query
|
|
func handleGetTxStatus(msg Decoder) (serveRequestFn, uint64, uint64, error) {
|
|
var r GetTxStatusPacket
|
|
if err := msg.Decode(&r); err != nil {
|
|
return nil, 0, 0, err
|
|
}
|
|
return func(backend serverBackend, p *clientPeer, waitOrStop func() bool) *reply {
|
|
stats := make([]light.TxStatus, len(r.Hashes))
|
|
for i, hash := range r.Hashes {
|
|
if i != 0 && !waitOrStop() {
|
|
return nil
|
|
}
|
|
stats[i] = txStatus(backend, hash)
|
|
}
|
|
return p.replyTxStatus(r.ReqID, stats)
|
|
}, r.ReqID, uint64(len(r.Hashes)), nil
|
|
}
|
|
|
|
// txStatus returns the status of a specified transaction.
|
|
func txStatus(b serverBackend, hash common.Hash) light.TxStatus {
|
|
var stat light.TxStatus
|
|
// Looking the transaction in txpool first.
|
|
stat.Status = b.TxPool().Status([]common.Hash{hash})[0]
|
|
|
|
// If the transaction is unknown to the pool, try looking it up locally.
|
|
if stat.Status == core.TxStatusUnknown {
|
|
lookup := b.BlockChain().GetTransactionLookup(hash)
|
|
if lookup != nil {
|
|
stat.Status = core.TxStatusIncluded
|
|
stat.Lookup = lookup
|
|
}
|
|
}
|
|
return stat
|
|
}
|