diff --git a/packages/beacon-node/src/chain/errors/executionPayloadBid.ts b/packages/beacon-node/src/chain/errors/executionPayloadBid.ts index b3d090eb95d0..6d5e41e0bf31 100644 --- a/packages/beacon-node/src/chain/errors/executionPayloadBid.ts +++ b/packages/beacon-node/src/chain/errors/executionPayloadBid.ts @@ -12,6 +12,7 @@ export enum ExecutionPayloadBidErrorCode { UNKNOWN_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_PARENT_BLOCK_HASH", INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT", NOT_LATER_THAN_PARENT = "EXECUTION_PAYLOAD_BID_ERROR_NOT_LATER_THAN_PARENT", + INVALID_PREV_RANDAO = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_PREV_RANDAO", INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE", NO_MATCHING_PROPOSER_PREFERENCES = "EXECUTION_PAYLOAD_BID_ERROR_NO_MATCHING_PROPOSER_PREFERENCES", PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH", @@ -43,6 +44,12 @@ export type ExecutionPayloadBidErrorType = | {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex} | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot} | {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot} + | { + code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO; + builderIndex: BuilderIndex; + bidPrevRandao: string; + expectedPrevRandao: string; + } | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot} | { code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES; diff --git a/packages/beacon-node/src/chain/validation/executionPayloadBid.ts b/packages/beacon-node/src/chain/validation/executionPayloadBid.ts index 6e062a13d653..47228d6faf2f 100644 --- a/packages/beacon-node/src/chain/validation/executionPayloadBid.ts +++ b/packages/beacon-node/src/chain/validation/executionPayloadBid.ts @@ -232,6 +232,18 @@ async function validateExecutionPayloadBid( }); } + // [REJECT] `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that + // `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`. + const randaoMix = state.getRandaoMix(computeEpochAtSlot(state.slot)); + if (!byteArrayEquals(bid.prevRandao, randaoMix)) { + throw new ExecutionPayloadBidError(GossipAction.REJECT, { + code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO, + builderIndex: bid.builderIndex, + bidPrevRandao: toHex(bid.prevRandao), + expectedPrevRandao: toHex(randaoMix), + }); + } + // [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`. const signatureSet = createSingleSignatureSetFromComponents( PublicKey.fromBytes(builder.pubkey),