2020-12-14 03:27:15 -06:00
|
|
|
// Copyright 2020 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 eth
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
2021-02-18 10:54:29 -06:00
|
|
|
"time"
|
2020-12-14 03:27:15 -06:00
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
core/types: support for optional blob sidecar in BlobTx (#27841)
This PR removes the newly added txpool.Transaction wrapper type, and instead adds a way
of keeping the blob sidecar within types.Transaction. It's better this way because most
code in go-ethereum does not care about blob transactions, and probably never will. This
will start mattering especially on the client side of RPC, where all APIs are based on
types.Transaction. Users need to be able to use the same signing flows they already
have.
However, since blobs are only allowed in some places but not others, we will now need to
add checks to avoid creating invalid blocks. I'm still trying to figure out the best place
to do some of these. The way I have it currently is as follows:
- In block validation (import), txs are verified not to have a blob sidecar.
- In miner, we strip off the sidecar when committing the transaction into the block.
- In TxPool validation, txs must have a sidecar to be added into the blobpool.
- Note there is a special case here: when transactions are re-added because of a chain
reorg, we cannot use the transactions gathered from the old chain blocks as-is,
because they will be missing their blobs. This was previously handled by storing the
blobs into the 'blobpool limbo'. The code has now changed to store the full
transaction in the limbo instead, but it might be confusing for code readers why we're
not simply adding the types.Transaction we already have.
Code changes summary:
- txpool.Transaction removed and all uses replaced by types.Transaction again
- blobpool now stores types.Transaction instead of defining its own blobTx format for storage
- the blobpool limbo now stores types.Transaction instead of storing only the blobs
- checks to validate the presence/absence of the blob sidecar added in certain critical places
2023-08-14 03:13:34 -05:00
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
2021-03-26 07:00:06 -05:00
|
|
|
"github.com/ethereum/go-ethereum/metrics"
|
2020-12-14 03:27:15 -06:00
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
|
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
|
|
|
"github.com/ethereum/go-ethereum/params"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// softResponseLimit is the target maximum size of replies to data retrievals.
|
|
|
|
softResponseLimit = 2 * 1024 * 1024
|
|
|
|
|
|
|
|
// maxHeadersServe is the maximum number of block headers to serve. This number
|
|
|
|
// is there to limit the number of disk lookups.
|
|
|
|
maxHeadersServe = 1024
|
|
|
|
|
|
|
|
// maxBodiesServe is the maximum number of block bodies to serve. This number
|
|
|
|
// is mostly there to limit the number of disk lookups. With 24KB block sizes
|
|
|
|
// nowadays, the practical limit will always be softResponseLimit.
|
|
|
|
maxBodiesServe = 1024
|
|
|
|
|
|
|
|
// maxReceiptsServe is the maximum number of block receipts to serve. This
|
|
|
|
// number is mostly there to limit the number of disk lookups. With block
|
|
|
|
// containing 200+ transactions nowadays, the practical limit will always
|
|
|
|
// be softResponseLimit.
|
|
|
|
maxReceiptsServe = 1024
|
|
|
|
)
|
|
|
|
|
|
|
|
// Handler is a callback to invoke from an outside runner after the boilerplate
|
|
|
|
// exchanges have passed.
|
|
|
|
type Handler func(peer *Peer) error
|
|
|
|
|
|
|
|
// Backend defines the data retrieval methods to serve remote requests and the
|
|
|
|
// callback methods to invoke on remote deliveries.
|
|
|
|
type Backend interface {
|
|
|
|
// Chain retrieves the blockchain object to serve data.
|
|
|
|
Chain() *core.BlockChain
|
|
|
|
|
|
|
|
// TxPool retrieves the transaction pool object to serve data.
|
|
|
|
TxPool() TxPool
|
|
|
|
|
|
|
|
// AcceptTxs retrieves whether transaction processing is enabled on the node
|
|
|
|
// or if inbound transactions should simply be dropped.
|
|
|
|
AcceptTxs() bool
|
|
|
|
|
|
|
|
// RunPeer is invoked when a peer joins on the `eth` protocol. The handler
|
|
|
|
// should do any peer maintenance work, handshakes and validations. If all
|
|
|
|
// is passed, control should be given back to the `handler` to process the
|
|
|
|
// inbound messages going forward.
|
|
|
|
RunPeer(peer *Peer, handler Handler) error
|
|
|
|
|
|
|
|
// PeerInfo retrieves all known `eth` information about a peer.
|
|
|
|
PeerInfo(id enode.ID) interface{}
|
|
|
|
|
|
|
|
// Handle is a callback to be invoked when a data packet is received from
|
|
|
|
// the remote peer. Only packets not consumed by the protocol handler will
|
|
|
|
// be forwarded to the backend.
|
|
|
|
Handle(peer *Peer, packet Packet) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// TxPool defines the methods needed by the protocol handler to serve transactions.
|
|
|
|
type TxPool interface {
|
2021-12-02 08:42:09 -06:00
|
|
|
// Get retrieves the transaction from the local txpool with the given hash.
|
core/types: support for optional blob sidecar in BlobTx (#27841)
This PR removes the newly added txpool.Transaction wrapper type, and instead adds a way
of keeping the blob sidecar within types.Transaction. It's better this way because most
code in go-ethereum does not care about blob transactions, and probably never will. This
will start mattering especially on the client side of RPC, where all APIs are based on
types.Transaction. Users need to be able to use the same signing flows they already
have.
However, since blobs are only allowed in some places but not others, we will now need to
add checks to avoid creating invalid blocks. I'm still trying to figure out the best place
to do some of these. The way I have it currently is as follows:
- In block validation (import), txs are verified not to have a blob sidecar.
- In miner, we strip off the sidecar when committing the transaction into the block.
- In TxPool validation, txs must have a sidecar to be added into the blobpool.
- Note there is a special case here: when transactions are re-added because of a chain
reorg, we cannot use the transactions gathered from the old chain blocks as-is,
because they will be missing their blobs. This was previously handled by storing the
blobs into the 'blobpool limbo'. The code has now changed to store the full
transaction in the limbo instead, but it might be confusing for code readers why we're
not simply adding the types.Transaction we already have.
Code changes summary:
- txpool.Transaction removed and all uses replaced by types.Transaction again
- blobpool now stores types.Transaction instead of defining its own blobTx format for storage
- the blobpool limbo now stores types.Transaction instead of storing only the blobs
- checks to validate the presence/absence of the blob sidecar added in certain critical places
2023-08-14 03:13:34 -05:00
|
|
|
Get(hash common.Hash) *types.Transaction
|
2020-12-14 03:27:15 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// MakeProtocols constructs the P2P protocol definitions for `eth`.
|
|
|
|
func MakeProtocols(backend Backend, network uint64, dnsdisc enode.Iterator) []p2p.Protocol {
|
2023-08-25 10:10:30 -05:00
|
|
|
protocols := make([]p2p.Protocol, 0, len(ProtocolVersions))
|
|
|
|
for _, version := range ProtocolVersions {
|
|
|
|
protocols = append(protocols, p2p.Protocol{
|
2021-02-02 02:44:36 -06:00
|
|
|
Name: ProtocolName,
|
2020-12-14 03:27:15 -06:00
|
|
|
Version: version,
|
|
|
|
Length: protocolLengths[version],
|
|
|
|
Run: func(p *p2p.Peer, rw p2p.MsgReadWriter) error {
|
|
|
|
peer := NewPeer(version, p, rw, backend.TxPool())
|
|
|
|
defer peer.Close()
|
|
|
|
|
|
|
|
return backend.RunPeer(peer, func(peer *Peer) error {
|
|
|
|
return Handle(backend, peer)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
NodeInfo: func() interface{} {
|
|
|
|
return nodeInfo(backend.Chain(), network)
|
|
|
|
},
|
|
|
|
PeerInfo: func(id enode.ID) interface{} {
|
|
|
|
return backend.PeerInfo(id)
|
|
|
|
},
|
2024-08-15 15:14:42 -05:00
|
|
|
Attributes: []enr.Entry{currentENREntry(backend.Chain())},
|
2023-08-25 10:10:30 -05:00
|
|
|
})
|
2020-12-14 03:27:15 -06:00
|
|
|
}
|
|
|
|
return protocols
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeInfo represents a short summary of the `eth` sub-protocol metadata
|
|
|
|
// known about the host peer.
|
|
|
|
type NodeInfo struct {
|
2024-08-20 08:59:48 -05:00
|
|
|
Network uint64 `json:"network"` // Ethereum network ID (1=Mainnet, Holesky=17000)
|
2020-12-14 03:27:15 -06:00
|
|
|
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
|
|
|
|
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
|
|
|
|
Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules
|
|
|
|
Head common.Hash `json:"head"` // Hex hash of the host's best owned block
|
|
|
|
}
|
|
|
|
|
|
|
|
// nodeInfo retrieves some `eth` protocol metadata about the running host node.
|
|
|
|
func nodeInfo(chain *core.BlockChain, network uint64) *NodeInfo {
|
|
|
|
head := chain.CurrentBlock()
|
2023-03-02 00:29:15 -06:00
|
|
|
hash := head.Hash()
|
|
|
|
|
2020-12-14 03:27:15 -06:00
|
|
|
return &NodeInfo{
|
|
|
|
Network: network,
|
2023-03-02 00:29:15 -06:00
|
|
|
Difficulty: chain.GetTd(hash, head.Number.Uint64()),
|
2020-12-14 03:27:15 -06:00
|
|
|
Genesis: chain.Genesis().Hash(),
|
|
|
|
Config: chain.Config(),
|
2023-03-02 00:29:15 -06:00
|
|
|
Head: hash,
|
2020-12-14 03:27:15 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle is invoked whenever an `eth` connection is made that successfully passes
|
|
|
|
// the protocol handshake. This method will keep processing messages until the
|
|
|
|
// connection is torn down.
|
|
|
|
func Handle(backend Backend, peer *Peer) error {
|
|
|
|
for {
|
|
|
|
if err := handleMessage(backend, peer); err != nil {
|
|
|
|
peer.Log().Debug("Message handling failed in `eth`", "err", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 10:54:29 -06:00
|
|
|
type msgHandler func(backend Backend, msg Decoder, peer *Peer) error
|
|
|
|
type Decoder interface {
|
|
|
|
Decode(val interface{}) error
|
|
|
|
Time() time.Time
|
|
|
|
}
|
|
|
|
|
2022-10-31 09:23:26 -05:00
|
|
|
var eth68 = map[uint64]msgHandler{
|
|
|
|
NewBlockHashesMsg: handleNewBlockhashes,
|
|
|
|
NewBlockMsg: handleNewBlock,
|
|
|
|
TransactionsMsg: handleTransactions,
|
2024-02-08 07:49:19 -06:00
|
|
|
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
|
2023-10-03 07:03:19 -05:00
|
|
|
GetBlockHeadersMsg: handleGetBlockHeaders,
|
|
|
|
BlockHeadersMsg: handleBlockHeaders,
|
|
|
|
GetBlockBodiesMsg: handleGetBlockBodies,
|
|
|
|
BlockBodiesMsg: handleBlockBodies,
|
|
|
|
GetReceiptsMsg: handleGetReceipts,
|
|
|
|
ReceiptsMsg: handleReceipts,
|
|
|
|
GetPooledTransactionsMsg: handleGetPooledTransactions,
|
|
|
|
PooledTransactionsMsg: handlePooledTransactions,
|
2022-06-15 05:56:47 -05:00
|
|
|
}
|
|
|
|
|
2020-12-14 03:27:15 -06:00
|
|
|
// handleMessage is invoked whenever an inbound message is received from a remote
|
|
|
|
// peer. The remote connection is torn down upon returning any error.
|
|
|
|
func handleMessage(backend Backend, peer *Peer) error {
|
|
|
|
// Read the next message from the remote peer, and ensure it's fully consumed
|
|
|
|
msg, err := peer.rw.ReadMsg()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if msg.Size > maxMessageSize {
|
|
|
|
return fmt.Errorf("%w: %v > %v", errMsgTooLarge, msg.Size, maxMessageSize)
|
|
|
|
}
|
|
|
|
defer msg.Discard()
|
|
|
|
|
2024-02-08 07:49:19 -06:00
|
|
|
var handlers = eth68
|
|
|
|
|
2021-04-22 03:42:46 -05:00
|
|
|
// Track the amount of time it takes to serve the request and run the handler
|
2021-03-26 07:00:06 -05:00
|
|
|
if metrics.Enabled {
|
|
|
|
h := fmt.Sprintf("%s/%s/%d/%#02x", p2p.HandleHistName, ProtocolName, peer.Version(), msg.Code)
|
|
|
|
defer func(start time.Time) {
|
2021-03-26 09:14:12 -05:00
|
|
|
sampler := func() metrics.Sample {
|
|
|
|
return metrics.ResettingSample(
|
|
|
|
metrics.NewExpDecaySample(1028, 0.015),
|
|
|
|
)
|
|
|
|
}
|
2021-03-26 07:00:06 -05:00
|
|
|
metrics.GetOrRegisterHistogramLazy(h, nil, sampler).Update(time.Since(start).Microseconds())
|
|
|
|
}(time.Now())
|
|
|
|
}
|
2021-02-18 10:54:29 -06:00
|
|
|
if handler := handlers[msg.Code]; handler != nil {
|
|
|
|
return handler(backend, msg, peer)
|
2020-12-14 03:27:15 -06:00
|
|
|
}
|
2021-02-18 10:54:29 -06:00
|
|
|
return fmt.Errorf("%w: %v", errInvalidMsgCode, msg.Code)
|
2020-12-14 03:27:15 -06:00
|
|
|
}
|