diff --git a/testing/jormungandr-integration-tests/src/jormungandr/explorer/block.rs b/testing/jormungandr-integration-tests/src/jormungandr/explorer/block.rs index b5f871fb71..23697943e8 100644 --- a/testing/jormungandr-integration-tests/src/jormungandr/explorer/block.rs +++ b/testing/jormungandr-integration-tests/src/jormungandr/explorer/block.rs @@ -72,11 +72,13 @@ pub fn explorer_block_test() { let mut fragment_generator = FragmentGenerator::new( sender, receiver, + None, jormungandr.to_remote(), time_era.slots_per_epoch(), 2, 2, 2, + 0, fragment_sender, ); diff --git a/testing/jormungandr-integration-tests/src/jormungandr/fragments.rs b/testing/jormungandr-integration-tests/src/jormungandr/fragments.rs index 9d6972ee5f..5981eae69e 100644 --- a/testing/jormungandr-integration-tests/src/jormungandr/fragments.rs +++ b/testing/jormungandr-integration-tests/src/jormungandr/fragments.rs @@ -58,11 +58,13 @@ pub fn send_all_fragments() { let mut fragment_generator = FragmentGenerator::new( sender, receiver, + None, jormungandr.to_remote(), time_era.slots_per_epoch(), 2, 2, 2, + 0, fragment_sender, ); diff --git a/testing/jormungandr-integration-tests/src/jormungandr/mempool.rs b/testing/jormungandr-integration-tests/src/jormungandr/mempool.rs index 357e24ab06..113a9811c2 100644 --- a/testing/jormungandr-integration-tests/src/jormungandr/mempool.rs +++ b/testing/jormungandr-integration-tests/src/jormungandr/mempool.rs @@ -4,6 +4,7 @@ use assert_fs::{ TempDir, }; use chain_core::property::{FromStr, Serialize}; +use chain_crypto::Ed25519; use chain_impl_mockchain::{ block::BlockDate, chaintypes::ConsensusVersion, @@ -16,7 +17,7 @@ use hersir::{ }; use jormungandr_automation::{ jormungandr::{ConfigurationBuilder, FragmentNode, LeadershipMode, MemPoolCheck, Starter}, - testing::time, + testing::{keys::create_new_key_pair, time}, }; use jormungandr_lib::interfaces::{ BlockDate as BlockDateDto, InitialToken, InitialUTxO, Mempool, PersistentLog, SlotDuration, @@ -36,6 +37,7 @@ pub fn dump_send_correct_fragments() { let persistent_log_path = temp_dir.child("persistent_log"); let receiver = thor::Wallet::default(); let sender = thor::Wallet::default(); + let first_bft_leader = create_new_key_pair::(); let jormungandr = startup::start_bft( vec![&sender, &receiver], @@ -43,6 +45,7 @@ pub fn dump_send_correct_fragments() { .with_slots_per_epoch(60) .with_block_content_max_size(100000.into()) .with_slot_duration(1) + .with_consensus_leaders_ids(vec![first_bft_leader.identifier().into()]) .with_mempool(Mempool { pool_max_entries: 1_000_000usize.into(), log_max_entries: 1_000_000usize.into(), @@ -72,11 +75,13 @@ pub fn dump_send_correct_fragments() { let mut fragment_generator = FragmentGenerator::new( sender, receiver, + Some(first_bft_leader), jormungandr.to_remote(), time_era.slots_per_epoch(), 2, 2, 2, + 2, fragment_sender, ); diff --git a/testing/jormungandr-integration-tests/src/non_functional/fragment.rs b/testing/jormungandr-integration-tests/src/non_functional/fragment.rs index a8ef7052eb..3f4bc514e2 100644 --- a/testing/jormungandr-integration-tests/src/non_functional/fragment.rs +++ b/testing/jormungandr-integration-tests/src/non_functional/fragment.rs @@ -50,11 +50,13 @@ pub fn fragment_load_test() { let mut request_generator = FragmentGenerator::new( faucet, receiver, + None, jormungandr.to_remote(), 60, 30, 30, 30, + 0, FragmentSender::new( jormungandr.genesis_block_hash(), jormungandr.fees(), diff --git a/testing/mjolnir/src/mjolnir_lib/fragment/standard/all.rs b/testing/mjolnir/src/mjolnir_lib/fragment/standard/all.rs index 4c357cedf2..a4f1f000cf 100644 --- a/testing/mjolnir/src/mjolnir_lib/fragment/standard/all.rs +++ b/testing/mjolnir/src/mjolnir_lib/fragment/standard/all.rs @@ -3,8 +3,12 @@ use crate::{ mjolnir_lib::{args::parse_shift, build_monitor, MjolnirError}, }; use chain_addr::Discrimination; +use chain_crypto::Ed25519; use chain_impl_mockchain::block::BlockDate; -use jormungandr_automation::{jormungandr::RemoteJormungandrBuilder, testing::time}; +use jormungandr_automation::{ + jormungandr::RemoteJormungandrBuilder, + testing::{keys::create_new_key_pair, time}, +}; use jormungandr_lib::crypto::hash::Hash; use jortestkit::{ load::ConfigurationBuilder, @@ -103,14 +107,18 @@ impl AllFragments { FragmentSenderSetup::no_verify(), ); + let bft_secret_alice = create_new_key_pair::(); + let mut generator = FragmentGenerator::new( faucet, receiver, + Some(bft_secret_alice), remote_jormungandr, settings.slots_per_epoch, 30, 30, 30, + 30, fragment_sender, ); diff --git a/testing/mjolnir/src/mjolnir_lib/generators/fragment_generator.rs b/testing/mjolnir/src/mjolnir_lib/generators/fragment_generator.rs index cb332459b9..fe3ad2726c 100644 --- a/testing/mjolnir/src/mjolnir_lib/generators/fragment_generator.rs +++ b/testing/mjolnir/src/mjolnir_lib/generators/fragment_generator.rs @@ -1,6 +1,9 @@ use chain_core::property::FromStr; +use chain_crypto::Ed25519; use chain_impl_mockchain::{ - certificate::{VotePlan, VoteTallyPayload}, + certificate::{UpdateProposal, UpdateVote, VotePlan, VoteTallyPayload}, + chaintypes::ConsensusVersion, + fragment::FragmentId, vote::Choice, }; use chain_time::TimeEra; @@ -8,7 +11,10 @@ use jormungandr_automation::{ jormungandr::{MemPoolCheck, RemoteJormungandr}, testing::{SyncNode, VoteCastCounter, VotePlanBuilder}, }; -use jormungandr_lib::{crypto::hash::Hash, interfaces::BlockDate as BlockDateDto}; +use jormungandr_lib::{ + crypto::{hash::Hash, key::KeyPair}, + interfaces::{BlockContentMaxSize, BlockDate as BlockDateDto, ConfigParam, ConfigParams}, +}; use jortestkit::load::{Request, RequestFailure, RequestGenerator}; use rand::RngCore; use rand_core::OsRng; @@ -26,6 +32,8 @@ pub struct FragmentGenerator<'a, S: SyncNode + Send> { active_stake_pools: Vec, vote_plans_for_casting: Vec, vote_plans_for_tally: Vec, + update_proposals_for_casting: Vec, + bft_leader: Option>, node: RemoteJormungandr, rand: OsRng, vote_cast_register: Option, @@ -34,6 +42,8 @@ pub struct FragmentGenerator<'a, S: SyncNode + Send> { stake_pools_count: usize, vote_plans_for_tally_count: usize, vote_plans_for_casting_count: usize, + update_proposals_for_casting_count: usize, + fragment_options_count: usize, } impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { @@ -41,16 +51,21 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { pub fn new( sender: Wallet, receiver: Wallet, + bft_leader: Option>, node: RemoteJormungandr, slots_per_epoch: u32, stake_pools_count: usize, vote_plans_for_tally_count: usize, vote_plans_for_casting_count: usize, + update_proposals_for_casting_count: usize, fragment_sender: FragmentSender<'a, S>, ) -> Self { assert!(vote_plans_for_casting_count > 1); assert!(stake_pools_count > 1); assert!(vote_plans_for_tally_count > 1); + if bft_leader.is_some() { + assert!(update_proposals_for_casting_count > 1); + } Self { sender, @@ -58,6 +73,8 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { active_stake_pools: vec![], vote_plans_for_casting: vec![], vote_plans_for_tally: vec![], + update_proposals_for_casting: vec![], + bft_leader, node, vote_cast_register: None, rand: OsRng, @@ -66,6 +83,8 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { stake_pools_count, vote_plans_for_tally_count, vote_plans_for_casting_count, + update_proposals_for_casting_count, + fragment_options_count: 0, } } @@ -79,6 +98,56 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { let settings = self.node.rest().settings().unwrap(); let block0_hash = Hash::from_str(&settings.block0_hash).unwrap(); let fees = settings.fees; + if settings.consensus_version == ConsensusVersion::Bft.to_string() { + assert!( + self.bft_leader.is_some(), + "Consensus version bft, bft leader needed" + ); + self.fragment_options_count = 12; + + let update_proposals: Vec = iter::from_fn(|| { + Some(UpdateProposal::new( + ConfigParams::new(vec![ConfigParam::BlockContentMaxSize( + BlockContentMaxSize::from(self.rand.next_u32()), + )]) + .into(), + self.bft_leader + .as_ref() + .unwrap() + .identifier() + .into_public_key() + .into(), + )) + }) + .take(self.update_proposals_for_casting_count) + .collect(); + + for update_proposal in update_proposals { + fragments.push( + FragmentBuilder::new(&block0_hash, &fees, self.fragment_sender.date()) + .update_proposal( + &self.sender, + update_proposal, + &self + .bft_leader + .as_ref() + .unwrap() + .signing_key() + .into_secret_key(), + ), + ); + self.sender.confirm_transaction(); + } + self.update_proposals_for_casting = fragments.iter().map(|f| f.hash()).collect(); + } + + if settings.consensus_version == ConsensusVersion::GenesisPraos.to_string() { + assert!( + self.bft_leader.is_none(), + "Consesus version genesis praos, bft leader will be ignored" + ); + self.fragment_options_count = 10; + } let stake_pools: Vec = iter::from_fn(|| Some(StakePool::new(&self.sender))) .take(self.stake_pools_count) @@ -116,6 +185,7 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { ); self.sender.confirm_transaction(); } + for vote_plan_for_casting in &votes_plan_for_casting { fragments.push( FragmentBuilder::new(&block0_hash, &fees, self.fragment_sender.date()) @@ -155,14 +225,15 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { pub fn send_all(&mut self) -> Result, FragmentSenderError> { let mut checks = Vec::new(); - for i in 0..10 { + + for i in 0..self.fragment_options_count { checks.push(self.send_one(i as u8)?); } Ok(checks) } pub fn send_one(&mut self, option: u8) -> Result { - match option % 10 { + match option % self.fragment_options_count as u8 { 0 => self.fragment_sender.send_transaction( &mut self.sender, &self.receiver, @@ -280,6 +351,54 @@ impl<'a, S: SyncNode + Send> FragmentGenerator<'a, S> { VoteTallyPayload::Public, ) } + 10 => { + let change_params = ConfigParams::new(vec![ConfigParam::BlockContentMaxSize( + BlockContentMaxSize::from(self.rand.next_u32()), + )]); + + let update_proposal = UpdateProposal::new( + change_params.into(), + self.bft_leader + .as_ref() + .unwrap() + .identifier() + .into_public_key() + .into(), + ); + + self.fragment_sender.send_update_proposal( + &mut self.sender, + &self.bft_leader.as_ref().unwrap().signing_key().into(), + update_proposal, + &self.node, + ) + } + 11 => { + let index = self.rand.next_u32() as usize % self.update_proposals_for_casting.len(); + let update_proposal = self.update_proposals_for_casting.get(index).unwrap(); + + let update_vote = UpdateVote::new( + *update_proposal, + self.bft_leader + .as_ref() + .unwrap() + .identifier() + .into_public_key() + .into(), + ); + + self.fragment_sender.send_update_vote( + &mut self.sender, + &self + .bft_leader + .as_ref() + .unwrap() + .signing_key() + .into_secret_key(), + update_vote, + &self.node, + ) + } _ => unreachable!(), } }