mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 07:37:20 +00:00
eth/catalyst: implement testing_buildBlockV1 (#33656)
implements https://github.com/ethereum/execution-apis/pull/710/changes#r2712256529 --------- Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
d3dd48e59d
commit
e40aa46e88
10 changed files with 270 additions and 14 deletions
|
|
@ -213,7 +213,7 @@ func encodeTransactions(txs []*types.Transaction) [][]byte {
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
func DecodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||||
var txs = make([]*types.Transaction, len(enc))
|
var txs = make([]*types.Transaction, len(enc))
|
||||||
for i, encTx := range enc {
|
for i, encTx := range enc {
|
||||||
var tx types.Transaction
|
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
|
// 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).
|
// 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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
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"
|
httpAPIs = "eth:1.0 net:1.0 rpc:1.0 web3:1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,9 +47,10 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Register adds the engine API to the full node.
|
// Register adds the engine API and related APIs to the full node.
|
||||||
func Register(stack *node.Node, backend *eth.Ethereum) error {
|
func Register(stack *node.Node, backend *eth.Ethereum) error {
|
||||||
stack.RegisterAPIs([]rpc.API{
|
stack.RegisterAPIs([]rpc.API{
|
||||||
|
newTestingAPI(backend),
|
||||||
{
|
{
|
||||||
Namespace: "engine",
|
Namespace: "engine",
|
||||||
Service: NewConsensusAPI(backend),
|
Service: NewConsensusAPI(backend),
|
||||||
|
|
|
||||||
79
eth/catalyst/api_testing.go
Normal file
79
eth/catalyst/api_testing.go
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright 2026 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 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/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// testingAPI implements the testing_ namespace.
|
||||||
|
// It's an engine-API adjacent namespace for testing purposes.
|
||||||
|
type testingAPI struct {
|
||||||
|
eth *eth.Ethereum
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestingAPI(backend *eth.Ethereum) rpc.API {
|
||||||
|
return rpc.API{
|
||||||
|
Namespace: "testing",
|
||||||
|
Service: &testingAPI{backend},
|
||||||
|
Version: "1.0",
|
||||||
|
Authenticated: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
// If transactions is empty but not nil, build an empty block
|
||||||
|
// If the transactions is nil, build a block with the current transactions from the txpool
|
||||||
|
// If the transactions is not nil and not empty, build a block with the transactions
|
||||||
|
buildEmpty := transactions != nil && len(*transactions) == 0
|
||||||
|
var txs []*types.Transaction
|
||||||
|
if transactions != nil {
|
||||||
|
dec := make([][]byte, 0, len(*transactions))
|
||||||
|
for _, tx := range *transactions {
|
||||||
|
dec = append(dec, tx)
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
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, buildEmpty, extra)
|
||||||
|
}
|
||||||
121
eth/catalyst/api_testing_test.go
Normal file
121
eth/catalyst/api_testing_test.go
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
// Copyright 2026 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 catalyst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"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/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBuildBlockV1(t *testing.T) {
|
||||||
|
genesis, blocks := generateMergeChain(5, true)
|
||||||
|
n, ethservice := startEthService(t, genesis, blocks)
|
||||||
|
defer n.Close()
|
||||||
|
|
||||||
|
parent := ethservice.BlockChain().CurrentBlock()
|
||||||
|
attrs := engine.PayloadAttributes{
|
||||||
|
Timestamp: parent.Time + 1,
|
||||||
|
Random: crypto.Keccak256Hash([]byte("test")),
|
||||||
|
SuggestedFeeRecipient: parent.Coinbase,
|
||||||
|
Withdrawals: nil,
|
||||||
|
BeaconRoot: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNonce, _ := ethservice.APIBackend.GetPoolNonce(context.Background(), testAddr)
|
||||||
|
tx, _ := types.SignTx(types.NewTransaction(currentNonce, testAddr, big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
|
||||||
|
|
||||||
|
api := &testingAPI{eth: ethservice}
|
||||||
|
|
||||||
|
t.Run("buildOnCurrentHead", func(t *testing.T) {
|
||||||
|
envelope, err := api.BuildBlockV1(parent.Hash(), attrs, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockV1 failed: %v", err)
|
||||||
|
}
|
||||||
|
if envelope == nil || envelope.ExecutionPayload == nil {
|
||||||
|
t.Fatal("expected non-nil envelope and payload")
|
||||||
|
}
|
||||||
|
payload := envelope.ExecutionPayload
|
||||||
|
if payload.ParentHash != parent.Hash() {
|
||||||
|
t.Errorf("parent hash mismatch: got %x want %x", payload.ParentHash, parent.Hash())
|
||||||
|
}
|
||||||
|
if payload.Number != parent.Number.Uint64()+1 {
|
||||||
|
t.Errorf("block number mismatch: got %d want %d", payload.Number, parent.Number.Uint64()+1)
|
||||||
|
}
|
||||||
|
if payload.Timestamp != attrs.Timestamp {
|
||||||
|
t.Errorf("timestamp mismatch: got %d want %d", payload.Timestamp, attrs.Timestamp)
|
||||||
|
}
|
||||||
|
if payload.FeeRecipient != attrs.SuggestedFeeRecipient {
|
||||||
|
t.Errorf("fee recipient mismatch: got %x want %x", payload.FeeRecipient, attrs.SuggestedFeeRecipient)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("wrongParentHash", func(t *testing.T) {
|
||||||
|
wrongParent := common.Hash{0x01}
|
||||||
|
_, err := api.BuildBlockV1(wrongParent, attrs, nil, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error when parentHash is not current head")
|
||||||
|
}
|
||||||
|
if err.Error() != "parentHash is not current head" {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("buildEmptyBlock", func(t *testing.T) {
|
||||||
|
emptyTxs := []hexutil.Bytes{}
|
||||||
|
envelope, err := api.BuildBlockV1(parent.Hash(), attrs, &emptyTxs, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockV1 with empty txs failed: %v", err)
|
||||||
|
}
|
||||||
|
if envelope == nil || envelope.ExecutionPayload == nil {
|
||||||
|
t.Fatal("expected non-nil envelope and payload")
|
||||||
|
}
|
||||||
|
if len(envelope.ExecutionPayload.Transactions) != 0 {
|
||||||
|
t.Errorf("expected empty block, got %d transactions", len(envelope.ExecutionPayload.Transactions))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("buildBlockWithTransactions", func(t *testing.T) {
|
||||||
|
enc, _ := tx.MarshalBinary()
|
||||||
|
txs := []hexutil.Bytes{enc}
|
||||||
|
envelope, err := api.BuildBlockV1(parent.Hash(), attrs, &txs, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockV1 with transaction failed: %v", err)
|
||||||
|
}
|
||||||
|
if len(envelope.ExecutionPayload.Transactions) != 1 {
|
||||||
|
t.Errorf("expected 1 transaction, got %d", len(envelope.ExecutionPayload.Transactions))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("buildBlockWithTransactionsFromTxPool", func(t *testing.T) {
|
||||||
|
ethservice.TxPool().Add([]*types.Transaction{tx}, true)
|
||||||
|
envelope, err := api.BuildBlockV1(parent.Hash(), attrs, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockV1 with transaction failed: %v", err)
|
||||||
|
}
|
||||||
|
if len(envelope.ExecutionPayload.Transactions) != 1 {
|
||||||
|
t.Errorf("expected 1 transaction, got %d", len(envelope.ExecutionPayload.Transactions))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -376,5 +376,6 @@ func RegisterSimulatedBeaconAPIs(stack *node.Node, sim *SimulatedBeacon) {
|
||||||
Service: api,
|
Service: api,
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
},
|
},
|
||||||
|
newTestingAPI(sim.eth),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"maps"
|
"maps"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
|
@ -88,8 +89,10 @@ func (al accessList) accessList() types.AccessList {
|
||||||
for slot := range slots {
|
for slot := range slots {
|
||||||
tuple.StorageKeys = append(tuple.StorageKeys, slot)
|
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
|
return acl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ package override
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
|
@ -58,9 +60,13 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi
|
||||||
if diff == nil {
|
if diff == nil {
|
||||||
return 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.
|
// Tracks destinations of precompiles that were moved.
|
||||||
dirtyAddrs := make(map[common.Address]struct{})
|
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 a precompile was moved to this address already, it can't be overridden.
|
||||||
if _, ok := dirtyAddrs[addr]; ok {
|
if _, ok := dirtyAddrs[addr]; ok {
|
||||||
return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
|
return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
|
||||||
|
|
|
||||||
|
|
@ -273,3 +273,26 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs, witness bool) (*Payload
|
||||||
}()
|
}()
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildTestingPayload is for testing_buildBlockV*. It creates a block with the exact content given
|
||||||
|
// by the parameters instead of using the locally available transactions.
|
||||||
|
func (miner *Miner) BuildTestingPayload(args *BuildPayloadArgs, transactions []*types.Transaction, empty bool, 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: empty,
|
||||||
|
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)
|
withdrawals types.Withdrawals // List of withdrawals to include in block (shanghai field)
|
||||||
beaconRoot *common.Hash // The beacon root (cancun field).
|
beaconRoot *common.Hash // The beacon root (cancun field).
|
||||||
noTxs bool // Flag whether an empty block without any transaction is expected
|
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.
|
// generateWork generates a sealing block based on the given parameters.
|
||||||
|
|
@ -132,6 +136,20 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
||||||
work.size += uint64(genParam.withdrawals.Size())
|
work.size += uint64(genParam.withdrawals.Size())
|
||||||
|
|
||||||
if !genParam.noTxs {
|
if !genParam.noTxs {
|
||||||
|
// If forceOverrides is true and overrideTxs is not empty, commit the override transactions
|
||||||
|
// otherwise, fill the block with the current transactions from the txpool
|
||||||
|
if genParam.forceOverrides && len(genParam.overrideTxs) > 0 {
|
||||||
|
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)
|
interrupt := new(atomic.Int32)
|
||||||
timer := time.AfterFunc(miner.config.Recommit, func() {
|
timer := time.AfterFunc(miner.config.Recommit, func() {
|
||||||
interrupt.Store(commitInterruptTimeout)
|
interrupt.Store(commitInterruptTimeout)
|
||||||
|
|
@ -143,6 +161,7 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay
|
||||||
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
log.Warn("Block building is interrupted", "allowance", common.PrettyDuration(miner.config.Recommit))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
body := types.Body{Transactions: work.txs, Withdrawals: genParam.withdrawals}
|
||||||
|
|
||||||
allLogs := make([]*types.Log, 0)
|
allLogs := make([]*types.Log, 0)
|
||||||
|
|
@ -224,6 +243,9 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir
|
||||||
if len(miner.config.ExtraData) != 0 {
|
if len(miner.config.ExtraData) != 0 {
|
||||||
header.Extra = miner.config.ExtraData
|
header.Extra = miner.config.ExtraData
|
||||||
}
|
}
|
||||||
|
if genParams.forceOverrides {
|
||||||
|
header.Extra = genParams.overrideExtraData
|
||||||
|
}
|
||||||
// Set the randomness field from the beacon chain if it's available.
|
// Set the randomness field from the beacon chain if it's available.
|
||||||
if genParams.random != (common.Hash{}) {
|
if genParams.random != (common.Hash{}) {
|
||||||
header.MixDigest = genParams.random
|
header.MixDigest = genParams.random
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue