diff --git a/radix-common/src/types/entity_type.rs b/radix-common/src/types/entity_type.rs index cb3db0160a5..1ea9235c12a 100644 --- a/radix-common/src/types/entity_type.rs +++ b/radix-common/src/types/entity_type.rs @@ -200,7 +200,7 @@ impl EntityType { matches!(self, EntityType::GlobalNonFungibleResourceManager) } - pub const fn is_global_virtual(&self) -> bool { + pub const fn is_global_preallocated(&self) -> bool { match self { EntityType::GlobalPreallocatedSecp256k1Account | EntityType::GlobalPreallocatedEd25519Account diff --git a/radix-common/src/types/node_and_substate.rs b/radix-common/src/types/node_and_substate.rs index 5434a263ffc..c9a82060439 100644 --- a/radix-common/src/types/node_and_substate.rs +++ b/radix-common/src/types/node_and_substate.rs @@ -96,8 +96,8 @@ impl NodeId { matches!(self.entity_type(), Some(t) if t.is_global_non_fungible_resource_manager()) } - pub const fn is_global_virtual(&self) -> bool { - matches!(self.entity_type(), Some(t) if t.is_global_virtual()) + pub const fn is_global_preallocated(&self) -> bool { + matches!(self.entity_type(), Some(t) if t.is_global_preallocated()) } pub const fn is_internal_kv_store(&self) -> bool { diff --git a/radix-engine/src/system/system_callback.rs b/radix-engine/src/system/system_callback.rs index a1c2ea9cf54..3798df09c1f 100644 --- a/radix-engine/src/system/system_callback.rs +++ b/radix-engine/src/system/system_callback.rs @@ -800,7 +800,7 @@ impl System { continue; } - if node_id.is_global_virtual() { + if node_id.is_global_preallocated() { // Allow global virtual and add reference global_addresses.insert(GlobalAddress::new_or_panic(node_id.clone().into())); continue; diff --git a/radix-transaction-scenarios/src/accounts.rs b/radix-transaction-scenarios/src/accounts.rs index b6af2f94f51..5ab6a75abc1 100644 --- a/radix-transaction-scenarios/src/accounts.rs +++ b/radix-transaction-scenarios/src/accounts.rs @@ -9,8 +9,8 @@ use crate::internal_prelude::ScenarioCore; /// /// # Warning /// -/// Any scenario that is run after genesis can not use virtual accounts as users could find private -/// key we're using (these are public private key anyway and we're not trying to hide them) and +/// Any scenario that is run after genesis can not use virtual accounts as users could find the private +/// key we're using (these are public and we're not trying to hide them) and /// change the account's settings or perhaps even the access rule of the account leading scenarios /// to fail. An allocated account **MUST** be used for any scenario that runs after genesis. pub struct PreallocatedAccount { diff --git a/radix-transaction-scenarios/src/runners/dumper.rs b/radix-transaction-scenarios/src/runners/dumper.rs index 7712baab160..c585f5f61fd 100644 --- a/radix-transaction-scenarios/src/runners/dumper.rs +++ b/radix-transaction-scenarios/src/runners/dumper.rs @@ -449,7 +449,6 @@ mod test { self.scenario_folder .put_file("scenario_summary.txt", summary); - self.scenario_folder.verify_no_extra_content_exists() } } @@ -480,10 +479,12 @@ mod test { ScenarioFilter::SpecificScenariosByName(btreeset!( scenario_logical_name.to_string() )), - &mut ScenarioDumpingHooks::new(scenario_folder), + &mut ScenarioDumpingHooks::new(scenario_folder.clone()), &mut (), &VmModules::default(), ); + + scenario_folder.verify_no_extra_content_exists(); } } } @@ -519,6 +520,36 @@ mod test { metadata.logical_name ); } + + fn on_scenario_ended(&mut self, event: OnScenarioEnded) { + let OnScenarioEnded { + metadata, + end_state, + .. + } = event; + if let Some(testnet_run_at) = metadata.testnet_run_at { + if testnet_run_at > ProtocolVersion::EARLIEST { + assert!( + metadata.safe_to_run_on_used_ledger, + "Scenario \"{}\" is set to run on non-Babylon testnets, but is not marked as `safe_to_run_on_used_ledger`. This could break stokenet. Change the scenario to not use pre-allocated addresses, and set `safe_to_run_on_used_ledger` to `true`.", + metadata.logical_name + ); + } + } + if metadata.safe_to_run_on_used_ledger { + for (address_name, address) in end_state.output.interesting_addresses.0.iter() { + if let DescribedAddress::Global(address) = address { + let entity_type = address.as_node_id().entity_type().unwrap(); + assert!( + !entity_type.is_global_preallocated(), + "Scenario \"{}\" is marked as `safe_to_run_on_used_ledger`, but its interesting address {} is pre-allocated - which suggests the scenario can be broken by someone messing with this address before the scenario runs. Change the scenario to explicitly create accounts/identities (see e.g. `maya-router.rs`).", + metadata.logical_name, + address_name, + ); + } + } + } + } } TransactionScenarioExecutor::new( InMemorySubstateDatabase::standard(), diff --git a/radix-transaction-scenarios/src/scenario.rs b/radix-transaction-scenarios/src/scenario.rs index e4c5fe4954b..381d811bf5f 100644 --- a/radix-transaction-scenarios/src/scenario.rs +++ b/radix-transaction-scenarios/src/scenario.rs @@ -379,6 +379,15 @@ pub struct ScenarioMetadata { /// Note that setting this will change the definition of the given protocol update, /// so shouldn't be changed once the protocol update is locked in. pub testnet_run_at: Option, + /// This setting should be `true` for new scenarios, because new scenarios should + /// not use pre-allocated account addresses which may already exist on-ledger, + /// which could break scenario execution. + /// + /// A test validates adherence to this: + /// * If `!safe_to_run_on_used_ledger` then `testnet_run_at` is not past genesis. + /// * If `safe_to_run_on_used_ledger` then pre-allocated account/identity addresses + /// do not appear in well-known addresses. + pub safe_to_run_on_used_ledger: bool, } pub trait ScenarioCreator: Sized + 'static + Send + Sync { diff --git a/radix-transaction-scenarios/src/scenarios/access_controller_v2.rs b/radix-transaction-scenarios/src/scenarios/access_controller_v2.rs index 24f34dd2bc8..61480d13118 100644 --- a/radix-transaction-scenarios/src/scenarios/access_controller_v2.rs +++ b/radix-transaction-scenarios/src/scenarios/access_controller_v2.rs @@ -50,6 +50,7 @@ impl ScenarioCreator for AccessControllerV2ScenarioCreator { logical_name: "access-controller-v2", protocol_min_requirement: ProtocolVersion::Bottlenose, testnet_run_at: Some(ProtocolVersion::Bottlenose), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/account_authorized_depositors.rs b/radix-transaction-scenarios/src/scenarios/account_authorized_depositors.rs index a27e5d15d80..29773cb8a5c 100644 --- a/radix-transaction-scenarios/src/scenarios/account_authorized_depositors.rs +++ b/radix-transaction-scenarios/src/scenarios/account_authorized_depositors.rs @@ -33,6 +33,7 @@ impl ScenarioCreator for AccountAuthorizedDepositorsScenarioCreator { logical_name: "account_authorized_depositors", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/account_locker.rs b/radix-transaction-scenarios/src/scenarios/account_locker.rs index 2c575c574c7..b7078f2f3cd 100644 --- a/radix-transaction-scenarios/src/scenarios/account_locker.rs +++ b/radix-transaction-scenarios/src/scenarios/account_locker.rs @@ -51,6 +51,7 @@ impl ScenarioCreator for AccountLockerScenarioCreator { logical_name: "account_locker", protocol_min_requirement: ProtocolVersion::Bottlenose, testnet_run_at: Some(ProtocolVersion::Bottlenose), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/fungible_resource.rs b/radix-transaction-scenarios/src/scenarios/fungible_resource.rs index 303b33efefe..871dc13ba16 100644 --- a/radix-transaction-scenarios/src/scenarios/fungible_resource.rs +++ b/radix-transaction-scenarios/src/scenarios/fungible_resource.rs @@ -37,6 +37,7 @@ impl ScenarioCreator for FungibleResourceScenarioCreator { logical_name: "fungible_resource", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/global_n_owned.rs b/radix-transaction-scenarios/src/scenarios/global_n_owned.rs index fa0a8180b96..6c3b9c3e2ae 100644 --- a/radix-transaction-scenarios/src/scenarios/global_n_owned.rs +++ b/radix-transaction-scenarios/src/scenarios/global_n_owned.rs @@ -16,6 +16,7 @@ impl ScenarioCreator for GlobalNOwnedScenarioCreator { logical_name: "global_n_owned", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/kv_store_with_remote_type.rs b/radix-transaction-scenarios/src/scenarios/kv_store_with_remote_type.rs index 6c95a979605..b2d2f55355d 100644 --- a/radix-transaction-scenarios/src/scenarios/kv_store_with_remote_type.rs +++ b/radix-transaction-scenarios/src/scenarios/kv_store_with_remote_type.rs @@ -16,6 +16,7 @@ impl ScenarioCreator for KVStoreScenarioCreator { logical_name: "kv_store_with_remote_type", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/max_transaction.rs b/radix-transaction-scenarios/src/scenarios/max_transaction.rs index 413235d0ca2..8b562b59ee1 100644 --- a/radix-transaction-scenarios/src/scenarios/max_transaction.rs +++ b/radix-transaction-scenarios/src/scenarios/max_transaction.rs @@ -16,6 +16,7 @@ impl ScenarioCreator for MaxTransactionScenarioCreator { logical_name: "max_transaction", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/maya_router.rs b/radix-transaction-scenarios/src/scenarios/maya_router.rs index bfd3f16087f..de0ce763516 100644 --- a/radix-transaction-scenarios/src/scenarios/maya_router.rs +++ b/radix-transaction-scenarios/src/scenarios/maya_router.rs @@ -47,6 +47,7 @@ impl ScenarioCreator for MayaRouterScenarioCreator { logical_name: "maya_router", protocol_min_requirement: ProtocolVersion::Bottlenose, testnet_run_at: Some(ProtocolVersion::Bottlenose), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/metadata.rs b/radix-transaction-scenarios/src/scenarios/metadata.rs index c357551d70f..64dc0771e47 100644 --- a/radix-transaction-scenarios/src/scenarios/metadata.rs +++ b/radix-transaction-scenarios/src/scenarios/metadata.rs @@ -44,6 +44,7 @@ impl ScenarioCreator for MetadataScenarioCreator { logical_name: "metadata", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/non_fungible_resource.rs b/radix-transaction-scenarios/src/scenarios/non_fungible_resource.rs index 995a39c8939..995821cb292 100644 --- a/radix-transaction-scenarios/src/scenarios/non_fungible_resource.rs +++ b/radix-transaction-scenarios/src/scenarios/non_fungible_resource.rs @@ -41,6 +41,7 @@ impl ScenarioCreator for NonFungibleResourceScenarioCreator { logical_name: "non_fungible_resource", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs b/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs index bd25057fe91..97d4331e912 100644 --- a/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs +++ b/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs @@ -36,6 +36,7 @@ impl ScenarioCreator for NonFungibleResourceWithRemoteTypeScenarioCreator { logical_name: "non_fungible_resource_with_remote_type", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/radiswap.rs b/radix-transaction-scenarios/src/scenarios/radiswap.rs index 637d502d302..042596b41d4 100644 --- a/radix-transaction-scenarios/src/scenarios/radiswap.rs +++ b/radix-transaction-scenarios/src/scenarios/radiswap.rs @@ -54,6 +54,7 @@ impl ScenarioCreator for RadiswapScenarioCreator { logical_name: "radiswap", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/royalties.rs b/radix-transaction-scenarios/src/scenarios/royalties.rs index 7d408c914fa..0b8a5eaa789 100644 --- a/radix-transaction-scenarios/src/scenarios/royalties.rs +++ b/radix-transaction-scenarios/src/scenarios/royalties.rs @@ -21,6 +21,7 @@ impl ScenarioCreator for RoyaltiesScenarioCreator { logical_name: "royalties", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: true, }; fn create_with_config_and_state( diff --git a/radix-transaction-scenarios/src/scenarios/transfer_xrd.rs b/radix-transaction-scenarios/src/scenarios/transfer_xrd.rs index afca31efd0b..11b498050d0 100644 --- a/radix-transaction-scenarios/src/scenarios/transfer_xrd.rs +++ b/radix-transaction-scenarios/src/scenarios/transfer_xrd.rs @@ -30,6 +30,7 @@ impl ScenarioCreator for TransferXrdScenarioCreator { logical_name: "transfer_xrd", protocol_min_requirement: ProtocolVersion::Babylon, testnet_run_at: Some(ProtocolVersion::Babylon), + safe_to_run_on_used_ledger: false, }; fn create_with_config_and_state(