diff --git a/eth2/state_processing/benches/bench_block_processing.rs b/eth2/state_processing/benches/bench_block_processing.rs index 128b1051b..a315717b2 100644 --- a/eth2/state_processing/benches/bench_block_processing.rs +++ b/eth2/state_processing/benches/bench_block_processing.rs @@ -17,6 +17,8 @@ use types::*; pub fn bench_block_processing_n_validators(c: &mut Criterion, validator_count: usize) { let spec = ChainSpec::foundation(); + let bench_builder = BlockBenchingBuilder::new(validator_count, &spec); + let (mut state, keypairs) = build_state(validator_count, &spec); let block = build_block(&mut state, &keypairs, &spec); @@ -94,105 +96,160 @@ fn build_state(validator_count: usize, spec: &ChainSpec) -> (BeaconState, Vec BeaconBlock { - let mut builder = TestingBeaconBlockBuilder::new(spec); +pub struct BlockBenchingBuilder { + pub state_builder: TestingBeaconStateBuilder, + pub block_builder: TestingBeaconBlockBuilder, - builder.set_slot(state.slot); + pub num_validators: usize, + pub num_proposer_slashings: usize, + pub num_attester_slashings: usize, + pub num_indices_per_slashable_vote: usize, + pub num_attestations: usize, + pub num_deposits: usize, + pub num_exits: usize, + pub num_transfers: usize, +} - let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); - let keypair = &keypairs[proposer_index]; +impl BlockBenchingBuilder { + pub fn new(num_validators: usize, spec: &ChainSpec) -> Self { + let mut state_builder = + TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(num_validators, &spec); + let mut block_builder = TestingBeaconBlockBuilder::new(spec); - builder.set_randao_reveal(&keypair.sk, &state.fork, spec); - - // Used as a stream of validator indices for use in slashings, exits, etc. - let mut validators_iter = (0..keypairs.len() as u64).into_iter(); - - // Insert the maximum possible number of `ProposerSlashing` objects. - debug!( - "Inserting {} proposer slashings...", - spec.max_proposer_slashings - ); - for _ in 0..spec.max_proposer_slashings { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - builder.insert_proposer_slashing( - validator_index, - &keypairs[validator_index as usize].sk, - &state.fork, - spec, - ); + Self { + state_builder, + block_builder, + num_validators: 0, + num_proposer_slashings: 0, + num_attester_slashings: 0, + num_indices_per_slashable_vote: spec.max_indices_per_slashable_vote as usize, + num_attestations: 0, + num_deposits: 0, + num_exits: 0, + num_transfers: 0 + } } - // Insert the maximum possible number of `AttesterSlashing` objects - debug!( - "Inserting {} attester slashings...", - spec.max_attester_slashings - ); - for _ in 0..spec.max_attester_slashings { - let mut attesters: Vec = vec![]; - let mut secret_keys: Vec<&SecretKey> = vec![]; + pub fn maximize_block_operations(&mut self, spec: &ChainSpec) { + self.num_proposer_slashings = spec.max_proposer_slashings as usize; + self.num_attester_slashings = spec.max_attester_slashings as usize; + self.num_indices_per_slashable_vote = spec.max_indices_per_slashable_vote as usize; + self.num_attestations = spec.max_attestations as usize; + self.num_deposits = spec.max_deposits as usize; + self.num_exits = spec.max_voluntary_exits as usize; + self.num_transfers = spec.max_transfers as usize; + } - for _ in 0..spec.max_indices_per_slashable_vote { + pub fn set_slot(&mut self, slot: Slot, spec: &ChainSpec) { + self.state_builder.teleport_to_slot(slot, &spec); + } + + pub fn build_caches(&mut self, spec: &ChainSpec) { + // Builds all caches; benches will not contain shuffling/committee building times. + self.state_builder.build_caches(&spec).unwrap(); + } + + pub fn build(self, spec: &ChainSpec) -> (BeaconBlock, BeaconState) { + let (mut state, keypairs) = self.state_builder.build(); + let builder = &mut self.block_builder; + + builder.set_slot(state.slot); + + let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); + let keypair = &keypairs[proposer_index]; + + builder.set_randao_reveal(&keypair.sk, &state.fork, spec); + + // Used as a stream of validator indices for use in slashings, exits, etc. + let mut validators_iter = (0..keypairs.len() as u64).into_iter(); + + // Insert `ProposerSlashing` objects. + debug!( + "Inserting {} proposer slashings...", + self.num_proposer_slashings + ); + for _ in 0..self.num_proposer_slashings { let validator_index = validators_iter.next().expect("Insufficient validators."); - attesters.push(validator_index); - secret_keys.push(&keypairs[validator_index as usize].sk); + builder.insert_proposer_slashing( + validator_index, + &keypairs[validator_index as usize].sk, + &state.fork, + spec, + ); } - builder.insert_attester_slashing(&attesters, &secret_keys, &state.fork, spec); - } - - // Insert the maximum possible number of `Attestation` objects. - debug!("Inserting {} attestations...", spec.max_attestations); - let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect(); - builder - .fill_with_attestations(state, &all_secret_keys, spec) - .unwrap(); - - // Insert the maximum possible number of `Deposit` objects. - debug!("Inserting {} deposits...", spec.max_deposits); - for i in 0..spec.max_deposits { - builder.insert_deposit(32_000_000_000, state.deposit_index + i, state, spec); - } - - // Insert the maximum possible number of `Exit` objects. - debug!("Inserting {} exits...", spec.max_voluntary_exits); - for _ in 0..spec.max_voluntary_exits { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - builder.insert_exit( - state, - validator_index, - &keypairs[validator_index as usize].sk, - spec, + // Insert `AttesterSlashing` objects + debug!( + "Inserting {} attester slashings...", + self.num_attester_slashings ); + for _ in 0..self.num_attester_slashings { + let mut attesters: Vec = vec![]; + let mut secret_keys: Vec<&SecretKey> = vec![]; + + for _ in 0..self.num_indices_per_slashable_vote { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + attesters.push(validator_index); + secret_keys.push(&keypairs[validator_index as usize].sk); + } + + builder.insert_attester_slashing(&attesters, &secret_keys, &state.fork, spec); + } + + // Insert `Attestation` objects. + debug!("Inserting {} attestations...", self.num_attestations); + let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect(); + builder + .insert_attestations(&state, &all_secret_keys, self.num_attestations as usize, spec) + .unwrap(); + + // Insert `Deposit` objects. + debug!("Inserting {} deposits...", self.num_deposits); + for i in 0..self.num_deposits { + builder.insert_deposit(32_000_000_000, state.deposit_index + (i as u64), &state, spec); + } + + // Insert the maximum possible number of `Exit` objects. + debug!("Inserting {} exits...", self.num_exits); + for _ in 0..self.num_exits { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + builder.insert_exit( + &state, + validator_index, + &keypairs[validator_index as usize].sk, + spec, + ); + } + + // Insert the maximum possible number of `Transfer` objects. + debug!("Inserting {} transfers...", self.num_transfers); + for _ in 0..self.num_transfers { + let validator_index = validators_iter.next().expect("Insufficient validators."); + + // Manually set the validator to be withdrawn. + state.validator_registry[validator_index as usize].withdrawable_epoch = + state.previous_epoch(spec); + + builder.insert_transfer( + &state, + validator_index, + validator_index, + 1, + keypairs[validator_index as usize].clone(), + spec, + ); + } + + let mut block = builder.build(&keypair.sk, &state.fork, spec); + + // Set the eth1 data to be different from the state. + block.eth1_data.block_hash = Hash256::from_slice(&vec![42; 32]); + + (block, state) } - - // Insert the maximum possible number of `Transfer` objects. - debug!("Inserting {} transfers...", spec.max_transfers); - for _ in 0..spec.max_transfers { - let validator_index = validators_iter.next().expect("Insufficient validators."); - - // Manually set the validator to be withdrawn. - state.validator_registry[validator_index as usize].withdrawable_epoch = - state.previous_epoch(spec); - - builder.insert_transfer( - state, - validator_index, - validator_index, - 1, - keypairs[validator_index as usize].clone(), - spec, - ); - } - - let mut block = builder.build(&keypair.sk, &state.fork, spec); - - // Set the eth1 data to be different from the state. - block.eth1_data.block_hash = Hash256::from_slice(&vec![42; 32]); - - block } /// Run the detailed benchmarking suite on the given `BeaconState`. diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index 97e395e1f..ecb42e27b 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -74,19 +74,20 @@ impl TestingBeaconBlockBuilder { self.block.body.attester_slashings.push(attester_slashing); } - /// Fills the block with `MAX_ATTESTATIONS` attestations. + /// Fills the block with `num_attestations` attestations. /// /// It will first go and get each committee that is able to include an attestation in this - /// block. If there are enough committees, it will produce an attestation for each. If there - /// are _not_ enough committees, it will start splitting the committees in half until it + /// block. If there _are_ enough committees, it will produce an attestation for each. If there + /// _are not_ enough committees, it will start splitting the committees in half until it /// achieves the target. It will then produce separate attestations for each split committee. /// /// Note: the signed messages of the split committees will be identical -- it would be possible /// to aggregate these split attestations. - pub fn fill_with_attestations( + pub fn insert_attestations( &mut self, state: &BeaconState, secret_keys: &[&SecretKey], + num_attestations: usize, spec: &ChainSpec, ) -> Result<(), BeaconStateError> { let mut slot = self.block.slot - spec.min_attestation_inclusion_delay; @@ -110,7 +111,7 @@ impl TestingBeaconBlockBuilder { } for (committee, shard) in state.get_crosslink_committees_at_slot(slot, spec)? { - if attestations_added >= spec.max_attestations { + if attestations_added >= num_attestations { break; } @@ -125,12 +126,12 @@ impl TestingBeaconBlockBuilder { // Loop through all the committees, splitting each one in half until we have // `MAX_ATTESTATIONS` committees. loop { - if committees.len() >= spec.max_attestations as usize { + if committees.len() >= num_attestations as usize { break; } for index in 0..committees.len() { - if committees.len() >= spec.max_attestations as usize { + if committees.len() >= num_attestations as usize { break; }