From 59351d25b2174aaa6f538b5b216aae65e3862869 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 6 Jun 2022 15:43:12 +1000 Subject: [PATCH] Make block production async (make lint passing) --- beacon_node/beacon_chain/src/beacon_chain.rs | 327 +++++++++++++----- beacon_node/beacon_chain/src/errors.rs | 3 + .../beacon_chain/src/execution_payload.rs | 5 +- beacon_node/beacon_chain/src/test_utils.rs | 16 +- beacon_node/http_api/src/lib.rs | 161 ++++----- .../src/per_block_processing/tests.rs | 22 +- consensus/types/src/payload.rs | 2 + testing/state_transition_vectors/src/exit.rs | 7 +- 8 files changed, 362 insertions(+), 181 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 9fd7a51a9fd..13bfb5e5d98 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -18,7 +18,7 @@ use crate::early_attester_cache::EarlyAttesterCache; use crate::errors::{BeaconChainError as Error, BlockProductionError}; use crate::eth1_chain::{Eth1Chain, Eth1ChainBackend}; use crate::events::ServerSentEventHandler; -use crate::execution_payload::get_execution_payload; +use crate::execution_payload::{get_execution_payload, PreparePayloadHandle}; use crate::fork_choice_signal::{ForkChoiceSignalRx, ForkChoiceSignalTx, ForkChoiceWaitResult}; use crate::head_tracker::HeadTracker; use crate::historical_blocks::HistoricalBlockError; @@ -243,6 +243,24 @@ pub enum HeadSafetyStatus { Invalid(ExecutionBlockHash), } +/// Used internally to split block production into discreet functions. +struct PartialBeaconBlock { + state: BeaconState, + slot: Slot, + proposer_index: u64, + parent_root: Hash256, + randao_reveal: Signature, + eth1_data: Eth1Data, + graffiti: Graffiti, + proposer_slashings: Vec, + attester_slashings: Vec>, + attestations: Vec>, + deposits: Vec, + voluntary_exits: Vec, + sync_aggregate: Option>, + prepare_payload_handle: Option>, +} + pub type BeaconForkChoice = ForkChoice< BeaconForkChoiceStore< ::EthSpec, @@ -3054,7 +3072,7 @@ impl BeaconChain { /// /// The produced block will not be inherently valid, it must be signed by a block producer. /// Block signing is out of the scope of this function and should be done by a separate program. - pub fn produce_block>( + pub async fn produce_block>( self: &Arc, randao_reveal: Signature, slot: Slot, @@ -3066,16 +3084,50 @@ impl BeaconChain { validator_graffiti, ProduceBlockVerification::VerifyRandao, ) + .await } /// Same as `produce_block` but allowing for configuration of RANDAO-verification. - pub fn produce_block_with_verification>( + pub async fn produce_block_with_verification>( self: &Arc, randao_reveal: Signature, slot: Slot, validator_graffiti: Option, verification: ProduceBlockVerification, ) -> Result, BlockProductionError> { + // Part 1/2 (blocking) + // + // Load the parent state from disk. + let chain = self.clone(); + let (state, state_root_opt) = self + .task_executor + .spawn_blocking_handle( + move || chain.load_state_for_block_production::(slot), + "produce_partial_beacon_block", + ) + .ok_or(BlockProductionError::ShuttingDown)? + .await + .map_err(BlockProductionError::TokioJoin)??; + + // Part 2/2 (async, with some blocking components) + // + // Produce the blopck upon the state + self.produce_block_on_state::( + state, + state_root_opt, + slot, + randao_reveal, + validator_graffiti, + verification, + ) + .await + } + + /// Same as `produce_block` but allowing for configuration of RANDAO-verification. + fn load_state_for_block_production>( + self: &Arc, + slot: Slot, + ) -> Result<(BeaconState, Option), BlockProductionError> { metrics::inc_counter(&metrics::BLOCK_PRODUCTION_REQUESTS); let _complete_timer = metrics::start_timer(&metrics::BLOCK_PRODUCTION_TIMES); @@ -3131,16 +3183,10 @@ impl BeaconChain { (state, None) }; + drop(state_load_timer); - self.produce_block_on_state::( - state, - state_root_opt, - slot, - randao_reveal, - validator_graffiti, - verification, - ) + Ok((state, state_root_opt)) } /// Produce a block for some `slot` upon the given `state`. @@ -3155,15 +3201,79 @@ impl BeaconChain { /// The provided `state_root_opt` should only ever be set to `Some` if the contained value is /// equal to the root of `state`. Providing this value will serve as an optimization to avoid /// performing a tree hash in some scenarios. - pub fn produce_block_on_state>( - &self, - mut state: BeaconState, + pub async fn produce_block_on_state>( + self: &Arc, + state: BeaconState, state_root_opt: Option, produce_at_slot: Slot, randao_reveal: Signature, validator_graffiti: Option, verification: ProduceBlockVerification, ) -> Result, BlockProductionError> { + // Part 1/3 (blocking) + // + // Perform the state advance and block-packing functions. + let chain = self.clone(); + let mut partial_beacon_block = self + .task_executor + .spawn_blocking_handle( + move || { + chain.produce_partial_beacon_block( + state, + state_root_opt, + produce_at_slot, + randao_reveal, + validator_graffiti, + ) + }, + "produce_partial_beacon_block", + ) + .ok_or(BlockProductionError::ShuttingDown)? + .await + .map_err(BlockProductionError::TokioJoin)??; + + // Part 2/3 (async) + // + // Wait for the execution layer to return an execution payload (if one is required). + let prepare_payload_handle = partial_beacon_block.prepare_payload_handle.take(); + let execution_payload = if let Some(prepare_payload_handle) = prepare_payload_handle { + let execution_payload = prepare_payload_handle + .await + .map_err(BlockProductionError::TokioJoin)? + .ok_or(BlockProductionError::ShuttingDown)??; + Some(execution_payload) + } else { + None + }; + + // Part 3/3 (blocking) + // + // Perform the final steps of combining all the parts and computing the state root. + let chain = self.clone(); + self.task_executor + .spawn_blocking_handle( + move || { + chain.complete_partial_beacon_block( + partial_beacon_block, + execution_payload, + verification, + ) + }, + "produce_partial_beacon_block", + ) + .ok_or(BlockProductionError::ShuttingDown)? + .await + .map_err(BlockProductionError::TokioJoin)? + } + + fn produce_partial_beacon_block>( + self: &Arc, + mut state: BeaconState, + state_root_opt: Option, + produce_at_slot: Slot, + randao_reveal: Signature, + validator_graffiti: Option, + ) -> Result, BlockProductionError> { let eth1_chain = self .eth1_chain .as_ref() @@ -3194,13 +3304,31 @@ impl BeaconChain { state.latest_block_header().canonical_root() }; + let slot = state.slot(); + let proposer_index = state.get_beacon_proposer_index(state.slot(), &self.spec)? as u64; + + // If required, start the process of loading an execution payload from the EL early. This + // allows it to run concurrently with things like attestation packing. + let prepare_payload_handle = match &state { + BeaconState::Base(_) | BeaconState::Altair(_) => None, + BeaconState::Merge(_) => { + // TODO(paul): should this be from fork choice instead? + let finalized_checkpoint = state.finalized_checkpoint(); + let prepare_payload_handle = get_execution_payload( + self.clone(), + &state, + finalized_checkpoint, + proposer_index, + )?; + Some(prepare_payload_handle) + } + }; + let (proposer_slashings, attester_slashings, voluntary_exits) = self.op_pool.get_slashings_and_exits(&state, &self.spec); let eth1_data = eth1_chain.eth1_data_for_block_production(&state, &self.spec)?; - let deposits = eth1_chain - .deposits_for_block_inclusion(&state, ð1_data, &self.spec)? - .into(); + let deposits = eth1_chain.deposits_for_block_inclusion(&state, ð1_data, &self.spec)?; // Iterate through the naive aggregation pool and ensure all the attestations from there // are included in the operation pool. @@ -3249,29 +3377,69 @@ impl BeaconChain { curr_attestation_filter, &self.spec, ) - .map_err(BlockProductionError::OpPoolError)? - .into(); + .map_err(BlockProductionError::OpPoolError)?; drop(attestation_packing_timer); - let slot = state.slot(); - let proposer_index = state.get_beacon_proposer_index(state.slot(), &self.spec)? as u64; - - // Closure to fetch a sync aggregate in cases where it is required. - let get_sync_aggregate = || -> Result, BlockProductionError> { - Ok(self - .op_pool - .get_sync_aggregate(&state) - .map_err(BlockProductionError::OpPoolError)? - .unwrap_or_else(|| { - warn!( - self.log, - "Producing block with no sync contributions"; - "slot" => state.slot(), - ); - SyncAggregate::new() - })) + let sync_aggregate = match &state { + BeaconState::Base(_) => None, + BeaconState::Altair(_) | BeaconState::Merge(_) => { + let sync_aggregate = self + .op_pool + .get_sync_aggregate(&state) + .map_err(BlockProductionError::OpPoolError)? + .unwrap_or_else(|| { + warn!( + self.log, + "Producing block with no sync contributions"; + "slot" => state.slot(), + ); + SyncAggregate::new() + }); + Some(sync_aggregate) + } }; + Ok(PartialBeaconBlock { + state, + slot, + proposer_index, + parent_root, + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + prepare_payload_handle, + }) + } + + fn complete_partial_beacon_block>( + &self, + partial_beacon_block: PartialBeaconBlock, + execution_payload: Option, + verification: ProduceBlockVerification, + ) -> Result, BlockProductionError> { + let PartialBeaconBlock { + mut state, + slot, + proposer_index, + parent_root, + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + prepare_payload_handle: _, + } = partial_beacon_block; + let inner_block = match &state { BeaconState::Base(_) => BeaconBlock::Base(BeaconBlockBase { slot, @@ -3284,56 +3452,51 @@ impl BeaconChain { graffiti, proposer_slashings: proposer_slashings.into(), attester_slashings: attester_slashings.into(), - attestations, - deposits, + attestations: attestations.into(), + deposits: deposits.into(), voluntary_exits: voluntary_exits.into(), _phantom: PhantomData, }, }), - BeaconState::Altair(_) => { - let sync_aggregate = get_sync_aggregate()?; - BeaconBlock::Altair(BeaconBlockAltair { - slot, - proposer_index, - parent_root, - state_root: Hash256::zero(), - body: BeaconBlockBodyAltair { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings: proposer_slashings.into(), - attester_slashings: attester_slashings.into(), - attestations, - deposits, - voluntary_exits: voluntary_exits.into(), - sync_aggregate, - _phantom: PhantomData, - }, - }) - } - BeaconState::Merge(_) => { - let sync_aggregate = get_sync_aggregate()?; - let execution_payload = - get_execution_payload::(self, &state, proposer_index).await?; - BeaconBlock::Merge(BeaconBlockMerge { - slot, - proposer_index, - parent_root, - state_root: Hash256::zero(), - body: BeaconBlockBodyMerge { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings: proposer_slashings.into(), - attester_slashings: attester_slashings.into(), - attestations, - deposits, - voluntary_exits: voluntary_exits.into(), - sync_aggregate, - execution_payload, - }, - }) - } + BeaconState::Altair(_) => BeaconBlock::Altair(BeaconBlockAltair { + slot, + proposer_index, + parent_root, + state_root: Hash256::zero(), + body: BeaconBlockBodyAltair { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings: proposer_slashings.into(), + attester_slashings: attester_slashings.into(), + attestations: attestations.into(), + deposits: deposits.into(), + voluntary_exits: voluntary_exits.into(), + sync_aggregate: sync_aggregate + .ok_or(BlockProductionError::MissingSyncAggregate)?, + _phantom: PhantomData, + }, + }), + BeaconState::Merge(_) => BeaconBlock::Merge(BeaconBlockMerge { + slot, + proposer_index, + parent_root, + state_root: Hash256::zero(), + body: BeaconBlockBodyMerge { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings: proposer_slashings.into(), + attester_slashings: attester_slashings.into(), + attestations: attestations.into(), + deposits: deposits.into(), + voluntary_exits: voluntary_exits.into(), + sync_aggregate: sync_aggregate + .ok_or(BlockProductionError::MissingSyncAggregate)?, + execution_payload: execution_payload + .ok_or(BlockProductionError::MissingExecutionPayload)?, + }, + }), }; let block = SignedBeaconBlock::from_block( diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index 23833d6d767..dbbc02f2783 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -248,6 +248,9 @@ pub enum BlockProductionError { BlockTooLarge(usize), ForkChoiceError(BeaconChainError), ShuttingDown, + MissingSyncAggregate, + MissingExecutionPayload, + TokioJoin(tokio::task::JoinError), } easy_from_to!(BlockProcessingError, BlockProductionError); diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index c1ff8b0f69b..bc0c83eac39 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -24,8 +24,8 @@ use std::sync::Arc; use tokio::task::JoinHandle; use types::*; -type PreparePayloadResult = Result; -type PreparePayloadHandle = JoinHandle>>; +pub type PreparePayloadResult = Result; +pub type PreparePayloadHandle = JoinHandle>>; /// Used to await the result of executing payload with a remote EE. pub struct PayloadNotifier { @@ -342,6 +342,7 @@ pub fn get_execution_payload< /// Equivalent to the `prepare_execution_payload` function in the Validator Guide: /// /// https://github.com/ethereum/consensus-specs/blob/v1.1.5/specs/merge/validator.md#block-proposal +#[allow(clippy::too_many_arguments)] pub async fn prepare_execution_payload( chain: &BeaconChain, current_epoch: Epoch, diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index b12270f1aa2..8d60895de13 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -580,7 +580,7 @@ where state.get_block_root(slot).unwrap() == state.get_block_root(slot - 1).unwrap() } - pub fn make_block( + pub async fn make_block( &self, mut state: BeaconState, slot: Slot, @@ -614,6 +614,7 @@ where Some(graffiti), ProduceBlockVerification::VerifyRandao, ) + .await .unwrap(); let signed_block = block.sign( @@ -628,7 +629,7 @@ where /// Useful for the `per_block_processing` tests. Creates a block, and returns the state after /// caches are built but before the generated block is processed. - pub fn make_block_return_pre_state( + pub async fn make_block_return_pre_state( &self, mut state: BeaconState, slot: Slot, @@ -664,6 +665,7 @@ where Some(graffiti), ProduceBlockVerification::VerifyRandao, ) + .await .unwrap(); let signed_block = block.sign( @@ -1250,7 +1252,7 @@ where /// Create a new block, apply `block_modifier` to it, sign it and return it. /// /// The state returned is a pre-block state at the same slot as the produced block. - pub fn make_block_with_modifier( + pub async fn make_block_with_modifier( &self, state: BeaconState, slot: Slot, @@ -1259,7 +1261,7 @@ where assert_ne!(slot, 0, "can't produce a block at slot 0"); assert!(slot >= state.slot()); - let (block, state) = self.make_block_return_pre_state(state, slot); + let (block, state) = self.make_block_return_pre_state(state, slot).await; let (mut block, _) = block.deconstruct(); block_modifier(&mut block); @@ -1426,7 +1428,7 @@ where state: BeaconState, ) -> Result<(SignedBeaconBlockHash, SignedBeaconBlock, BeaconState), BlockError> { self.set_current_slot(slot); - let (block, new_state) = self.make_block(state, slot); + let (block, new_state) = self.make_block(state, slot).await; let block_hash = self.process_block(slot, block.clone()).await?; Ok((block_hash, block, new_state)) } @@ -1616,13 +1618,13 @@ where /// Deprecated: Use make_block() instead /// /// Returns a newly created block, signed by the proposer for the given slot. - pub fn build_block( + pub async fn build_block( &self, state: BeaconState, slot: Slot, _block_strategy: BlockStrategy, ) -> (SignedBeaconBlock, BeaconState) { - self.make_block(state, slot) + self.make_block(state, slot).await } /// Uses `Self::extend_chain` to build the chain out to the `target_slot`. diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 30d62317919..2799518b968 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -1942,48 +1942,49 @@ pub fn serve( |endpoint_version: EndpointVersion, slot: Slot, query: api_types::ValidatorBlocksQuery, - chain: Arc>| { - blocking_json_task(move || { - let randao_reveal = query.randao_reveal.as_ref().map_or_else( - || { - if query.verify_randao { - Err(warp_utils::reject::custom_bad_request( - "randao_reveal is mandatory unless verify_randao=false".into(), - )) - } else { - Ok(Signature::empty()) - } - }, - |sig_bytes| { - sig_bytes.try_into().map_err(|e| { - warp_utils::reject::custom_bad_request(format!( - "randao reveal is not a valid BLS signature: {:?}", - e - )) - }) - }, - )?; + chain: Arc>| async move { + let randao_reveal = query.randao_reveal.as_ref().map_or_else( + || { + if query.verify_randao { + Err(warp_utils::reject::custom_bad_request( + "randao_reveal is mandatory unless verify_randao=false".into(), + )) + } else { + Ok(Signature::empty()) + } + }, + |sig_bytes| { + sig_bytes.try_into().map_err(|e| { + warp_utils::reject::custom_bad_request(format!( + "randao reveal is not a valid BLS signature: {:?}", + e + )) + }) + }, + )?; - let randao_verification = if query.verify_randao { - ProduceBlockVerification::VerifyRandao - } else { - ProduceBlockVerification::NoVerification - }; + let randao_verification = if query.verify_randao { + ProduceBlockVerification::VerifyRandao + } else { + ProduceBlockVerification::NoVerification + }; - let (block, _) = chain - .produce_block_with_verification::>( - randao_reveal, - slot, - query.graffiti.map(Into::into), - randao_verification, - ) - .map_err(warp_utils::reject::block_production_error)?; - let fork_name = block - .to_ref() - .fork_name(&chain.spec) - .map_err(inconsistent_fork_rejection)?; - fork_versioned_response(endpoint_version, fork_name, block) - }) + let (block, _) = chain + .produce_block_with_verification::>( + randao_reveal, + slot, + query.graffiti.map(Into::into), + randao_verification, + ) + .await + .map_err(warp_utils::reject::block_production_error)?; + let fork_name = block + .to_ref() + .fork_name(&chain.spec) + .map_err(inconsistent_fork_rejection)?; + + fork_versioned_response(endpoint_version, fork_name, block) + .map(|response| warp::reply::json(&response)) }, ); @@ -2004,48 +2005,48 @@ pub fn serve( |endpoint_version: EndpointVersion, slot: Slot, query: api_types::ValidatorBlocksQuery, - chain: Arc>| { - blocking_json_task(move || { - let randao_reveal = query.randao_reveal.as_ref().map_or_else( - || { - if query.verify_randao { - Err(warp_utils::reject::custom_bad_request( - "randao_reveal is mandatory unless verify_randao=false".into(), - )) - } else { - Ok(Signature::empty()) - } - }, - |sig_bytes| { - sig_bytes.try_into().map_err(|e| { - warp_utils::reject::custom_bad_request(format!( - "randao reveal is not a valid BLS signature: {:?}", - e - )) - }) - }, - )?; + chain: Arc>| async move { + let randao_reveal = query.randao_reveal.as_ref().map_or_else( + || { + if query.verify_randao { + Err(warp_utils::reject::custom_bad_request( + "randao_reveal is mandatory unless verify_randao=false".into(), + )) + } else { + Ok(Signature::empty()) + } + }, + |sig_bytes| { + sig_bytes.try_into().map_err(|e| { + warp_utils::reject::custom_bad_request(format!( + "randao reveal is not a valid BLS signature: {:?}", + e + )) + }) + }, + )?; - let randao_verification = if query.verify_randao { - ProduceBlockVerification::VerifyRandao - } else { - ProduceBlockVerification::NoVerification - }; + let randao_verification = if query.verify_randao { + ProduceBlockVerification::VerifyRandao + } else { + ProduceBlockVerification::NoVerification + }; - let (block, _) = chain - .produce_block_with_verification::>( - randao_reveal, - slot, - query.graffiti.map(Into::into), - randao_verification, - ) - .map_err(warp_utils::reject::block_production_error)?; - let fork_name = block - .to_ref() - .fork_name(&chain.spec) - .map_err(inconsistent_fork_rejection)?; - fork_versioned_response(endpoint_version, fork_name, block) - }) + let (block, _) = chain + .produce_block_with_verification::>( + randao_reveal, + slot, + query.graffiti.map(Into::into), + randao_verification, + ) + .await + .map_err(warp_utils::reject::block_production_error)?; + let fork_name = block + .to_ref() + .fork_name(&chain.spec) + .map_err(inconsistent_fork_rejection)?; + fork_versioned_response(endpoint_version, fork_name, block) + .map(|response| warp::reply::json(&response)) }, ); diff --git a/consensus/state_processing/src/per_block_processing/tests.rs b/consensus/state_processing/src/per_block_processing/tests.rs index 435491fe98c..883c980a6be 100644 --- a/consensus/state_processing/src/per_block_processing/tests.rs +++ b/consensus/state_processing/src/per_block_processing/tests.rs @@ -63,7 +63,9 @@ async fn valid_block_ok() { let state = harness.get_current_state(); let slot = state.slot(); - let (block, mut state) = harness.make_block_return_pre_state(state, slot + Slot::new(1)); + let (block, mut state) = harness + .make_block_return_pre_state(state, slot + Slot::new(1)) + .await; let result = per_block_processing( &mut state, @@ -85,7 +87,7 @@ async fn invalid_block_header_state_slot() { let state = harness.get_current_state(); let slot = state.slot() + Slot::new(1); - let (signed_block, mut state) = harness.make_block_return_pre_state(state, slot); + let (signed_block, mut state) = harness.make_block_return_pre_state(state, slot).await; let (mut block, signature) = signed_block.deconstruct(); *block.slot_mut() = slot + Slot::new(1); @@ -114,7 +116,9 @@ async fn invalid_parent_block_root() { let state = harness.get_current_state(); let slot = state.slot(); - let (signed_block, mut state) = harness.make_block_return_pre_state(state, slot + Slot::new(1)); + let (signed_block, mut state) = harness + .make_block_return_pre_state(state, slot + Slot::new(1)) + .await; let (mut block, signature) = signed_block.deconstruct(); *block.parent_root_mut() = Hash256::from([0xAA; 32]); @@ -145,7 +149,9 @@ async fn invalid_block_signature() { let state = harness.get_current_state(); let slot = state.slot(); - let (signed_block, mut state) = harness.make_block_return_pre_state(state, slot + Slot::new(1)); + let (signed_block, mut state) = harness + .make_block_return_pre_state(state, slot + Slot::new(1)) + .await; let (block, _) = signed_block.deconstruct(); let result = per_block_processing( @@ -174,9 +180,11 @@ async fn invalid_randao_reveal_signature() { let state = harness.get_current_state(); let slot = state.slot(); - let (signed_block, mut state) = harness.make_block_with_modifier(state, slot + 1, |block| { - *block.body_mut().randao_reveal_mut() = Signature::empty(); - }); + let (signed_block, mut state) = harness + .make_block_with_modifier(state, slot + 1, |block| { + *block.body_mut().randao_reveal_mut() = Signature::empty(); + }) + .await; let result = per_block_processing( &mut state, diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index d736f0be193..a21eeb63c27 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -28,6 +28,8 @@ pub trait ExecPayload: + Hash + TryFrom> + From> + + Send + + 'static { fn block_type() -> BlockType; diff --git a/testing/state_transition_vectors/src/exit.rs b/testing/state_transition_vectors/src/exit.rs index 0511d26e008..3e4bb7bf3f9 100644 --- a/testing/state_transition_vectors/src/exit.rs +++ b/testing/state_transition_vectors/src/exit.rs @@ -50,11 +50,12 @@ impl ExitTest { let validator_index = self.validator_index; let exit_epoch = self.exit_epoch; - let (signed_block, state) = - harness.make_block_with_modifier(state.clone(), state.slot() + 1, |block| { + let (signed_block, state) = harness + .make_block_with_modifier(state.clone(), state.slot() + 1, |block| { harness.add_voluntary_exit(block, validator_index, exit_epoch); block_modifier(&harness, block); - }); + }) + .await; (signed_block, state) }