Skip to content
5 changes: 5 additions & 0 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion beacon_chain/spec/mev/electra_mev.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
(
Expand Down
31 changes: 15 additions & 16 deletions beacon_chain/validators/beacon_validators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -618,17 +618,17 @@ 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:
let
response = awaitWithTimeout(
payloadBuilderClient.getHeader(
slot, executionBlockHash, pubkey),
BUILDER_PROPOSAL_DELAY_TOLERANCE):
builderTimeout):
return err "Timeout obtaining Electra blinded header from builder"

res = decodeBytesJsonOrSsz(
Expand All @@ -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(
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -995,9 +996,7 @@ 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

Expand Down
18 changes: 18 additions & 0 deletions docs/builder-proposal-delay-tolerance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Builder Proposal Delay Tolerance

You can now configure the builder proposal delay tolerance (MEV block builder timeout) via the following flag:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding now: By the time this would appear in the documentation, it will simply be the case.

It's true that some programming language documentation, or e.g., the curl docs, explicitly say some option appeared in $SOFTWARE version x.y.z. I'm not sure that's that useful here, since due to the hardfork mechanism, essentially no one is running a Nimbus version older than a year at any given time, and typically less.

The release notes do document this the appearance of such features, for people who need a timeline.

Similarly, whether or not this is combined with https://github.com/status-im/nimbus-eth2/blob/stable/docs/the_nimbus_book/src/external-block-builder.md it's worth ensuring both use consistent terminology.


```
--builder-proposal-delay-tolerance=<milliseconds>
```

- **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.

**Example usage:**

```
./nimbus_beacon_node --builder-proposal-delay-tolerance=2000
```

This option is useful for node operators who wish to tune performance for different environments or experiment with MEV builder timing.
Loading