From 72da0df9e853b14e35ebc8671ba3f67a106c3c3a Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Wed, 27 Nov 2019 08:52:16 +1100 Subject: [PATCH] Ensure eth1 block is produced without any votes --- beacon_node/beacon_chain/src/eth1_chain.rs | 91 ++++++++++++++++------ 1 file changed, 67 insertions(+), 24 deletions(-) diff --git a/beacon_node/beacon_chain/src/eth1_chain.rs b/beacon_node/beacon_chain/src/eth1_chain.rs index 6ddb2d1beb..e4f42955f6 100644 --- a/beacon_node/beacon_chain/src/eth1_chain.rs +++ b/beacon_node/beacon_chain/src/eth1_chain.rs @@ -205,9 +205,22 @@ impl Eth1ChainBackend for CachingEth1Backend { let blocks = self.core.blocks().read(); - let (new_eth1_data, all_eth1_data) = if let Some(sets) = - eth1_data_sets(blocks.iter(), state, prev_eth1_hash, spec, &self.log) - { + let period = T::SlotsPerEth1VotingPeriod::to_u64(); + let eth1_follow_distance = spec.eth1_follow_distance; + let voting_period_start_slot = (state.slot / period) * period; + let voting_period_start_seconds = slot_start_seconds::( + state.genesis_time, + spec.milliseconds_per_slot, + voting_period_start_slot, + ); + + let (new_eth1_data, all_eth1_data) = if let Some(sets) = eth1_data_sets( + blocks.iter(), + prev_eth1_hash, + voting_period_start_seconds, + spec, + &self.log, + ) { sets } else { crit!( @@ -233,13 +246,24 @@ impl Eth1ChainBackend for CachingEth1Backend { let eth1_data = if let Some(eth1_data) = find_winning_vote(valid_votes) { eth1_data } else { - crit!( - self.log, - "Unable to find a winning eth1 vote"; - "outcome" => "casting random eth1 vote" - ); + blocks + .iter() + .rev() + .skip_while(|eth1_block| eth1_block.timestamp > voting_period_start_seconds) + .skip(eth1_follow_distance as usize) + .take(1) + .collect::>() + .first() + .and_then(|&block| block.clone().eth1_data()) + .unwrap_or_else(|| { + crit!( + self.log, + "Unable to find a winning eth1 vote"; + "outcome" => "casting random eth1 vote" + ); - return Ok(random_eth1_data()); + random_eth1_data() + }) }; Ok(eth1_data) @@ -329,25 +353,17 @@ fn eth1_block_hash_at_start_of_voting_period( /// /// `prev_eth1_hash` is the `eth1_data.block_hash` at the start of the voting period defined by /// `state.slot`. -fn eth1_data_sets<'a, T: EthSpec, I>( +fn eth1_data_sets<'a, I>( blocks: I, - state: &BeaconState, prev_eth1_hash: Hash256, + voting_period_start_seconds: u64, spec: &ChainSpec, log: &Logger, ) -> Option<(Eth1DataBlockNumber, Eth1DataBlockNumber)> where - T: EthSpec, I: DoubleEndedIterator + Clone, { - let period = T::SlotsPerEth1VotingPeriod::to_u64(); let eth1_follow_distance = spec.eth1_follow_distance; - let voting_period_start_slot = (state.slot / period) * period; - let voting_period_start_seconds = slot_start_seconds::( - state.genesis_time, - spec.milliseconds_per_slot, - voting_period_start_slot, - ); let in_scope_eth1_data = blocks .rev() @@ -788,6 +804,16 @@ mod test { mod eth1_data_sets { use super::*; + fn get_voting_period_start_seconds(state: &BeaconState, spec: &ChainSpec) -> u64 { + let period = ::SlotsPerEth1VotingPeriod::to_u64(); + let voting_period_start_slot = (state.slot / period) * period; + slot_start_seconds::( + state.genesis_time, + spec.milliseconds_per_slot, + voting_period_start_slot, + ) + } + #[test] fn empty_cache() { let log = null_logger().unwrap(); @@ -799,7 +825,13 @@ mod test { let blocks = vec![]; assert_eq!( - eth1_data_sets(blocks.iter(), &state, prev_eth1_hash, &spec, &log), + eth1_data_sets( + blocks.iter(), + prev_eth1_hash, + get_voting_period_start_seconds(&state, spec), + &spec, + &log + ), None ); } @@ -817,7 +849,13 @@ mod test { let blocks = vec![get_eth1_block(0, 0)]; assert_eq!( - eth1_data_sets(blocks.iter(), &state, prev_eth1_hash, &spec, &log), + eth1_data_sets( + blocks.iter(), + prev_eth1_hash, + get_voting_period_start_seconds(&state, &spec), + &spec, + &log + ), None ); } @@ -842,9 +880,14 @@ mod test { .map(|i| get_eth1_block(i, i)) .collect::>(); - let (new_eth1_data, all_eth1_data) = - eth1_data_sets(blocks.iter(), &state, prev_eth1_hash, &spec, &log) - .expect("should find data"); + let (new_eth1_data, all_eth1_data) = eth1_data_sets( + blocks.iter(), + prev_eth1_hash, + get_voting_period_start_seconds(&state, &spec), + &spec, + &log, + ) + .expect("should find data"); assert_eq!( all_eth1_data.len(),