mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
eth/catalyst: implement testing_buildPayloadV1
This commit is contained in:
parent
add1890a57
commit
348f1d78ac
8 changed files with 125 additions and 13 deletions
|
|
@ -213,7 +213,7 @@ func encodeTransactions(txs []*types.Transaction) [][]byte {
|
|||
return enc
|
||||
}
|
||||
|
||||
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||
func DecodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||
var txs = make([]*types.Transaction, len(enc))
|
||||
for i, encTx := range enc {
|
||||
var tx types.Transaction
|
||||
|
|
@ -251,7 +251,7 @@ func ExecutableDataToBlock(data ExecutableData, versionedHashes []common.Hash, b
|
|||
// for stateless execution, so it skips checking if the executable data hashes to
|
||||
// the requested hash (stateless has to *compute* the root hash, it's not given).
|
||||
func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte) (*types.Block, error) {
|
||||
txs, err := decodeTransactions(data.Transactions)
|
||||
txs, err := DecodeTransactions(data.Transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ func makeFullNode(ctx *cli.Context) *node.Node {
|
|||
}
|
||||
utils.RegisterSyncOverrideService(stack, eth, synctarget, ctx.Bool(utils.ExitWhenSyncedFlag.Name))
|
||||
|
||||
catalyst.RegisterTestingAPI(stack, eth)
|
||||
|
||||
if ctx.IsSet(utils.DeveloperFlag.Name) {
|
||||
// Start dev mode.
|
||||
simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), cfg.Eth.Miner.PendingFeeRecipient, eth)
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0"
|
||||
ipcAPIs = "admin:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 testing:1.0 txpool:1.0 web3:1.0"
|
||||
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||
)
|
||||
|
||||
|
|
|
|||
60
eth/catalyst/api_testing.go
Normal file
60
eth/catalyst/api_testing.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
package catalyst
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
"github.com/ethereum/go-ethereum/miner"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
type TestingAPI struct {
|
||||
eth *eth.Ethereum
|
||||
}
|
||||
|
||||
func NewTestingAPI(eth *eth.Ethereum) *TestingAPI {
|
||||
return &TestingAPI{
|
||||
eth: eth,
|
||||
}
|
||||
}
|
||||
|
||||
func RegisterTestingAPI(stack *node.Node, backend *eth.Ethereum) error {
|
||||
stack.RegisterAPIs([]rpc.API{{
|
||||
Namespace: "testing",
|
||||
Service: NewTestingAPI(backend),
|
||||
Authenticated: false,
|
||||
},
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *TestingAPI) BuildBlockV1(parentHash common.Hash, payloadAttributes engine.PayloadAttributes, transactions []hexutil.Bytes, extraData *hexutil.Bytes) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
if api.eth.BlockChain().CurrentBlock().Hash() != parentHash {
|
||||
return nil, errors.New("parentHash is not current head")
|
||||
}
|
||||
dec := make([][]byte, 0, len(transactions))
|
||||
for _, tx := range transactions {
|
||||
dec = append(dec, tx)
|
||||
}
|
||||
txs, err := engine.DecodeTransactions(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extra := make([]byte, 0)
|
||||
if extraData != nil {
|
||||
extra = *extraData
|
||||
}
|
||||
args := &miner.BuildPayloadArgs{
|
||||
Parent: parentHash,
|
||||
Timestamp: payloadAttributes.Timestamp,
|
||||
FeeRecipient: payloadAttributes.SuggestedFeeRecipient,
|
||||
Random: payloadAttributes.Random,
|
||||
Withdrawals: payloadAttributes.Withdrawals,
|
||||
BeaconRoot: payloadAttributes.BeaconRoot,
|
||||
}
|
||||
return api.eth.Miner().BuildTestingPayload(args, txs, extra)
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@ package logger
|
|||
|
||||
import (
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
|
|
@ -88,8 +89,10 @@ func (al accessList) accessList() types.AccessList {
|
|||
for slot := range slots {
|
||||
tuple.StorageKeys = append(tuple.StorageKeys, slot)
|
||||
}
|
||||
acl = append(acl, tuple)
|
||||
keys := slices.SortedFunc(maps.Keys(slots), common.Hash.Cmp)
|
||||
acl = append(acl, types.AccessTuple{Address: addr, StorageKeys: keys})
|
||||
}
|
||||
slices.SortFunc(acl, func(a, b types.AccessTuple) int { return a.Address.Cmp(b.Address) })
|
||||
return acl
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ package override
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math/big"
|
||||
"slices"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
|
@ -58,9 +60,13 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi
|
|||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
// Iterate in deterministic order so error messages and behavior are stable (e.g. for tests).
|
||||
addrs := slices.SortedFunc(maps.Keys(*diff), common.Address.Cmp)
|
||||
|
||||
// Tracks destinations of precompiles that were moved.
|
||||
dirtyAddrs := make(map[common.Address]struct{})
|
||||
for addr, account := range *diff {
|
||||
for _, addr := range addrs {
|
||||
account := (*diff)[addr]
|
||||
// If a precompile was moved to this address already, it can't be overridden.
|
||||
if _, ok := dirtyAddrs[addr]; ok {
|
||||
return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
|
||||
|
|
|
|||
|
|
@ -273,3 +273,24 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
|||
}()
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*types.Transaction, extraData []byte) (*engine.ExecutionPayloadEnvelope, error) {
|
||||
fullParams := &generateParams{
|
||||
timestamp: args.Timestamp,
|
||||
forceTime: true,
|
||||
parentHash: args.Parent,
|
||||
coinbase: args.FeeRecipient,
|
||||
random: args.Random,
|
||||
withdrawals: args.Withdrawals,
|
||||
beaconRoot: args.BeaconRoot,
|
||||
noTxs: false,
|
||||
forceOverrides: true,
|
||||
overrideExtraData: extraData,
|
||||
overrideTxs: transactions,
|
||||
}
|
||||
res := miner.generateWork(fullParams, false)
|
||||
if res.err != nil {
|
||||
return nil, res.err
|
||||
}
|
||||
return engine.BlockToExecutableData(res.block, new(big.Int), res.sidecars, res.requests), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ type generateParams struct {
|
|||
withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
|
||||
beaconRoot *common.Hash // The beacon root (cancun field).
|
||||
noTxs bool // Flag whether an empty block without any transaction is expected
|
||||
|
||||
forceOverrides bool // Flag whether we should overwrite extraData and transactions
|
||||
overrideExtraData []byte
|
||||
overrideTxs []*types.Transaction
|
||||
}
|
||||
|
||||
// generateWork generates a sealing block based on the given parameters.
|
||||
|
|
@ -132,6 +136,18 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
work.size += uint64(genParam.withdrawals.Size())
|
||||
|
||||
if !genParam.noTxs {
|
||||
if genParam.forceOverrides {
|
||||
if work.gasPool == nil {
|
||||
work.gasPool = new(core.GasPool).AddGas(work.header.GasLimit)
|
||||
}
|
||||
for _, tx := range genParam.overrideTxs {
|
||||
work.state.SetTxContext(tx.Hash(), work.tcount)
|
||||
if err := miner.commitTransaction(work, tx); err != nil {
|
||||
// all passed transactions HAVE to be valid at this point
|
||||
return &newPayloadResult{err: err}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
interrupt := new(atomic.Int32)
|
||||
timer := time.AfterFunc(miner.config.Recommit, func() {
|
||||
interrupt.Store(commitInterruptTimeout)
|
||||
|
|
@ -143,6 +159,7 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
|||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||
}
|
||||
}
|
||||
}
|
||||
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
||||
|
||||
allLogs := make([]*types.Log, 0)
|
||||
|
|
@ -224,6 +241,9 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
|||
if len(miner.config.ExtraData) != 0 {
|
||||
header.Extra = miner.config.ExtraData
|
||||
}
|
||||
if genParams.forceOverrides {
|
||||
header.Extra = genParams.overrideExtraData
|
||||
}
|
||||
// Set the randomness field from the beacon chain if it's available.
|
||||
if genParams.random != (common.Hash{}) {
|
||||
header.MixDigest = genParams.random
|
||||
|
|
|
|||
Loading…
Reference in a new issue