diff --git a/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs b/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs index 93cd42754..5b2f513a7 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/genesis_config_presets.rs @@ -437,6 +437,7 @@ fn dancelight_testnet_genesis( x.stash.clone() }) .collect::>(), + ..Default::default() }, }) } diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs index aa85fdb91..cc44c0f06 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/common/mod.rs @@ -18,8 +18,8 @@ use { crate::{ - BlockProductionCost, CollatorAssignmentCost, ExternalValidatorSlashes, MessageQueue, - RuntimeCall, + Authorship, BlockProductionCost, CollatorAssignmentCost, ExternalValidatorSlashes, + MessageQueue, RuntimeCall, }, babe_primitives::{ digests::{PreDigest, SecondaryPlainPreDigest}, @@ -250,6 +250,7 @@ pub fn start_block() -> RunSummary { // Initialize the new block Babe::on_initialize(System::block_number()); + Authorship::on_initialize(System::block_number()); ContainerRegistrar::on_initialize(System::block_number()); ExternalValidatorSlashes::on_initialize(System::block_number()); Session::on_initialize(System::block_number()); @@ -280,6 +281,7 @@ pub fn end_block() { advance_block_state_machine(RunBlockState::End(block_number)); // Finalize the block Babe::on_finalize(System::block_number()); + Authorship::on_finalize(System::block_number()); Session::on_finalize(System::block_number()); Grandpa::on_finalize(System::block_number()); TransactionPayment::on_finalize(System::block_number()); @@ -335,6 +337,8 @@ pub struct ExtBuilder { balances: Vec<(AccountId, Balance)>, // [validator, amount] validators: Vec<(AccountId, Balance)>, + // [validator, amount] + external_validators: Vec<(AccountId, Balance)>, // [collator, amount] collators: Vec<(AccountId, Balance)>, // sudo key @@ -362,6 +366,7 @@ impl Default for ExtBuilder { (AccountId::from(ALICE), 210 * UNIT), (AccountId::from(BOB), 100 * UNIT), ], + external_validators: vec![], collators: Default::default(), sudo: Default::default(), para_ids: Default::default(), @@ -398,6 +403,11 @@ impl ExtBuilder { self } + pub fn with_external_validators(mut self, validators: Vec<(AccountId, Balance)>) -> Self { + self.external_validators = validators; + self + } + pub fn with_collators(mut self, collators: Vec<(AccountId, Balance)>) -> Self { self.collators = collators; self @@ -614,6 +624,32 @@ impl ExtBuilder { keys.extend(validator_keys) } + if !self.external_validators.is_empty() { + let validator_keys: Vec<_> = self + .external_validators + .clone() + .into_iter() + .map(|(account, _balance)| { + let authority_keys = + get_authority_keys_from_seed(&account.to_string(), self.keystore.as_ref()); + ( + account.clone(), + account, + crate::SessionKeys { + babe: authority_keys.babe.clone(), + grandpa: authority_keys.grandpa.clone(), + para_validator: authority_keys.para_validator.clone(), + para_assignment: authority_keys.para_assignment.clone(), + authority_discovery: authority_keys.authority_discovery.clone(), + beefy: authority_keys.beefy.clone(), + nimbus: authority_keys.nimbus.clone(), + }, + ) + }) + .collect(); + keys.extend(validator_keys) + } + if !self.collators.is_empty() { // We set invulnerables in pallet_invulnerables let invulnerables: Vec = self @@ -674,6 +710,11 @@ impl ExtBuilder { .iter() .map(|(account, _)| account.clone()) .collect(), + external_validators: self + .external_validators + .iter() + .map(|(account, _)| account.clone()) + .collect(), } .assimilate_storage(&mut t) .unwrap(); diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs index b4d4ae11e..4deb7891b 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/external_validators_tests.rs @@ -713,6 +713,11 @@ fn external_validators_rewards_sends_message_on_era_end() { (AccountId::from(ALICE), 210_000 * UNIT), (AccountId::from(BOB), 100_000 * UNIT), ]) + .with_validators(vec![]) + .with_external_validators(vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ]) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here().into(); @@ -829,18 +834,13 @@ fn external_validators_rewards_merkle_proofs() { vec![AccountId::from(CHARLIE), AccountId::from(DAVE)] ); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 0 - ); - // Reward all validators in era 1 crate::RewardValidators::reward_backing(vec![ValidatorIndex(0)]); crate::RewardValidators::reward_backing(vec![ValidatorIndex(1)]); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 1 + assert_eq!( + pallet_external_validators_rewards::RewardPointsForEra::::iter().count(), + 1 ); let (_era_index, era_rewards) = @@ -1048,8 +1048,6 @@ fn external_validators_whitelisted_never_rewarded() { #[test] fn external_validators_rewards_test_command_integrity() { - use {crate::ValidatorIndex, runtime_parachains::inclusion::RewardValidators}; - ExtBuilder::default() .with_balances(vec![ (AccountId::from(ALICE), 210_000 * UNIT), @@ -1139,18 +1137,10 @@ fn external_validators_rewards_test_command_integrity() { vec![AccountId::from(CHARLIE), AccountId::from(DAVE)] ); - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 0 - ); - - // Reward Alice and Bob in era 1 - crate::RewardValidators::reward_backing(vec![ValidatorIndex(0)]); - crate::RewardValidators::reward_backing(vec![ValidatorIndex(1)]); - - assert!( - pallet_external_validators_rewards::RewardPointsForEra::::iter().count() - == 1 + // Validators are automatically rewarded. + assert_eq!( + pallet_external_validators_rewards::RewardPointsForEra::::iter().count(), + 1 ); let expected_inflation = @@ -1180,10 +1170,16 @@ fn external_validators_rewards_test_command_integrity() { .count(); let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + + let blocks_per_session: u128 = Babe::current_epoch().duration.into(); + let points_per_block = 20; + let expected_total_points = + (sessions_per_era as u128) * blocks_per_session * points_per_block; + let expected_rewards_command = Command::ReportRewards { external_idx: 1u64, era_index: 1u32, - total_points: 40u128, + total_points: expected_total_points, tokens_inflated: expected_inflation, rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, token_id, @@ -1209,6 +1205,15 @@ fn external_validators_rewards_are_minted_in_sovereign_account() { (AccountId::from(ALICE), 210_000 * UNIT), (AccountId::from(BOB), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs index 43fc94f28..790308ae9 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/inbound_queue_tests/integration_tests.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Tanssi. If not, see -use crate::tests::common::{mock_snowbridge_message_proof, ExtBuilder}; +use crate::tests::common::{mock_snowbridge_message_proof, ExtBuilder, ALICE, BOB, UNIT}; use crate::{AccountId, EthereumInboundQueue, ExternalValidators, Runtime}; use alloy_sol_types::SolEvent; use frame_system::pallet_prelude::OriginFor; @@ -33,7 +33,16 @@ use tp_bridge::symbiotic_message_processor::{ #[test] fn test_inbound_queue_message_passing() { - ExtBuilder::default().build().execute_with(|| { + ExtBuilder::default() + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ).build().execute_with(|| { let current_nonce = 1; snowbridge_pallet_system::Channels::::set(PRIMARY_GOVERNANCE_CHANNEL, Some(Channel { @@ -59,8 +68,6 @@ fn test_inbound_queue_message_passing() { proof: dummy_proof.clone(), }), Err(DispatchError::Other("No handler for message found"))); - assert_eq!(ExternalValidators::validators(), ExternalValidators::whitelisted_validators()); - let payload_validators = vec![ AccountKeyring::Charlie.to_account_id(), AccountKeyring::Ferdie.to_account_id(), @@ -91,7 +98,6 @@ fn test_inbound_queue_message_passing() { proof: dummy_proof.clone(), }), Ok(())); - let expected_validators = [ExternalValidators::whitelisted_validators(), payload_validators].concat(); assert_eq!(ExternalValidators::validators(), expected_validators); }); diff --git a/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs b/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs index fa920191a..3298bc4b1 100644 --- a/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs +++ b/chains/orchestrator-relays/runtime/dancelight/src/tests/slashes.rs @@ -407,6 +407,11 @@ fn test_slashes_are_sent_to_ethereum() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators(vec![]) + .with_external_validators(vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ]) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here().into(); @@ -422,10 +427,6 @@ fn test_slashes_are_sent_to_ethereum() { )); run_to_block(2); - assert_ok!(ExternalValidators::remove_whitelisted( - RuntimeOrigin::root(), - AccountId::from(ALICE) - )); inject_babe_slash(&AccountId::from(ALICE).to_string()); @@ -552,6 +553,15 @@ fn test_slashes_are_sent_to_ethereum_accumulatedly() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() @@ -683,6 +693,15 @@ fn test_slashes_are_sent_to_ethereum_accumulate_until_next_era() { (AccountId::from(CHARLIE), 100_000 * UNIT), (AccountId::from(DAVE), 100_000 * UNIT), ]) + .with_validators( + vec![] + ) + .with_external_validators( + vec![ + (AccountId::from(ALICE), 210 * UNIT), + (AccountId::from(BOB), 100 * UNIT), + ] + ) .build() .execute_with(|| { let token_location: VersionedLocation = Location::here() diff --git a/pallets/external-validators-rewards/src/lib.rs b/pallets/external-validators-rewards/src/lib.rs index 7952f83b7..c41baeb42 100644 --- a/pallets/external-validators-rewards/src/lib.rs +++ b/pallets/external-validators-rewards/src/lib.rs @@ -43,7 +43,7 @@ use { snowbridge_core::{ChannelId, TokenId}, snowbridge_outbound_queue_merkle_tree::{merkle_proof, merkle_root, verify_proof, MerkleProof}, sp_core::H256, - sp_runtime::traits::{Hash, MaybeEquivalence}, + sp_runtime::traits::{Hash, MaybeEquivalence, Zero}, sp_staking::SessionIndex, sp_std::collections::btree_set::BTreeSet, sp_std::vec, @@ -268,73 +268,92 @@ pub mod pallet { impl tp_traits::OnEraEnd for Pallet { fn on_era_end(era_index: EraIndex) { + // Will send a ReportRewards message to Ethereum unless: + // - the reward token is misconfigured + // - the tokens inflation is 0 (misconfigured inflation) + // - the total points is 0 (no rewards to distribute) + // - it fails to mint the tokens in the Ethereum Sovereign Account + // - the generated message doesn't pass validation + let token_location = T::TokenLocationReanchored::get(); let token_id = T::TokenIdFromLocation::convert_back(&token_location); - if let Some(token_id) = token_id { - if let Some(utils) = Self::generate_era_rewards_utils(era_index, None) { - let tokens_inflated = T::EraInflationProvider::get(); - - let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get(); - if let Err(err) = - T::Currency::mint_into(ðereum_sovereign_account, tokens_inflated.into()) - { - log::error!(target: "ext_validators_rewards", "Failed to mint inflation into Ethereum Soverein Account: {err:?}"); - log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute"); - return; - } + let Some(token_id) = token_id else { + log::error!(target: "ext_validators_rewards", "no token id found for location {:?}", token_location); + return; + }; - let command = Command::ReportRewards { - external_idx: T::ExternalIndexProvider::get_external_index(), - era_index, - total_points: utils.total_points, - tokens_inflated, - rewards_merkle_root: utils.rewards_merkle_root, - token_id, - }; - - let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL; - - let outbound_message = Message { - id: None, - channel_id, - command: command.clone(), - }; - - // Validate and deliver the message - match T::ValidateMessage::validate(&outbound_message) { - Ok((ticket, _fee)) => { - let message_id = ticket.message_id(); - if let Err(err) = T::OutboundQueue::deliver(ticket) { - log::error!(target: "ext_validators_rewards", "OutboundQueue delivery of message failed. {err:?}"); - } else { - Self::deposit_event(Event::RewardsMessageSent { - message_id, - rewards_command: command, - }); - } - } - Err(err) => { - log::error!(target: "ext_validators_rewards", "OutboundQueue validation of message failed. {err:?}"); - } - } + let Some(utils) = Self::generate_era_rewards_utils(era_index, None) else { + // Unreachable, this should never happen as we are sending + // None as the second param in Self::generate_era_rewards_utils. + log::error!( + target: "ext_validators_rewards", + "Outbound message not sent for era {:?}!", + era_index + ); + return; + }; - frame_system::Pallet::::register_extra_weight_unchecked( - T::WeightInfo::on_era_end(), - DispatchClass::Mandatory, - ); - } else { - // Unreachable, this should never happen as we are sending - // None as the second param in Self::generate_era_rewards_utils. - log::error!( - target: "ext_validators_rewards", - "Outbound message not sent for era {:?}!", - era_index - ); + let tokens_inflated = T::EraInflationProvider::get(); + + if tokens_inflated.is_zero() { + log::error!(target: "ext_validators_rewards", "Not sending message because tokens_inflated is 0"); + return; + } + + if utils.total_points.is_zero() { + log::error!(target: "ext_validators_rewards", "Not sending message because total_points is 0"); + return; + } + + let ethereum_sovereign_account = T::RewardsEthereumSovereignAccount::get(); + if let Err(err) = + T::Currency::mint_into(ðereum_sovereign_account, tokens_inflated.into()) + { + log::error!(target: "ext_validators_rewards", "Failed to mint inflation into Ethereum Soverein Account: {err:?}"); + log::error!(target: "ext_validators_rewards", "Not sending message since there are no rewards to distribute"); + return; + } + + let command = Command::ReportRewards { + external_idx: T::ExternalIndexProvider::get_external_index(), + era_index, + total_points: utils.total_points, + tokens_inflated, + rewards_merkle_root: utils.rewards_merkle_root, + token_id, + }; + + let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL; + + let outbound_message = Message { + id: None, + channel_id, + command: command.clone(), + }; + + // Validate and deliver the message + match T::ValidateMessage::validate(&outbound_message) { + Ok((ticket, _fee)) => { + let message_id = ticket.message_id(); + if let Err(err) = T::OutboundQueue::deliver(ticket) { + log::error!(target: "ext_validators_rewards", "OutboundQueue delivery of message failed. {err:?}"); + } else { + Self::deposit_event(Event::RewardsMessageSent { + message_id, + rewards_command: command, + }); + } + } + Err(err) => { + log::error!(target: "ext_validators_rewards", "OutboundQueue validation of message failed. {err:?}"); } - } else { - log::debug!(target: "ext_validators_rewards", "no token id found for location {:?}", token_location); } + + frame_system::Pallet::::register_extra_weight_unchecked( + T::WeightInfo::on_era_end(), + DispatchClass::Mandatory, + ); } } } diff --git a/pallets/external-validators-rewards/src/mock.rs b/pallets/external-validators-rewards/src/mock.rs index 174ce8284..6aeefe9e6 100644 --- a/pallets/external-validators-rewards/src/mock.rs +++ b/pallets/external-validators-rewards/src/mock.rs @@ -17,7 +17,7 @@ use { crate as pallet_external_validators_rewards, frame_support::{ parameter_types, - traits::{ConstU128, ConstU32, ConstU64}, + traits::{ConstU32, ConstU64}, }, pallet_balances::AccountData, snowbridge_core::{ @@ -156,6 +156,7 @@ parameter_types! { pub const RewardsEthereumSovereignAccount: u64 = 0xffffffffffffffff; pub RewardTokenLocation: Location = Location::here(); + pub EraInflationProvider: u128 = Mock::mock().era_inflation.unwrap_or(42); } impl pallet_external_validators_rewards::Config for Test { @@ -164,7 +165,7 @@ impl pallet_external_validators_rewards::Config for Test { type HistoryDepth = ConstU32<10>; type BackingPoints = ConstU32<20>; type DisputeStatementPoints = ConstU32<20>; - type EraInflationProvider = ConstU128<42>; + type EraInflationProvider = EraInflationProvider; type ExternalIndexProvider = TimestampProvider; type GetWhitelistedValidators = (); type Hashing = Keccak256; @@ -191,6 +192,7 @@ pub mod mock_data { #[derive(Clone, Default, Encode, Decode, sp_core::RuntimeDebug, scale_info::TypeInfo)] pub struct Mocks { pub active_era: Option, + pub era_inflation: Option, } #[pallet::config] diff --git a/pallets/external-validators-rewards/src/tests.rs b/pallets/external-validators-rewards/src/tests.rs index 77e367d99..d97639aab 100644 --- a/pallets/external-validators-rewards/src/tests.rs +++ b/pallets/external-validators-rewards/src/tests.rs @@ -16,7 +16,6 @@ use { crate::{self as pallet_external_validators_rewards, mock::*}, - frame_support::traits::Get, sp_core::H256, sp_std::collections::btree_map::BTreeMap, tp_bridge::Command, @@ -175,3 +174,100 @@ fn test_on_era_end_without_proper_token() { ); }) } + +#[test] +fn test_on_era_end_with_zero_inflation() { + new_test_ext().execute_with(|| { + run_to_block(1); + + Mock::mutate(|mock| { + mock.active_era = Some(ActiveEraInfo { + index: 1, + start: None, + }); + mock.era_inflation = Some(0); + }); + let points = vec![10u32, 30u32, 50u32]; + let total_points: u32 = points.iter().cloned().sum(); + let accounts = vec![1u64, 3u64, 5u64]; + let accounts_points: Vec<(u64, crate::RewardPoints)> = accounts + .iter() + .cloned() + .zip(points.iter().cloned()) + .collect(); + ExternalValidatorsRewards::reward_by_ids(accounts_points); + ExternalValidatorsRewards::on_era_end(1); + + let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + let expected_command = Command::ReportRewards { + external_idx: 31000u64, + era_index: 1u32, + total_points: total_points as u128, + tokens_inflated: + ::EraInflationProvider::get(), // test inflation value used in mock + rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, + token_id: H256::repeat_byte(0x01), + }; + + let events = System::events(); + let expected_not_thrown_event = + RuntimeEvent::ExternalValidatorsRewards(crate::Event::RewardsMessageSent { + message_id: Default::default(), + rewards_command: expected_command, + }); + assert!( + !events + .iter() + .any(|record| record.event == expected_not_thrown_event), + "event should not have been thrown", + ); + }) +} + +#[test] +fn test_on_era_end_with_zero_points() { + new_test_ext().execute_with(|| { + run_to_block(1); + + Mock::mutate(|mock| { + mock.active_era = Some(ActiveEraInfo { + index: 1, + start: None, + }); + }); + let points = vec![0u32, 0u32, 0u32]; + let total_points: u32 = points.iter().cloned().sum(); + let accounts = vec![1u64, 3u64, 5u64]; + let accounts_points: Vec<(u64, crate::RewardPoints)> = accounts + .iter() + .cloned() + .zip(points.iter().cloned()) + .collect(); + ExternalValidatorsRewards::reward_by_ids(accounts_points); + ExternalValidatorsRewards::on_era_end(1); + + let rewards_utils = ExternalValidatorsRewards::generate_era_rewards_utils(1, None); + let expected_command = Command::ReportRewards { + external_idx: 31000u64, + era_index: 1u32, + total_points: total_points as u128, + tokens_inflated: + ::EraInflationProvider::get(), // test inflation value used in mock + rewards_merkle_root: rewards_utils.unwrap().rewards_merkle_root, + token_id: H256::repeat_byte(0x01), + }; + + let events = System::events(); + let expected_not_thrown_event = + RuntimeEvent::ExternalValidatorsRewards(crate::Event::RewardsMessageSent { + message_id: Default::default(), + rewards_command: expected_command, + }); + assert!( + !events + .iter() + .any(|record| record.event == expected_not_thrown_event), + "event should not have been thrown", + ); + }) +} diff --git a/pallets/external-validators/src/lib.rs b/pallets/external-validators/src/lib.rs index 5ad7e59c3..541a722b0 100644 --- a/pallets/external-validators/src/lib.rs +++ b/pallets/external-validators/src/lib.rs @@ -214,6 +214,7 @@ pub mod pallet { pub struct GenesisConfig { pub skip_external_validators: bool, pub whitelisted_validators: Vec, + pub external_validators: Vec, } #[pallet::genesis_build] @@ -236,10 +237,16 @@ pub mod pallet { ) .expect("genesis validators are more than T::MaxWhitelistedValidators"); + let bounded_external_validators = BoundedVec::<_, T::MaxExternalValidators>::try_from( + self.external_validators.clone(), + ) + .expect("genesis external validators are more than T::MaxExternalValidators"); + >::put(self.skip_external_validators); >::put(&bounded_validators); >::put(&bounded_validators); >::put(&bounded_validators); + >::put(&bounded_external_validators); } } diff --git a/pallets/external-validators/src/mock.rs b/pallets/external-validators/src/mock.rs index c3eea772b..39b3622fc 100644 --- a/pallets/external-validators/src/mock.rs +++ b/pallets/external-validators/src/mock.rs @@ -298,6 +298,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { pallet_external_validators::GenesisConfig:: { skip_external_validators: false, whitelisted_validators, + ..Default::default() } .assimilate_storage(&mut t) .unwrap(); diff --git a/tools/iforgor/tanssi.toml b/tools/iforgor/tanssi.toml index 7d0f14caa..e91164d1f 100644 --- a/tools/iforgor/tanssi.toml +++ b/tools/iforgor/tanssi.toml @@ -58,9 +58,17 @@ cargo test --release --all --features fast-runtime name = "[Tanssi] Cargo Test Crate" only_in_dir = "**/tanssi" script = """ -cargo test --release -p $1 --features runtime-benchmarks +cargo test --release -p $1 --features=fast-runtime $2 """ -args = ["Which crate to test"] +args = ["Which crate to test", "Tests filter"] + +[[entries]] +name = "[Tanssi] Cargo Test Crate (with benchmarks)" +only_in_dir = "**/tanssi" +script = """ +cargo test --release -p $1 --features=fast-runtime,benchmarks $2 +""" +args = ["Which crate to test", "Tests filter"] ## Build