diff --git a/builder/builder.go b/builder/builder.go index 64c9626e9b..e4642da0bd 100644 --- a/builder/builder.go +++ b/builder/builder.go @@ -63,6 +63,8 @@ type Builder struct { payloadMu sync.Mutex payload IPayload + extraData []byte + stop chan struct{} } @@ -75,6 +77,7 @@ type BuilderArgs struct { eth IEthereumService ignoreLatePayloadAttributes bool beaconClient IBeaconClient + extraData []byte } func NewBuilder(args BuilderArgs) (*Builder, error) { @@ -91,6 +94,8 @@ func NewBuilder(args BuilderArgs) (*Builder, error) { slotCtx: slotCtx, slotCtxCancel: slotCtxCancel, + extraData: args.extraData, + stop: make(chan struct{}, 1), }, nil } @@ -364,6 +369,8 @@ func (b *Builder) handlePayloadAttributes(attrs *builderTypes.PayloadAttributes) b.slotCtxCancel() } + attrs.ExtraData = b.extraData + slotCtx, slotCtxCancel := context.WithTimeout(context.Background(), b.builderBlockTime) b.slotAttrs = *attrs b.slotCtx = slotCtx diff --git a/builder/config.go b/builder/config.go index aef5ce663b..70ef4d042b 100644 --- a/builder/config.go +++ b/builder/config.go @@ -17,6 +17,7 @@ type Config struct { RetryInterval string `toml:",omitempty"` BlockTime time.Duration `toml:",omitempty"` ProposerAddress string `toml:",omitempty"` + ExtraData string `toml:",omitempty"` } // DefaultConfig is the default config for the builder. @@ -29,4 +30,5 @@ var DefaultConfig = Config{ BeaconEndpoints: []string{"http://127.0.0.1:5052"}, RetryInterval: RetryIntervalDefault.String(), BlockTime: BlockTimeDefault, + ExtraData: "", } diff --git a/builder/eth_service.go b/builder/eth_service.go index 953ccf367e..0e5e01e9bb 100644 --- a/builder/eth_service.go +++ b/builder/eth_service.go @@ -42,7 +42,8 @@ func (s *EthereumService) BuildBlock(attrs *builderTypes.PayloadAttributes) (IPa Transactions: attrs.Transactions, NoTxPool: attrs.NoTxPool, } - return s.eth.Miner().BuildPayload(args) + + return s.eth.Miner().BuildPayloadWithExtraData(args, attrs.ExtraData) } func (s *EthereumService) GetBlockByHash(hash common.Hash) *types.Block { diff --git a/builder/service.go b/builder/service.go index 527e611f40..8a03bc6515 100644 --- a/builder/service.go +++ b/builder/service.go @@ -100,6 +100,7 @@ func Register(stack *node.Node, backend *eth.Ethereum, cfg *Config) error { ignoreLatePayloadAttributes: cfg.IgnoreLatePayloadAttributes, beaconClient: beaconClient, blockTime: cfg.BlockTime, + extraData: []byte(cfg.ExtraData), } builderBackend, err := NewBuilder(builderArgs) diff --git a/builder/types/attributes.go b/builder/types/attributes.go index 54c12c2223..842f27772f 100644 --- a/builder/types/attributes.go +++ b/builder/types/attributes.go @@ -19,6 +19,8 @@ type PayloadAttributes struct { NoTxPool bool `json:"noTxPool,omitempty"` // Optimism addition: option to disable tx pool contents from being included Transactions []*types.Transaction `json:"transactions"` // Optimism addition: txs forced into the block via engine API + + ExtraData []byte `json:"extraData,omitempty"` // Flashbots addition: extra data to include in the block } func (attrs *PayloadAttributes) Equal(other *PayloadAttributes) bool { @@ -41,5 +43,9 @@ func (attrs *PayloadAttributes) Equal(other *PayloadAttributes) bool { return false } + if !slices.Equal(attrs.ExtraData, other.ExtraData) { + return false + } + return true } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index ce33b42b0a..f65454f302 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -184,6 +184,7 @@ var ( utils.BuilderBeaconEndpointsFlag, utils.BuilderBlockTimeFlag, utils.BuilderProposerSigningAddressFlag, + utils.BuilderExtraData, } rpcFlags = []cli.Flag{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d972b32c8f..86e5294c38 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -717,6 +717,12 @@ var ( EnvVars: []string{"BUILDER_PROPOSER_SIGNING_ADDRESS"}, Category: flags.BuilderCategory, } + BuilderExtraData = &cli.StringFlag{ + Name: "builder.extra_data", + Usage: "Extra data to include in the block", + EnvVars: []string{"BUILDER_EXTRA_DATA"}, + Category: flags.BuilderCategory, + } CustomChainFlag = &cli.StringFlag{ Name: "chain", @@ -1581,6 +1587,7 @@ func SetBuilderConfig(ctx *cli.Context, cfg *builder.Config) { cfg.BlockTime = ctx.Duration(BuilderBlockTimeFlag.Name) cfg.ProposerAddress = ctx.String(BuilderProposerSigningAddressFlag.Name) + cfg.ExtraData = ctx.String(BuilderExtraData.Name) } // SetNodeConfig applies node-related command line flags to the config. diff --git a/miner/miner.go b/miner/miner.go index ab551881bb..99b46ece7f 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -154,7 +154,12 @@ func (miner *Miner) SetGasTip(tip *big.Int) error { // BuildPayload builds the payload according to the provided parameters. func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) { - return miner.buildPayload(args) + return miner.buildPayload(args, nil) +} + +// BuildPayloadWithExtraData builds the payload according to the provided parameters and extra data. +func (miner *Miner) BuildPayloadWithExtraData(args *BuildPayloadArgs, extra []byte) (*Payload, error) { + return miner.buildPayload(args, extra) } // getPending retrieves the pending block based on the current head block. diff --git a/miner/payload_building.go b/miner/payload_building.go index b8bc0d5d4c..19563f3b7f 100644 --- a/miner/payload_building.go +++ b/miner/payload_building.go @@ -270,7 +270,7 @@ func (payload *Payload) stopBuilding() { } // buildPayload builds the payload according to the provided parameters. -func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { +func (miner *Miner) buildPayload(args *BuildPayloadArgs, extraData []byte) (*Payload, error) { if args.NoTxPool { // don't start the background payload updating job if there is no tx pool to pull from // Build the initial version with no transaction included. It should be fast // enough to run. The empty payload can at least make sure there is something @@ -287,6 +287,7 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { noTxs: true, txs: args.Transactions, gasLimit: args.GasLimit, + extraData: extraData, } empty := miner.generateWork(emptyParams) if empty.err != nil { @@ -311,6 +312,7 @@ func (miner *Miner) buildPayload(args *BuildPayloadArgs) (*Payload, error) { noTxs: false, txs: args.Transactions, gasLimit: args.GasLimit, + extraData: extraData, } // Since we skip building the empty block when using the tx pool, we need to explicitly diff --git a/miner/worker.go b/miner/worker.go index a408852273..8468269f7a 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -101,6 +101,8 @@ type generateParams struct { gasLimit *uint64 // Optional gas limit override interrupt *atomic.Int32 // Optional interruption signal to pass down to worker.generateWork isUpdate bool // Optional flag indicating that this is building a discardable update + + extraData []byte // Extra data to include in the block } // generateWork generates a sealing block based on the given parameters. @@ -197,9 +199,10 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) Time: timestamp, Coinbase: genParams.coinbase, } - // Set the extra field. - if len(miner.config.ExtraData) != 0 && miner.chainConfig.Optimism == nil { // Optimism chains must not set any extra data. - header.Extra = miner.config.ExtraData + // Set the extra field if specified. + if len(genParams.extraData) != 0 { + log.Debug("Setting extra data", "extraData", genParams.extraData) + header.Extra = genParams.extraData } // Set the randomness field from the beacon chain if it's available. if genParams.random != (common.Hash{}) {