diff --git a/massa-consensus-worker/Cargo.toml b/massa-consensus-worker/Cargo.toml index 8d32edcac80..5a0ca5db1d8 100644 --- a/massa-consensus-worker/Cargo.toml +++ b/massa-consensus-worker/Cargo.toml @@ -35,6 +35,8 @@ crossbeam-channel = {workspace = true, "optional" = true} # BOM UPGRADE Re massa_pool_exports = {workspace = true, features = ["test-exports"]} massa_pos_exports = {workspace = true, features = ["test-exports"]} massa_protocol_exports = {workspace = true, features = ["test-exports"]} +massa_execution_exports = {workspace = true, features = ["test-exports"]} +massa_consensus_exports = {workspace = true, features = ["test-exports"]} massa_test_framework = {workspace = true} mockall = {workspace = true} rand = {workspace = true} diff --git a/massa-consensus-worker/src/tests/certik/mod.rs b/massa-consensus-worker/src/tests/certik/mod.rs index 14c33eab382..56c17b40b34 100644 --- a/massa-consensus-worker/src/tests/certik/mod.rs +++ b/massa-consensus-worker/src/tests/certik/mod.rs @@ -1,5 +1 @@ -mod tools; - -pub mod scenarios; -pub mod two_threads_scenarios; -pub mod four_threads_scenarios; +mod tools; \ No newline at end of file diff --git a/massa-consensus-worker/src/tests/scenarios.rs b/massa-consensus-worker/src/tests/scenarios.rs index f95135bf3b7..76e85ce69e1 100644 --- a/massa-consensus-worker/src/tests/scenarios.rs +++ b/massa-consensus-worker/src/tests/scenarios.rs @@ -10,7 +10,10 @@ use super::{ use crate::tests::tools::create_block; use massa_consensus_exports::ConsensusConfig; use massa_execution_exports::MockExecutionController; -use massa_models::{address::Address, block_id::BlockId, config::ENDORSEMENT_COUNT, slot::Slot}; +use massa_models::{ + address::Address, block::BlockGraphStatus, block_id::BlockId, config::ENDORSEMENT_COUNT, + slot::Slot, +}; use massa_pool_exports::MockPoolController; use massa_pos_exports::{MockSelectorController, Selection}; use massa_signature::KeyPair; @@ -19,6 +22,43 @@ use massa_test_framework::TestUniverse; use massa_time::MassaTime; use mockall::Sequence; +#[test] +fn test_genesis_block_creation() { + let staking_key: KeyPair = KeyPair::generate(0).unwrap(); + let thread_count = 2; + let cfg = ConsensusConfig { + t0: MassaTime::from_millis(1000), + thread_count, + genesis_timestamp: MassaTime::now().unwrap(), + force_keep_final_periods: 50, + force_keep_final_periods_without_ops: 128, + max_future_processing_blocks: 10, + genesis_key: staking_key.clone(), + ..ConsensusConfig::default() + }; + let mut foreign_controllers = ConsensusForeignControllers::new_with_mocks(); + + foreign_controllers + .execution_controller + .expect_update_blockclique_status() + .return_once(|_, _, _| {}); + foreign_controllers + .pool_controller + .expect_notify_final_cs_periods() + .returning(|_| {}); + foreign_controllers + .pool_controller + .expect_add_denunciation_precursor() + .returning(|_| {}); + let universe = ConsensusTestUniverse::new(foreign_controllers, cfg); + let genesis_hashes = universe + .module_controller + .get_block_graph_status(None, None) + .expect("could not get block graph status") + .genesis_blocks; + assert_eq!(genesis_hashes.len() as u8, thread_count); +} + /// This test tests that the blocks are well processed by consensus even if they are not sent in a sorted way. #[test] fn test_unsorted_block() { @@ -265,3 +305,98 @@ fn test_parallel_incompatibility() { }, ); } + +#[test] +fn test_parent_in_the_future() { + let staking_key: KeyPair = KeyPair::generate(0).unwrap(); + let cfg = ConsensusConfig { + t0: MassaTime::from_millis(1000), + thread_count: 2, + genesis_timestamp: MassaTime::now().unwrap(), + force_keep_final_periods: 50, + force_keep_final_periods_without_ops: 128, + max_future_processing_blocks: 2, + block_db_prune_interval: MassaTime::from_millis(250), + genesis_key: staking_key.clone(), + ..ConsensusConfig::default() + }; + let staking_address = Address::from_public_key(&staking_key.get_public_key()); + let start_period = 100; + + let mut foreign_controllers = ConsensusForeignControllers::new_with_mocks(); + let storage = foreign_controllers.storage.clone(); + + foreign_controllers + .execution_controller + .expect_update_blockclique_status() + .returning(|_, _, _| {}); + foreign_controllers + .pool_controller + .expect_notify_final_cs_periods() + .returning(|_| {}); + foreign_controllers + .pool_controller + .expect_add_denunciation_precursor() + .returning(|_| {}); + foreign_controllers + .selector_controller + .expect_get_producer() + .returning(move |_| Ok(staking_address)); + foreign_controllers + .selector_controller + .expect_get_selection() + .returning(move |_| { + Ok(Selection { + producer: staking_address, + endorsements: vec![staking_address; ENDORSEMENT_COUNT as usize], + }) + }); + + let universe = ConsensusTestUniverse::new(foreign_controllers, cfg); + let genesis_hashes = universe + .module_controller + .get_block_graph_status(None, None) + .expect("could not get block graph status") + .genesis_blocks; + // create test blocks + + let t0s1 = create_block( + Slot::new(start_period, 0), + genesis_hashes.clone(), + &staking_key, + ); + + let t1s1 = create_block( + Slot::new(start_period, 1), + genesis_hashes.clone(), + &staking_key, + ); + + let t0s2 = create_block( + Slot::new(start_period.saturating_add(1), 0), + vec![t0s1.id, t1s1.id], + &staking_key, + ); + + // send blocks t0s1, t1s1, + register_block(&universe.module_controller, t0s1.clone(), storage.clone()); + register_block(&universe.module_controller, t1s1.clone(), storage.clone()); + //register blocks t0s2 + register_block(&universe.module_controller, t0s2.clone(), storage.clone()); + + // Wait for blocks_db to be pruned + std::thread::sleep(Duration::from_millis(1500)); + // We only keep t0s2 and t1s1 because of max_future_processing_blocks set to 2 + let status = universe + .module_controller + .get_block_statuses(&[t0s1.id, t1s1.id, t0s2.id]); + assert_eq!( + status, + vec![ + BlockGraphStatus::WaitingForSlot, + BlockGraphStatus::WaitingForSlot, + BlockGraphStatus::NotFound + ], + "wrong status" + ); +} diff --git a/massa-consensus-worker/src/worker/init.rs b/massa-consensus-worker/src/worker/init.rs index edaf1b21dbb..aab6057ebde 100644 --- a/massa-consensus-worker/src/worker/init.rs +++ b/massa-consensus-worker/src/worker/init.rs @@ -45,7 +45,6 @@ pub fn create_genesis_block( ) -> Result { let keypair = &cfg.genesis_key; let header = BlockHeader::new_verifiable( - // VERSIONNING TODO: what to implement here in case of restart? BlockHeader { current_version: 0, announced_version: None, diff --git a/massa-db-worker/src/massa_db.rs b/massa-db-worker/src/massa_db.rs index 5cb0453d8e5..783ea6f9cd7 100644 --- a/massa-db-worker/src/massa_db.rs +++ b/massa-db-worker/src/massa_db.rs @@ -878,11 +878,7 @@ mod test { // Check not allowed to init a second instance let db2 = MassaDB::new_with_options(db_config, db_opts.clone()); assert!(db2.is_err()); - assert!(db2 - .err() - .unwrap() - .into_string() - .contains("IO error: lock hold by current process")); + assert!(db2.err().unwrap().into_string().contains("IO error")); } #[test] diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index fb9edbc1329..36cc5519386 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1451,11 +1451,30 @@ mod tests { &keypair, ) .unwrap(); + + let balance_initial = sample_state.read().ledger.get_balance(&address).unwrap(); + let roll_count_too_high = balance_initial + .checked_div(exec_cfg.roll_price) + .unwrap() + .saturating_add(10); + // This second operation will fail as the price is too high + let operation_too_expensive = Operation::new_verifiable( + Operation { + fee: Amount::zero(), + expire_period: 10, + op: OperationType::RollBuy { + roll_count: roll_count_too_high, + }, + }, + OperationSerializer::new(), + &keypair, + ) + .unwrap(); // create the block containing the roll buy operation - storage.store_operations(vec![operation.clone()]); + storage.store_operations(vec![operation.clone(), operation_too_expensive.clone()]); let block = create_block( KeyPair::generate(0).unwrap(), - vec![operation], + vec![operation, operation_too_expensive], vec![], Slot::new(1, 0), ) @@ -1558,6 +1577,7 @@ mod tests { let roll_count_initial = sample_state.read().pos_state.get_rolls_for(&address); let roll_sell_1 = 10; let roll_sell_2 = 1; + let roll_sell_3 = roll_count_initial.saturating_add(10); let initial_deferred_credits = Amount::from_str("100").unwrap(); @@ -1602,11 +1622,27 @@ mod tests { &keypair, ) .unwrap(); + let operation3 = Operation::new_verifiable( + Operation { + fee: Amount::zero(), + expire_period: 10, + op: OperationType::RollSell { + roll_count: roll_sell_3, + }, + }, + OperationSerializer::new(), + &keypair, + ) + .unwrap(); // create the block containing the roll buy operation - storage.store_operations(vec![operation1.clone(), operation2.clone()]); + storage.store_operations(vec![ + operation1.clone(), + operation2.clone(), + operation3.clone(), + ]); let block = create_block( KeyPair::generate(0).unwrap(), - vec![operation1, operation2], + vec![operation1, operation2, operation3], vec![], Slot::new(3, 0), )