diff --git a/beacon_chain/conf.nim b/beacon_chain/conf.nim index e6810357b5..fd4ce37116 100644 --- a/beacon_chain/conf.nim +++ b/beacon_chain/conf.nim @@ -683,6 +683,11 @@ type defaultValue: 10 name: "local-block-value-boost" .}: uint8 + builderProposalDelayTolerance* {. + desc: "Timeout for builder proposal delay tolerance in milliseconds" + defaultValue: 1500 + name: "builder-proposal-delay-tolerance" .}: uint16 + historyMode* {. desc: "Retention strategy for historical data (archive/prune)" defaultValue: HistoryMode.Prune diff --git a/beacon_chain/spec/mev/electra_mev.nim b/beacon_chain/spec/mev/electra_mev.nim index 49f7a0f2fe..4587ede414 100644 --- a/beacon_chain/spec/mev/electra_mev.nim +++ b/beacon_chain/spec/mev/electra_mev.nim @@ -99,7 +99,6 @@ const # Spec is 1 second, but mev-boost indirection can induce delay when the relay # itself has already consumed the entire second. - BUILDER_PROPOSAL_DELAY_TOLERANCE* = 1500.milliseconds func shortLog*(v: BlindedBeaconBlock): auto = ( diff --git a/beacon_chain/validators/beacon_validators.nim b/beacon_chain/validators/beacon_validators.nim index d8025ec5ae..8be989ba14 100644 --- a/beacon_chain/validators/beacon_validators.nim +++ b/beacon_chain/validators/beacon_validators.nim @@ -618,9 +618,9 @@ proc makeBeaconBlockForHeadAndSlot*( proc getBlindedExecutionPayload[ EPH: electra_mev.BlindedExecutionPayloadAndBlobsBundle | fulu_mev.BlindedExecutionPayloadAndBlobsBundle]( - node: BeaconNode, payloadBuilderClient: RestClientRef, slot: Slot, - executionBlockHash: Eth2Digest, pubkey: ValidatorPubKey): - Future[BlindedBlockResult[EPH]] {.async: (raises: [CancelledError, RestError]).} = + node: BeaconNode, payloadBuilderClient: RestClientRef, slot: Slot, + executionBlockHash: Eth2Digest, pubkey: ValidatorPubKey, builderTimeout: Duration): + Future[BlindedBlockResult[EPH]] {.async: (raises: [CancelledError, RestError]).} = # Not ideal to use `when` where instead of splitting into separate functions, # but Nim doesn't overload on generic EPH type parameter. when EPH is electra_mev.BlindedExecutionPayloadAndBlobsBundle: @@ -628,7 +628,7 @@ proc getBlindedExecutionPayload[ response = awaitWithTimeout( payloadBuilderClient.getHeader( slot, executionBlockHash, pubkey), - BUILDER_PROPOSAL_DELAY_TOLERANCE): + builderTimeout): return err "Timeout obtaining Electra blinded header from builder" res = decodeBytesJsonOrSsz( @@ -646,7 +646,7 @@ proc getBlindedExecutionPayload[ response = awaitWithTimeout( payloadBuilderClient.getHeader( slot, executionBlockHash, pubkey), - BUILDER_PROPOSAL_DELAY_TOLERANCE): + builderTimeout): return err "Timeout obtaining Fulu blinded header from builder" res = decodeBytesJsonOrSsz( @@ -772,11 +772,11 @@ func getUnsignedBlindedBeaconBlock[ proc getBlindedBlockParts[ EPH: electra_mev.BlindedExecutionPayloadAndBlobsBundle | fulu_mev.BlindedExecutionPayloadAndBlobsBundle]( - node: BeaconNode, payloadBuilderClient: RestClientRef, head: BlockRef, - pubkey: ValidatorPubKey, slot: Slot, randao: ValidatorSig, - validator_index: ValidatorIndex, graffiti: GraffitiBytes): - Future[Result[(EPH, UInt256, UInt256, ForkedBeaconBlock, ExecutionRequests), string]] - {.async: (raises: [CancelledError]).} = + node: BeaconNode, payloadBuilderClient: RestClientRef, head: BlockRef, + pubkey: ValidatorPubKey, slot: Slot, randao: ValidatorSig, + validator_index: ValidatorIndex, graffiti: GraffitiBytes, builderTimeout: Duration): + Future[Result[(EPH, UInt256, UInt256, ForkedBeaconBlock, ExecutionRequests), string]] + {.async: (raises: [CancelledError]).} = let executionBlockHash = node.dag.loadExecutionBlockHash(head).valueOr: # With checkpoint sync, the checkpoint block may be unavailable, @@ -790,8 +790,8 @@ proc getBlindedBlockParts[ try: awaitWithTimeout( getBlindedExecutionPayload[EPH]( - node, payloadBuilderClient, slot, executionBlockHash, pubkey), - BUILDER_PROPOSAL_DELAY_TOLERANCE): + node, payloadBuilderClient, slot, executionBlockHash, pubkey, builderTimeout), + builderTimeout): BlindedBlockResult[EPH].err("getBlindedExecutionPayload timed out") except RestDecodingError as exc: BlindedBlockResult[EPH].err( @@ -886,9 +886,10 @@ proc getBuilderBid[ else: static: doAssert false + let builderTimeout = node.config.builderProposalDelayTolerance.milliseconds let blindedBlockParts = await getBlindedBlockParts[EPH]( node, payloadBuilderClient, head, validator_pubkey, slot, randao, - validator_index, graffitiBytes) + validator_index, graffitiBytes, builderTimeout) if blindedBlockParts.isErr: # Not signed yet, fine to try to fall back on EL beacon_block_builder_missed_with_fallback.inc() @@ -995,9 +996,6 @@ proc collectBids( engineBlockFut = makeBeaconBlockForHeadAndSlot( EPS, node, randao, validator_index, graffitiBytes, head, slot) - # getBuilderBid times out after BUILDER_PROPOSAL_DELAY_TOLERANCE, with 1 more - # second for remote validators. makeBeaconBlockForHeadAndSlot times out after - # 1 second. await allFutures(payloadBuilderBidFut, engineBlockFut) doAssert payloadBuilderBidFut.finished and engineBlockFut.finished diff --git a/docs/the_nimbus_book/src/external-block-builder.md b/docs/the_nimbus_book/src/external-block-builder.md index a48ef4695f..80b794d591 100644 --- a/docs/the_nimbus_book/src/external-block-builder.md +++ b/docs/the_nimbus_book/src/external-block-builder.md @@ -49,6 +49,17 @@ Additionally, the URL of the service exposing the [builder API](https://ethereum build/nimbus_validator_client \ --payload-builder=true ``` +### Builder Proposal Delay Tolerance + +You can configure the builder proposal delay tolerance (MEV block builder timeout) via the following flag: + +``` +--builder-proposal-delay-tolerance= +``` + +- **Default value:** 1500 (milliseconds) +- **Description:** Timeout for builder proposal delay tolerance. Increasing this value may allow the builder extra time to gather more transactions or MEV value, potentially improving block value and network efficiency. Lower values may reduce block proposal latency. + ## Useful resources