go-ethereum/les/server_requests.go
Manav Darji ac353affa3
Merge master to qa (#813)
* 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 commit 241843c7e7.

* 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 commit 22fa4033e8.

* 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 commit 4561012af9.

* 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 commit 241843c7e7.

* 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 commit 22fa4033e8.

* 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>
2023-04-06 15:36:19 +05:30

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
}