diff --git a/radix-clis/src/replay/cmd_alloc_dump.rs b/radix-clis/src/replay/cmd_alloc_dump.rs index 9e3d63772b6..8b89b332f89 100644 --- a/radix-clis/src/replay/cmd_alloc_dump.rs +++ b/radix-clis/src/replay/cmd_alloc_dump.rs @@ -8,7 +8,6 @@ use radix_common::prelude::*; use radix_engine::vm::VmModules; use radix_engine_profiling::info_alloc::*; use radix_substate_store_impls::rocks_db_with_merkle_tree::RocksDBWithMerkleTreeSubstateStore; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use radix_transactions::prelude::*; use std::fs::File; @@ -139,9 +138,7 @@ impl TxnAllocDump { let execution_cost_units = receipt .fee_summary() .map(|x| x.total_execution_cost_units_consumed.clone()); - let database_updates = receipt - .into_state_updates() - .create_database_updates::(); + let database_updates = receipt.into_state_updates().create_database_updates(); database.commit(&database_updates); match validated.inner { ValidatedLedgerTransactionInner::User(tx) => { diff --git a/radix-clis/src/replay/cmd_execute.rs b/radix-clis/src/replay/cmd_execute.rs index 6772a0ef9c3..b0d77520028 100644 --- a/radix-clis/src/replay/cmd_execute.rs +++ b/radix-clis/src/replay/cmd_execute.rs @@ -7,7 +7,6 @@ use flume; use radix_common::prelude::*; use radix_engine::vm::VmModules; use radix_substate_store_impls::rocks_db_with_merkle_tree::RocksDBWithMerkleTreeSubstateStore; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use std::fs::File; use std::path::PathBuf; @@ -84,8 +83,7 @@ impl TxnExecute { trace, ); let state_updates = receipt.into_state_updates(); - let database_updates = - state_updates.create_database_updates::(); + let database_updates = state_updates.create_database_updates(); database.commit(&database_updates); let new_state_root_hash = database.get_current_root_hash(); diff --git a/radix-clis/src/replay/cmd_execute_in_memory.rs b/radix-clis/src/replay/cmd_execute_in_memory.rs index 91efe56b005..6ed78249c53 100644 --- a/radix-clis/src/replay/cmd_execute_in_memory.rs +++ b/radix-clis/src/replay/cmd_execute_in_memory.rs @@ -8,7 +8,6 @@ use radix_common::prelude::*; use radix_engine::vm::VmModules; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; use radix_substate_store_impls::state_tree_support::StateTreeUpdatingDatabase; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use std::fs::File; use std::path::PathBuf; @@ -96,8 +95,7 @@ impl TxnExecuteInMemory { trace, ); let state_updates = receipt.into_state_updates(); - let database_updates = - state_updates.create_database_updates::(); + let database_updates = state_updates.create_database_updates(); database.commit(&database_updates); let new_state_root_hash = database.get_current_root_hash(); diff --git a/radix-clis/src/replay/cmd_measure.rs b/radix-clis/src/replay/cmd_measure.rs index a1aa7e6a3e8..171ad78c492 100644 --- a/radix-clis/src/replay/cmd_measure.rs +++ b/radix-clis/src/replay/cmd_measure.rs @@ -7,7 +7,6 @@ use flume; use radix_common::prelude::*; use radix_engine::vm::*; use radix_substate_store_impls::rocks_db_with_merkle_tree::RocksDBWithMerkleTreeSubstateStore; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use radix_transactions::prelude::*; use std::fs::File; @@ -110,9 +109,7 @@ impl TxnMeasure { let finalization_cost_units = receipt .fee_summary() .map(|x| x.total_finalization_cost_units_consumed.clone()); - let database_updates = receipt - .into_state_updates() - .create_database_updates::(); + let database_updates = receipt.into_state_updates().create_database_updates(); database.commit(&database_updates); let tx_processing_time = tx_start_time.elapsed(); if let ValidatedLedgerTransactionInner::User(tx) = validated.inner { diff --git a/radix-clis/src/replay/cmd_sync.rs b/radix-clis/src/replay/cmd_sync.rs index 24fafbd9540..aa6aebb8a98 100644 --- a/radix-clis/src/replay/cmd_sync.rs +++ b/radix-clis/src/replay/cmd_sync.rs @@ -6,7 +6,6 @@ use flume::Sender; use radix_common::prelude::*; use radix_engine::vm::VmModules; use radix_substate_store_impls::rocks_db_with_merkle_tree::RocksDBWithMerkleTreeSubstateStore; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use radix_transactions::prelude::*; use rocksdb::{Direction, IteratorMode, Options, DB}; @@ -74,8 +73,7 @@ impl TxnSync { trace, ); let state_updates = receipt.into_state_updates(); - let database_updates = - state_updates.create_database_updates::(); + let database_updates = state_updates.create_database_updates(); let current_version = database.get_current_version(); let new_version = current_version + 1; diff --git a/radix-clis/src/resim/cmd_publish.rs b/radix-clis/src/resim/cmd_publish.rs index b5b48d7559b..ce9cdff7c01 100644 --- a/radix-clis/src/resim/cmd_publish.rs +++ b/radix-clis/src/resim/cmd_publish.rs @@ -10,11 +10,8 @@ use radix_engine_interface::blueprints::package::{ }; use radix_engine_interface::prelude::*; use radix_rust::ContextualDisplay; -use radix_substate_store_interface::interface::DatabaseUpdates; -use radix_substate_store_interface::{ - db_key_mapper::{DatabaseKeyMapper, SpreadPrefixKeyMapper}, - interface::*, -}; +use radix_substate_store_interface::db_key_mapper::*; +use radix_substate_store_interface::interface::*; use radix_substate_store_queries::typed_substate_layout::*; use std::ffi::OsStr; use std::fs; diff --git a/radix-clis/src/resim/cmd_show_ledger.rs b/radix-clis/src/resim/cmd_show_ledger.rs index 79bbd16bb8d..d8ca8e00eaf 100644 --- a/radix-clis/src/resim/cmd_show_ledger.rs +++ b/radix-clis/src/resim/cmd_show_ledger.rs @@ -5,10 +5,7 @@ use radix_common::time::Instant; use radix_common::time::UtcDateTime; use radix_engine_interface::blueprints::consensus_manager::*; use radix_substate_store_impls::rocks_db::RocksdbSubstateStore; -use radix_substate_store_interface::{ - db_key_mapper::{DatabaseKeyMapper, SpreadPrefixKeyMapper}, - interface::ListableSubstateDatabase, -}; +use radix_substate_store_interface::interface::*; use crate::resim::*; @@ -54,8 +51,7 @@ impl ShowLedger { let mut components: Vec = vec![]; let mut resources: Vec = vec![]; - for key in substate_db.list_partition_keys() { - let (node_id, _) = SpreadPrefixKeyMapper::from_db_partition_key(&key); + for (node_id, _) in substate_db.read_partition_keys() { if let Ok(address) = PackageAddress::try_from(node_id.as_ref()) { if !packages.contains(&address) { packages.push(address); diff --git a/radix-clis/src/resim/dumper.rs b/radix-clis/src/resim/dumper.rs index 5dabe36c443..cf70d79e21b 100644 --- a/radix-clis/src/resim/dumper.rs +++ b/radix-clis/src/resim/dumper.rs @@ -12,10 +12,7 @@ use radix_engine_interface::blueprints::resource::NON_FUNGIBLE_RESOURCE_MANAGER_ use radix_engine_interface::types::{BlueprintPartitionOffset, CollectionDescriptor}; use radix_engine_interface::{prelude::MetadataValue, types::PackagePartitionOffset}; use radix_rust::ContextualDisplay; -use radix_substate_store_interface::{ - db_key_mapper::{MappedSubstateDatabase, SpreadPrefixKeyMapper}, - interface::SubstateDatabase, -}; +use radix_substate_store_interface::interface::*; use radix_substate_store_queries::query::ResourceAccounter; use radix_substate_store_queries::typed_substate_layout::*; @@ -38,9 +35,10 @@ pub fn dump_package( ) -> Result<(), EntityDumpError> { let address_bech32_encoder = AddressBech32Encoder::new(&NetworkDefinition::simulator()); let (_, substate) = substate_db - .list_mapped::( - package_address.as_node_id(), + .list_map_values::( + package_address, PackagePartitionOffset::CodeOriginalCodeKeyValue.as_main_partition(), + None::, ) .next() .ok_or(EntityDumpError::PackageNotFound)?; diff --git a/radix-common/src/types/node_and_substate.rs b/radix-common/src/types/node_and_substate.rs index c9a82060439..ca883099d3e 100644 --- a/radix-common/src/types/node_and_substate.rs +++ b/radix-common/src/types/node_and_substate.rs @@ -246,6 +246,13 @@ pub enum SubstateKey { Sorted(SortedKey), } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum SubstateKeyRef<'a> { + Field(&'a FieldKey), + Map(&'a MapKey), + Sorted(&'a SortedKey), +} + impl SubstateKey { pub fn for_field(&self) -> Option<&FieldKey> { match self { @@ -274,6 +281,90 @@ impl SubstateKey { _ => None, } } + + pub fn as_ref(&self) -> SubstateKeyRef { + match self { + SubstateKey::Field(key) => SubstateKeyRef::Field(key), + SubstateKey::Map(key) => SubstateKeyRef::Map(key), + SubstateKey::Sorted(key) => SubstateKeyRef::Sorted(key), + } + } +} + +pub enum SubstateKeyOrRef<'a> { + Owned(SubstateKey), + Borrowed(SubstateKeyRef<'a>), +} + +impl<'a> SubstateKeyOrRef<'a> { + pub fn as_ref(&self) -> SubstateKeyRef<'_> { + match self { + SubstateKeyOrRef::Owned(key) => key.as_ref(), + SubstateKeyOrRef::Borrowed(key_ref) => *key_ref, + } + } +} + +pub trait ResolvableSubstateKey<'a>: Sized { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a>; +} + +impl<'a> ResolvableSubstateKey<'a> for &'a SubstateKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Borrowed(self.as_ref()) + } +} + +impl> ResolvableSubstateKey<'static> for T { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'static> { + SubstateKeyOrRef::Owned(self.into()) + } +} + +impl<'a> ResolvableSubstateKey<'a> for FieldKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Owned(SubstateKey::Field(self)) + } +} + +impl<'a> ResolvableSubstateKey<'a> for &'a FieldKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Field(self)) + } +} + +impl<'a> ResolvableSubstateKey<'a> for MapKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Owned(SubstateKey::Map(self)) + } +} + +impl<'a> ResolvableSubstateKey<'a> for &'a MapKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Map(self)) + } +} + +impl<'a> ResolvableSubstateKey<'a> for SortedKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Owned(SubstateKey::Sorted(self)) + } +} + +impl<'a> ResolvableSubstateKey<'a> for &'a SortedKey { + fn into_substate_key_or_ref(self) -> SubstateKeyOrRef<'a> { + SubstateKeyOrRef::Borrowed(SubstateKeyRef::Sorted(self)) + } +} + +pub trait ResolvableOptionalSubstateKey<'a> { + fn into_optional_substate_key_or_ref(self) -> Option>; +} + +impl<'a, T: ResolvableSubstateKey<'a>> ResolvableOptionalSubstateKey<'a> for Option { + fn into_optional_substate_key_or_ref(self) -> Option> { + self.map(|k| k.into_substate_key_or_ref()) + } } pub type FieldKey = u8; diff --git a/radix-engine-monkey-tests/tests/fuzz_kernel.rs b/radix-engine-monkey-tests/tests/fuzz_kernel.rs index 96979a8e7c8..bb995dce16c 100644 --- a/radix-engine-monkey-tests/tests/fuzz_kernel.rs +++ b/radix-engine-monkey-tests/tests/fuzz_kernel.rs @@ -9,17 +9,16 @@ use radix_engine::kernel::kernel_api::{ }; use radix_engine::kernel::kernel_callback_api::*; use radix_engine::system::checkers::KernelDatabaseChecker; -use radix_engine::track::{to_state_updates, CommitableSubstateStore, Track}; +use radix_engine::track::{CommitableSubstateStore, Track}; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::CommittableSubstateDatabase; use rand::Rng; use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaCha8Rng; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; -use scrypto_test::prelude::CreateDatabaseUpdates; +use scrypto_test::prelude::*; #[derive(Default)] struct TestCallFrameData; @@ -470,7 +469,7 @@ fn kernel_fuzz Vec>( let txn_hash = &seed.to_be_bytes().repeat(4)[..]; let mut id_allocator = IdAllocator::new(Hash(txn_hash.try_into().unwrap())); let mut substate_db = InMemorySubstateDatabase::standard(); - let mut track = Track::::new(&substate_db); + let mut track = Track::new(&substate_db); let mut callback = TestCallbackObject; let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut callback); @@ -489,9 +488,9 @@ fn kernel_fuzz Vec>( let result = track.finalize(); if let Ok((tracked_substates, _)) = result { - let (_, state_updates) = to_state_updates::(tracked_substates); + let (_, state_updates) = tracked_substates.to_state_updates(); - let database_updates = state_updates.create_database_updates::(); + let database_updates = state_updates.create_database_updates(); substate_db.commit(&database_updates); let mut checker = KernelDatabaseChecker::new(); checker.check_db(&substate_db).unwrap_or_else(|_| { diff --git a/radix-engine-profiling/src/rocks_db_metrics/mod.rs b/radix-engine-profiling/src/rocks_db_metrics/mod.rs index 6c981ed8e19..8fddde1ab9a 100644 --- a/radix-engine-profiling/src/rocks_db_metrics/mod.rs +++ b/radix-engine-profiling/src/rocks_db_metrics/mod.rs @@ -73,13 +73,13 @@ impl SubstateStoreWithMetrics { impl SubstateDatabase for SubstateStoreWithMetrics { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, ) -> Option { let start = std::time::Instant::now(); - let ret = self.db.get_substate(partition_key, sort_key); + let ret = self.db.get_raw_substate_by_db_key(partition_key, sort_key); let duration = start.elapsed(); if let Some(value) = ret { @@ -95,12 +95,13 @@ impl SubstateDatabase } } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, ) -> Box + '_> { - self.db.list_entries_from(partition_key, from_sort_key) + self.db + .list_raw_values_from_db_key(partition_key, from_sort_key) } } @@ -152,7 +153,7 @@ impl CommittableSubstateDatab ) } else { delete_found = true; - if let Some(value) = self.get_substate( + if let Some(value) = self.get_raw_substate_by_db_key( &DbPartitionKey { node_key: node_key.clone(), partition_num: *partition_num, diff --git a/radix-engine-profiling/src/rocks_db_metrics/tests/read.rs b/radix-engine-profiling/src/rocks_db_metrics/tests/read.rs index c550f60abf9..21ceb09d9aa 100644 --- a/radix-engine-profiling/src/rocks_db_metrics/tests/read.rs +++ b/radix-engine-profiling/src/rocks_db_metrics/tests/read.rs @@ -219,7 +219,7 @@ fn run_read_test( print!("\rRead {}/{} ", j + 1, data_index_vector.len()); std::io::stdout().flush().ok(); - let read_value = substate_db.get_substate(&p, &s); + let read_value = substate_db.get_raw_substate_by_db_key(&p, &s); assert!(read_value.is_some()); assert_eq!(read_value.unwrap().len(), *v); @@ -275,7 +275,7 @@ fn run_read_not_found_test( data_index_vector.shuffle(&mut rng); for (p, s) in data_index_vector.iter() { - let read_value = substate_db.get_substate(&p, &s); + let read_value = substate_db.get_raw_substate_by_db_key(&p, &s); assert!(read_value.is_none()); } } diff --git a/radix-engine-tests/tests/application/stake_reconciliation.rs b/radix-engine-tests/tests/application/stake_reconciliation.rs index 8784b57d449..06bdb270808 100644 --- a/radix-engine-tests/tests/application/stake_reconciliation.rs +++ b/radix-engine-tests/tests/application/stake_reconciliation.rs @@ -49,7 +49,7 @@ fn test_stake_reconciliation() { let db = ledger.substate_db(); let old_keys: Vec = db.list_partition_keys().collect(); for key in old_keys { - let entries = db.list_entries(&key); + let entries = db.list_raw_values_from_db_key(&key, None); for (sort_key, value) in entries { pre_transaction_substates.insert((key.clone(), sort_key), value); } @@ -89,7 +89,7 @@ fn test_stake_reconciliation() { // let partition_num = PartitionNumber(1); // let substate_key = SubstateKey::Map(ScryptoRawPayload::from_valid_payload(vec![92, 32, 7, 32, 220, 0, 156, 5, 6, 83, 96, 189, 222, 100, 29, 145, 160, 147, 193, 127, 71, 54, 135, 62, 103, 35, 126, 168, 230, 117, 203, 71, 36, 132, 155, 157])); // let value_from_database: ScryptoRawValue = ledger.substate_db() - // .get_mapped::(&node_id, partition_num, &substate_key) + // .read_substate_typed(&node_id, partition_num, substate_key) // .unwrap(); // let substate_value = value_from_database.into_payload_bytes(); // let state_updates = StateUpdates { @@ -327,7 +327,7 @@ fn test_stake_reconciliation() { } for key in post_transaction_partitions { - let partition_entries = ledger.substate_db().list_entries(&key); + let partition_entries = ledger.substate_db().list_raw_values_from_db_key(&key, None); for (sort_key, current_value) in partition_entries { let full_key = (key.clone(), sort_key.clone()); let address = AddressBech32Encoder::for_simulator() diff --git a/radix-engine-tests/tests/blueprints/account_locker.rs b/radix-engine-tests/tests/blueprints/account_locker.rs index 567eb77a928..91959debdb8 100644 --- a/radix-engine-tests/tests/blueprints/account_locker.rs +++ b/radix-engine-tests/tests/blueprints/account_locker.rs @@ -3055,7 +3055,7 @@ pub impl DefaultLedgerSimulator { execution_config.system_overrides = Some(SystemOverrides { disable_auth, disable_costing, - ..Default::default() + ..SystemOverrides::default_for_network(&NetworkDefinition::mainnet()) }); let nonce = self.next_transaction_nonce(); diff --git a/radix-engine-tests/tests/db/substate_database_overlay.rs b/radix-engine-tests/tests/db/substate_database_overlay.rs index d00c12f316d..26896cee8dd 100644 --- a/radix-engine-tests/tests/db/substate_database_overlay.rs +++ b/radix-engine-tests/tests/db/substate_database_overlay.rs @@ -1,11 +1,9 @@ -use radix_engine::system::system_db_reader::*; use radix_engine::transaction::*; use radix_engine::updates::*; use radix_engine::vm::NoExtension; use radix_engine::vm::VmModules; use radix_substate_store_impls::memory_db::*; use radix_substate_store_impls::substate_database_overlay::*; -use radix_substate_store_interface::db_key_mapper::*; use radix_substate_store_interface::interface::*; use radix_transaction_scenarios::executor::*; use radix_transactions::builder::*; @@ -35,7 +33,7 @@ fn substates_written_to_root_database_can_be_read() { let db = SubstateDatabaseOverlay::new_unmergeable(&root); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -70,7 +68,7 @@ fn substates_written_to_overlay_can_be_read_later() { }); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -118,7 +116,7 @@ fn substate_deletes_to_overlay_prevent_substate_from_being_read() { }); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -164,7 +162,7 @@ fn partition_deletes_to_overlay_prevent_substate_from_being_read() { }); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -212,7 +210,7 @@ fn partition_resets_to_overlay_return_new_substate_data() { }); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -271,7 +269,7 @@ fn partition_resets_are_not_combined() { }); // Act - let substate = db.get_substate( + let substate = db.get_raw_substate_by_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -306,7 +304,7 @@ fn from_sort_key_in_list_entries_from_works_when_the_overlay_is_in_reset_mode() }); // Act - let mut substates = db.list_entries_from( + let mut substates = db.list_raw_values_from_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -350,7 +348,7 @@ fn from_sort_key_in_list_entries_from_works_when_the_overlay_is_in_delta_mode() }); // Act - let mut substates = db.list_entries_from( + let mut substates = db.list_raw_values_from_db_key( &DbPartitionKey { node_key: b"some-node".to_vec(), partition_num: 0, @@ -441,16 +439,9 @@ fn create_database_contents_hash database: &D, ) -> Hash { let mut accumulator_hash = Hash([0; 32]); - let reader = SystemDatabaseReader::new(database); - for (node_id, partition_number) in reader.partitions_iter() { - let db_node_key = SpreadPrefixKeyMapper::to_db_node_key(&node_id); - let db_partition_key = DbPartitionKey { - node_key: db_node_key, - partition_num: partition_number.0, - }; - + for (node_id, partition_number) in database.read_partition_keys() { for (substate_key, substate_value) in - SubstateDatabase::list_entries(database, &db_partition_key) + database.list_raw_values(node_id, partition_number, None::) { let entry_hash = hash( scrypto_encode(&(node_id, partition_number, substate_key, substate_value)).unwrap(), @@ -505,7 +496,7 @@ fn run_scenarios_in_memory_and_on_overlay(check_callback: impl DatabaseCompariso let database_updates = receipt .expect_commit_success() .state_updates - .create_database_updates::(); + .create_database_updates(); self.ledger_with_overlay .borrow_mut() .substate_db_mut() diff --git a/radix-engine-tests/tests/kernel/kernel.rs b/radix-engine-tests/tests/kernel/kernel.rs index 249513f5f5a..46d5139dce2 100644 --- a/radix-engine-tests/tests/kernel/kernel.rs +++ b/radix-engine-tests/tests/kernel/kernel.rs @@ -5,10 +5,9 @@ use radix_engine::kernel::id_allocator::IdAllocator; use radix_engine::kernel::kernel::Kernel; use radix_engine::kernel::kernel_api::*; use radix_engine::kernel::kernel_callback_api::*; -use radix_engine::track::Track; +use radix_engine::track::*; use radix_engine_interface::prelude::*; -use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; +use scrypto_test::prelude::*; #[derive(Default)] struct TestCallFrameData; @@ -212,7 +211,7 @@ fn kernel_move_node_via_create_with_opened_substate( variation: MoveVariation, ) -> Result<(), RuntimeError> { let database = InMemorySubstateDatabase::standard(); - let mut track = Track::::new(&database); + let mut track = Track::new(&database); let mut id_allocator = IdAllocator::new(Hash([0u8; Hash::LENGTH])); let mut callback = TestCallbackObject; let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut callback); @@ -349,7 +348,7 @@ fn test_kernel_move_node_via_invoke_with_opened_substate() { fn kernel_close_substate_should_fail_if_opened_child_exists() { // Arrange let database = InMemorySubstateDatabase::standard(); - let mut track = Track::::new(&database); + let mut track = Track::new(&database); let mut id_allocator = IdAllocator::new(Hash([0u8; Hash::LENGTH])); let mut callback = TestCallbackObject; let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut callback); diff --git a/radix-engine-tests/tests/kernel/kernel_open_substate.rs b/radix-engine-tests/tests/kernel/kernel_open_substate.rs index 1a7abe51fd4..cb1ed8f0c33 100644 --- a/radix-engine-tests/tests/kernel/kernel_open_substate.rs +++ b/radix-engine-tests/tests/kernel/kernel_open_substate.rs @@ -21,7 +21,6 @@ use radix_engine::vm::*; use radix_engine_interface::api::LockFlags; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_queries::typed_substate_layout::{ BlueprintVersionKey, PACKAGE_AUTH_TEMPLATE_PARTITION_OFFSET, }; @@ -81,7 +80,7 @@ pub fn test_open_substate_of_invisible_package_address() { ), finalization: Default::default(), }; - let mut track = Track::::new(&database); + let mut track = Track::new(&database); let mut id_allocator = IdAllocator::new(executable.unique_seed_for_id_allocator()); let mut kernel = Kernel::new_no_refs(&mut track, &mut id_allocator, &mut system); diff --git a/radix-engine-tests/tests/kernel/panics.rs b/radix-engine-tests/tests/kernel/panics.rs index 9625fbfdedb..2e69c96a8a6 100644 --- a/radix-engine-tests/tests/kernel/panics.rs +++ b/radix-engine-tests/tests/kernel/panics.rs @@ -161,7 +161,7 @@ impl KernelSubstateApi for MockKernel( + fn kernel_scan_keys( &mut self, _: &NodeId, _: PartitionNumber, @@ -170,7 +170,7 @@ impl KernelSubstateApi for MockKernel( + fn kernel_drain_substates( &mut self, _: &NodeId, _: PartitionNumber, diff --git a/radix-engine-tests/tests/system/bootstrap.rs b/radix-engine-tests/tests/system/bootstrap.rs index 777971f9a96..18242553b06 100644 --- a/radix-engine-tests/tests/system/bootstrap.rs +++ b/radix-engine-tests/tests/system/bootstrap.rs @@ -13,9 +13,6 @@ use radix_engine::updates::{BabylonSettings, ProtocolBuilder}; use radix_engine_interface::object_modules::metadata::{MetadataValue, UncheckedUrl}; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_interface::db_key_mapper::{ - MappedSubstateDatabase, SpreadPrefixKeyMapper, -}; use radix_substate_store_queries::typed_substate_layout::*; use radix_transactions::prelude::*; use scrypto_test::prelude::*; @@ -268,10 +265,10 @@ fn test_genesis_resource_with_initial_allocation(owned_resource: bool) { } = hooks.into_genesis_receipts(); let total_supply = substate_db - .get_mapped::( - &resource_address.as_node_id(), + .get_substate::( + resource_address, MAIN_BASE_PARTITION, - &FungibleResourceManagerField::TotalSupply.into(), + FungibleResourceManagerField::TotalSupply, ) .unwrap() .into_payload() @@ -310,7 +307,7 @@ fn test_genesis_resource_with_initial_allocation(owned_resource: bool) { // check if the metadata exists and is locked let reader = SystemDatabaseReader::new(&substate_db); let substate = reader - .fetch_substate::>( + .fetch_substate::>( created_owner_badge.as_node_id(), METADATA_BASE_PARTITION, &SubstateKey::Map(scrypto_encode("tags").unwrap()), diff --git a/radix-engine-tests/tests/system/system_db_checker.rs b/radix-engine-tests/tests/system/system_db_checker.rs index 411f75a6192..a0b53903b85 100644 --- a/radix-engine-tests/tests/system/system_db_checker.rs +++ b/radix-engine-tests/tests/system/system_db_checker.rs @@ -5,7 +5,6 @@ use radix_engine::system::checkers::{ use radix_engine::updates::ProtocolBuilder; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; -use radix_substate_store_interface::db_key_mapper::{DatabaseKeyMapper, SpreadPrefixKeyMapper}; use radix_substate_store_interface::interface::*; #[test] @@ -15,20 +14,12 @@ fn system_database_checker_should_report_missing_owner_error_on_broken_db() { ProtocolBuilder::for_simulator() .from_bootstrap_to_latest() .commit_each_protocol_update(&mut substate_db); - let (node_key, partition_num, sort_key, update) = ( - SpreadPrefixKeyMapper::to_db_node_key(PACKAGE_PACKAGE.as_node_id()), - SpreadPrefixKeyMapper::to_db_partition_num( - ROLE_ASSIGNMENT_BASE_PARTITION - .at_offset(ROLE_ASSIGNMENT_FIELDS_PARTITION_OFFSET) - .unwrap(), - ), - SpreadPrefixKeyMapper::to_db_sort_key(&SubstateKey::Field(0u8)), - DatabaseUpdate::Delete, - ); - let remove_owner_update = DatabaseUpdates::from_delta_maps( - indexmap!(DbPartitionKey {node_key, partition_num} => indexmap!(sort_key => update)), + + substate_db.delete_substate( + PACKAGE_PACKAGE, + ROLE_ASSIGNMENT_FIELDS_PARTITION, + SubstateKey::Field(0u8), ); - substate_db.commit(&remove_owner_update); // Act let mut checker = SystemDatabaseChecker::<()>::default(); diff --git a/radix-engine-tests/tests/vm/native_vm.rs b/radix-engine-tests/tests/vm/native_vm.rs index babed4b38ef..030b5ab52db 100644 --- a/radix-engine-tests/tests/vm/native_vm.rs +++ b/radix-engine-tests/tests/vm/native_vm.rs @@ -22,7 +22,6 @@ use radix_engine_interface::blueprints::account::*; use radix_engine_interface::blueprints::test_utils::invocations::*; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::*; -use radix_substate_store_interface::db_key_mapper::*; use radix_transactions::prelude::*; use scrypto_test::prelude::LedgerSimulatorBuilder; @@ -61,7 +60,7 @@ fn panics_can_be_caught_in_the_native_vm_and_converted_into_results() { .from_bootstrap_to_latest() .commit_each_protocol_update(&mut substate_db); - let mut track = Track::::new(&substate_db); + let mut track = Track::new(&substate_db); let scrypto_vm = ScryptoVm::::default(); let native_vm = NativeVm::new_with_extension(Extension); @@ -132,7 +131,7 @@ fn any_panics_can_be_caught_in_the_native_vm_and_converted_into_results() { .from_bootstrap_to_latest() .commit_each_protocol_update(&mut substate_db); - let mut track = Track::::new(&substate_db); + let mut track = Track::new(&substate_db); let scrypto_vm = ScryptoVm::::default(); let native_vm = NativeVm::new_with_extension(NonStringPanicExtension); diff --git a/radix-engine/src/kernel/call_frame.rs b/radix-engine/src/kernel/call_frame.rs index 89195af425a..01bb6291e95 100644 --- a/radix-engine/src/kernel/call_frame.rs +++ b/radix-engine/src/kernel/call_frame.rs @@ -1220,7 +1220,7 @@ impl CallFrame { Ok(removed) } - pub fn scan_keys<'f, K: SubstateKeyContent + 'static, S: CommitableSubstateStore, E>( + pub fn scan_keys<'f, K: SubstateKeyContent, S: CommitableSubstateStore, E>( &mut self, substate_io: &'f mut SubstateIO, node_id: &NodeId, @@ -1251,7 +1251,7 @@ impl CallFrame { Ok(keys) } - pub fn drain_substates<'f, K: SubstateKeyContent + 'static, S: CommitableSubstateStore, E>( + pub fn drain_substates<'f, K: SubstateKeyContent, S: CommitableSubstateStore, E>( &mut self, substate_io: &'f mut SubstateIO, node_id: &NodeId, diff --git a/radix-engine/src/kernel/kernel.rs b/radix-engine/src/kernel/kernel.rs index 313d030f00b..e58ebbc2718 100644 --- a/radix-engine/src/kernel/kernel.rs +++ b/radix-engine/src/kernel/kernel.rs @@ -11,7 +11,7 @@ use crate::track::interface::*; use crate::track::Track; use radix_engine_interface::api::field_api::LockFlags; use radix_engine_profiling_derive::trace_resources; -use radix_substate_store_interface::db_key_mapper::{SpreadPrefixKeyMapper, SubstateKeyContent}; +use radix_substate_store_interface::db_key_mapper::SubstateKeyContent; use radix_substate_store_interface::interface::SubstateDatabase; use sbor::rust::mem; @@ -45,7 +45,7 @@ impl KernelBoot { /// Organizes the radix engine stack to make a function entrypoint available for execution pub struct BootLoader<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> { pub id_allocator: IdAllocator, - pub track: Track<'h, S, SpreadPrefixKeyMapper>, + pub track: Track<'h, S>, pub init: M::Init, pub phantom: PhantomData, } @@ -93,7 +93,7 @@ impl<'h, M: KernelTransactionCallbackObject, S: SubstateDatabase> BootLoader<'h, .unwrap_or(KernelBoot::babylon()); // Upper Layer Initialization - let system_init_result = M::init(&mut self.track, &executable, self.init.clone()); + let system_init_result = M::init(&mut self.track, &executable, self.init); let (mut system, call_frame_inits) = match system_init_result { Ok(success) => success, @@ -960,7 +960,7 @@ where } #[trace_resources] - fn kernel_scan_keys( + fn kernel_scan_keys( &mut self, node_id: &NodeId, partition_num: PartitionNumber, @@ -997,7 +997,7 @@ where } #[trace_resources(log=limit)] - fn kernel_drain_substates( + fn kernel_drain_substates( &mut self, node_id: &NodeId, partition_num: PartitionNumber, diff --git a/radix-engine/src/kernel/kernel_api.rs b/radix-engine/src/kernel/kernel_api.rs index 231b30abcb7..10809d37e08 100644 --- a/radix-engine/src/kernel/kernel_api.rs +++ b/radix-engine/src/kernel/kernel_api.rs @@ -135,14 +135,14 @@ pub trait KernelSubstateApi { count: u32, ) -> Result, RuntimeError>; - fn kernel_scan_keys( + fn kernel_scan_keys( &mut self, node_id: &NodeId, partition_num: PartitionNumber, count: u32, ) -> Result, RuntimeError>; - fn kernel_drain_substates( + fn kernel_drain_substates( &mut self, node_id: &NodeId, partition_num: PartitionNumber, diff --git a/radix-engine/src/kernel/kernel_callback_api.rs b/radix-engine/src/kernel/kernel_callback_api.rs index b2629490f6d..3b59a586b66 100644 --- a/radix-engine/src/kernel/kernel_callback_api.rs +++ b/radix-engine/src/kernel/kernel_callback_api.rs @@ -5,10 +5,9 @@ use crate::kernel::kernel_api::KernelInvocation; use crate::kernel::kernel_api::{KernelApi, KernelInternalApi}; use crate::kernel::substate_io::SubstateDevice; use crate::track::interface::{IOAccess, NodeSubstates}; -use crate::track::{BootStore, CommitableSubstateStore, StoreCommitInfo, Track}; +use crate::track::*; use crate::transaction::ResourcesUsage; use radix_engine_interface::api::field_api::LockFlags; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::SubstateDatabase; pub trait CallFrameReferences { @@ -140,7 +139,7 @@ pub trait ExecutionReceipt { pub trait KernelTransactionCallbackObject: KernelCallbackObject { /// Initialization object - type Init: Clone; + type Init; /// The transaction object type Executable; /// Output to be returned at the end of execution @@ -167,7 +166,7 @@ pub trait KernelTransactionCallbackObject: KernelCallbackObject { /// Create final receipt fn create_receipt( self, - track: Track, + track: Track, result: Result, ) -> Self::Receipt; } diff --git a/radix-engine/src/kernel/substate_io.rs b/radix-engine/src/kernel/substate_io.rs index 3129c7ca51d..0cce52e4be3 100644 --- a/radix-engine/src/kernel/substate_io.rs +++ b/radix-engine/src/kernel/substate_io.rs @@ -586,7 +586,7 @@ impl<'g, S: CommitableSubstateStore + 'g> SubstateIO<'g, S> { Ok(removed) } - pub fn scan_keys( + pub fn scan_keys( &mut self, device: SubstateDevice, node_id: &NodeId, @@ -607,7 +607,7 @@ impl<'g, S: CommitableSubstateStore + 'g> SubstateIO<'g, S> { Ok(keys) } - pub fn drain_substates( + pub fn drain_substates( &mut self, device: SubstateDevice, node_id: &NodeId, diff --git a/radix-engine/src/system/bootstrap.rs b/radix-engine/src/system/bootstrap.rs index 9cc6bf0db52..5d44622dd7d 100644 --- a/radix-engine/src/system/bootstrap.rs +++ b/radix-engine/src/system/bootstrap.rs @@ -27,9 +27,6 @@ use radix_engine_interface::object_modules::metadata::{MetadataValue, UncheckedU use radix_engine_interface::object_modules::ModuleConfig; use radix_engine_interface::*; use radix_substate_store_interface::interface::*; -use radix_substate_store_interface::{ - db_key_mapper::SpreadPrefixKeyMapper, interface::SubstateDatabase, -}; use radix_transactions::model::*; use radix_transactions::prelude::*; @@ -399,7 +396,7 @@ pub fn create_substate_flash_for_genesis() -> FlashReceipt { system_updates, }); let flashed_db = FlashedSubstateDatabase { - flash_updates: state_updates.create_database_updates::(), + flash_updates: state_updates.create_database_updates(), }; let mut substate_schema_mapper = SubstateSchemaMapper::new(SystemDatabaseReader::new(&flashed_db)); @@ -426,7 +423,7 @@ struct FlashedSubstateDatabase { } impl SubstateDatabase for FlashedSubstateDatabase { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -452,7 +449,7 @@ impl SubstateDatabase for FlashedSubstateDatabase { }) } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, diff --git a/radix-engine/src/system/checkers/kernel_db_checker.rs b/radix-engine/src/system/checkers/kernel_db_checker.rs index 7f5faa4404b..cf73dcfc551 100644 --- a/radix-engine/src/system/checkers/kernel_db_checker.rs +++ b/radix-engine/src/system/checkers/kernel_db_checker.rs @@ -1,9 +1,6 @@ use crate::internal_prelude::*; use radix_engine_interface::types::*; -use radix_substate_store_interface::db_key_mapper::DatabaseKeyMapper; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; -use radix_substate_store_interface::interface::ListableSubstateDatabase; -use radix_substate_store_interface::interface::SubstateDatabase; +use radix_substate_store_interface::interface::*; #[derive(Debug)] pub enum KernelDatabaseCheckError { @@ -34,9 +31,7 @@ impl KernelDatabaseChecker { ) -> Result<(), KernelDatabaseCheckError> { let mut internal_nodes = BTreeMap::new(); - for db_partition_key in substate_db.list_partition_keys() { - let (node_id, _) = SpreadPrefixKeyMapper::from_db_partition_key(&db_partition_key); - + for (node_id, partition_number) in substate_db.read_partition_keys() { let state = internal_nodes .entry(node_id) .or_insert(NodeCheckerState::NoOwner(0u8)); @@ -47,7 +42,9 @@ impl KernelDatabaseChecker { } } - for (_, value) in substate_db.list_entries(&db_partition_key) { + for (_, value) in + substate_db.list_raw_values(node_id, partition_number, None::) + { let value = IndexedScryptoValue::from_vec(value) .map_err(KernelDatabaseCheckError::DecodeError)?; for owned in value.owned_nodes() { diff --git a/radix-engine/src/system/checkers/system_db_checker.rs b/radix-engine/src/system/checkers/system_db_checker.rs index 03c0a370487..f8b7dc3bd94 100644 --- a/radix-engine/src/system/checkers/system_db_checker.rs +++ b/radix-engine/src/system/checkers/system_db_checker.rs @@ -82,7 +82,6 @@ pub enum SystemPartitionCheckError { MissingKeyValueStoreValueSchema(SystemReaderError), InvalidKeyValueStoreKey, InvalidKeyValueStoreValue, - InvalidFieldKey, ContainsFieldWhichShouldNotExist(BlueprintId, NodeId, u8), InvalidFieldValue, MissingFieldSchema(SystemReaderError), @@ -488,19 +487,16 @@ impl SystemDatabaseChecker { return Err(SystemPartitionCheckError::InvalidBootLoaderPartition); } - for _ in reader - .substates_iter::(&node_checker_state.node_id, partition_number) - { + for _ in reader.field_iter(&node_checker_state.node_id, partition_number) { substate_count += 1; } } SystemPartitionDescriptor::TypeInfo => { - for (key, value) in reader - .substates_iter::(&node_checker_state.node_id, partition_number) + for (key, value) in + reader.field_iter(&node_checker_state.node_id, partition_number) { - match key { - SubstateKey::Field(0u8) => {} - _ => return Err(SystemPartitionCheckError::InvalidTypeInfoKey), + if key != 0 { + return Err(SystemPartitionCheckError::InvalidTypeInfoKey); }; let _type_info: TypeInfoSubstate = scrypto_decode(&value) @@ -510,13 +506,9 @@ impl SystemDatabaseChecker { } } SystemPartitionDescriptor::Schema => { - for (key, value) in reader - .substates_iter::(&node_checker_state.node_id, partition_number) + for (map_key, value) in + reader.map_iter(&node_checker_state.node_id, partition_number) { - let map_key = match key { - SubstateKey::Map(map_key) => map_key, - _ => return Err(SystemPartitionCheckError::InvalidSchemaKey), - }; let _schema_hash: Hash = scrypto_decode(&map_key) .map_err(|_| SystemPartitionCheckError::InvalidSchemaKey)?; @@ -538,17 +530,11 @@ impl SystemDatabaseChecker { .get_kv_store_payload_schema(&type_target, KeyOrValue::Value) .map_err(SystemPartitionCheckError::MissingKeyValueStoreValueSchema)?; - for (key, value) in reader - .substates_iter::(&node_checker_state.node_id, partition_number) + for (map_key, value) in + reader.map_iter(&node_checker_state.node_id, partition_number) { // Key Check { - let map_key = match key { - SubstateKey::Map(map_key) => map_key, - _ => { - return Err(SystemPartitionCheckError::InvalidKeyValueStoreKey) - } - }; reader .validate_payload( &map_key, @@ -601,15 +587,9 @@ impl SystemDatabaseChecker { match object_partition_descriptor { ObjectPartitionDescriptor::Fields => { - for (key, value) in reader.substates_iter::( - &node_checker_state.node_id, - partition_number, - ) { - let field_index = match key { - SubstateKey::Field(field_index) => field_index, - _ => return Err(SystemPartitionCheckError::InvalidFieldKey), - }; - + for (field_index, value) in + reader.field_iter(&node_checker_state.node_id, partition_number) + { expected_fields.remove(&(module_id, field_index)); if module_id.eq(&ModuleId::Main) && excluded_fields.contains(&field_index) @@ -676,19 +656,11 @@ impl SystemDatabaseChecker { .map_err(SystemPartitionCheckError::MissingIndexCollectionValueSchema)? }; - for (key, value) in reader.substates_iter::( - &node_checker_state.node_id, - partition_number, - ) { + for (map_key, value) in + reader.map_iter(&node_checker_state.node_id, partition_number) + { // Key Check let key = { - let map_key = match key { - SubstateKey::Map(map_key) => map_key, - _ => return Err( - SystemPartitionCheckError::InvalidIndexCollectionKey, - ), - }; - reader .validate_payload( &map_key, @@ -760,18 +732,11 @@ impl SystemDatabaseChecker { .map_err(SystemPartitionCheckError::MissingKeyValueCollectionValueSchema)? }; - for (key, value) in reader.substates_iter::( - &node_checker_state.node_id, - partition_number, - ) { + for (map_key, value) in + reader.map_iter(&node_checker_state.node_id, partition_number) + { // Key check let key = { - let map_key = match key { - SubstateKey::Map(map_key) => map_key, - _ => return Err( - SystemPartitionCheckError::InvalidKeyValueCollectionKey, - ), - }; reader .validate_payload( &map_key, @@ -832,19 +797,11 @@ impl SystemDatabaseChecker { .map_err(SystemPartitionCheckError::MissingSortedIndexCollectionValueSchema)? }; - for (key, value) in reader.substates_iter::( - &node_checker_state.node_id, - partition_number, - ) { + for (sorted_key, value) in + reader.sorted_iter(&node_checker_state.node_id, partition_number) + { // Key Check let key = { - let sorted_key = match key { - SubstateKey::Sorted(sorted_key) => sorted_key, - _ => return Err( - SystemPartitionCheckError::InvalidSortedIndexCollectionKey, - ), - }; - reader.validate_payload( &sorted_key.1, &key_schema, diff --git a/radix-engine/src/system/system.rs b/radix-engine/src/system/system.rs index 3e806bd3142..3e8f415fcce 100644 --- a/radix-engine/src/system/system.rs +++ b/radix-engine/src/system/system.rs @@ -2979,7 +2979,7 @@ impl<'a, Y: SystemBasedKernelApi> KernelSubstateApi for SystemSe .kernel_scan_sorted_substates(node_id, partition_num, limit) } - fn kernel_scan_keys( + fn kernel_scan_keys( &mut self, node_id: &NodeId, partition_num: PartitionNumber, @@ -2989,7 +2989,7 @@ impl<'a, Y: SystemBasedKernelApi> KernelSubstateApi for SystemSe .kernel_scan_keys::(node_id, partition_num, limit) } - fn kernel_drain_substates( + fn kernel_drain_substates( &mut self, node_id: &NodeId, partition_num: PartitionNumber, diff --git a/radix-engine/src/system/system_callback.rs b/radix-engine/src/system/system_callback.rs index 5cdb80f4096..da36b1537c0 100644 --- a/radix-engine/src/system/system_callback.rs +++ b/radix-engine/src/system/system_callback.rs @@ -44,7 +44,7 @@ use radix_engine_interface::blueprints::hooks::*; use radix_engine_interface::blueprints::identity::IDENTITY_BLUEPRINT; use radix_engine_interface::blueprints::package::*; use radix_engine_interface::blueprints::transaction_processor::*; -use radix_substate_store_interface::{db_key_mapper::SpreadPrefixKeyMapper, interface::*}; +use radix_substate_store_interface::interface::*; use radix_transactions::model::*; pub const BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY: FieldKey = 1u8; @@ -66,7 +66,16 @@ pub enum SystemBoot { } impl SystemBoot { - fn system_logic(&self) -> VersionedSystemLogic { + pub fn babylon_genesis(network_definition: NetworkDefinition) -> Self { + SystemBoot::V1(SystemParameters { + network_definition, + costing_parameters: CostingParameters::babylon_genesis(), + costing_module_config: CostingModuleConfig::babylon_genesis(), + limit_parameters: LimitParameters::babylon_genesis(), + }) + } + + fn system_logic_version(&self) -> VersionedSystemLogic { match self { Self::V1(..) => VersionedSystemLogic::V1, Self::V2(logic, _) => *logic, @@ -244,24 +253,25 @@ impl>> SystemBa type SystemCallback = V; } -#[derive(Clone)] -pub struct SystemInit { +pub struct SystemInit { + pub self_init: SystemSelfInit, + pub callback_init: V, +} + +pub struct SystemSelfInit { // These fields only affect side effects and do not affect ledger state execution pub enable_kernel_trace: bool, pub enable_cost_breakdown: bool, pub execution_trace: Option, pub enable_debug_information: bool, - // Higher layer initialization object - pub callback_init: C, - // An override of system configuration pub system_overrides: Option, } -pub struct System { +pub struct System { pub versioned_system_logic: VersionedSystemLogic, - pub callback: C, + pub callback: V, pub blueprint_cache: NonIterMap>, pub schema_cache: NonIterMap>, pub auth_cache: NonIterMap, @@ -273,7 +283,7 @@ pub trait HasModules { fn modules_mut(&mut self) -> &mut SystemModuleMixer; } -impl HasModules for System { +impl HasModules for System { #[inline] fn modules_mut(&mut self) -> &mut SystemModuleMixer { &mut self.modules @@ -285,7 +295,7 @@ pub struct SystemFinalization { intent_nullifications: Vec, } -impl System { +impl System { fn on_move_node( node_id: &NodeId, is_moving_down: bool, @@ -334,7 +344,7 @@ impl System { } } -impl System { +impl System { #[cfg(not(feature = "alloc"))] fn print_executable(executable: &ExecutableTransaction) { println!("{:-^120}", "Executable"); @@ -483,7 +493,7 @@ impl System { } fn finalize_fees_for_commit( - track: &mut Track, + track: &mut Track, fee_reserve: SystemLoanFeeReserve, is_success: bool, ) -> ( @@ -734,7 +744,7 @@ impl System { } fn update_transaction_tracker( - track: &mut Track, + track: &mut Track, next_epoch: Epoch, intent_hash_nullification: IntentHashNullification, is_success: bool, @@ -1089,7 +1099,7 @@ impl System { fn create_commit_receipt( outcome: Result, RuntimeError>, - mut track: Track, + mut track: Track, modules: SystemModuleMixer, system_finalization: SystemFinalization, ) -> TransactionReceiptV1 { @@ -1150,8 +1160,7 @@ impl System { // Generate state updates from tracked substates // Note that this process will prune invalid reads - let (new_node_ids, state_updates) = - to_state_updates::(tracked_substates); + let (new_node_ids, state_updates) = tracked_substates.to_state_updates(); // Summarizes state updates let system_structure = @@ -1250,7 +1259,7 @@ impl System { fn resolve_modules( store: &mut impl BootStore, executable: &ExecutableTransaction, - init_input: &SystemInit, + init_input: SystemSelfInit, ) -> Result<(VersionedSystemLogic, SystemModuleMixer), TransactionReceiptV1> { let system_boot = store .read_boot_substate( @@ -1259,14 +1268,14 @@ impl System { &SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY), ) .map(|v| scrypto_decode(v.as_slice()).unwrap()) - .unwrap_or(SystemBoot::V1(SystemParameters { - network_definition: NetworkDefinition::mainnet(), - costing_parameters: CostingParameters::babylon_genesis(), - costing_module_config: CostingModuleConfig::babylon_genesis(), - limit_parameters: LimitParameters::babylon_genesis(), - })); - - let system_logic_version = system_boot.system_logic(); + .unwrap_or_else(|| { + let overrides = init_input.system_overrides.as_ref(); + let network_definition = overrides.and_then(|o| o.network_definition.as_ref()) + .expect("Before bottlenose, no SystemBoot substate exists, so a network_definition must be provided in the SystemOverrides of the ExecutionConfig."); + SystemBoot::babylon_genesis(network_definition.clone()) + }); + + let system_logic_version = system_boot.system_logic_version(); let mut system_parameters = match system_boot { SystemBoot::V1(system_parameters) | SystemBoot::V2(_, system_parameters) => { system_parameters @@ -1368,8 +1377,8 @@ impl System { } } -impl KernelTransactionCallbackObject for System { - type Init = SystemInit; +impl KernelTransactionCallbackObject for System { + type Init = SystemInit; type Executable = ExecutableTransaction; type ExecutionOutput = Vec; type Receipt = TransactionReceiptV1; @@ -1377,18 +1386,19 @@ impl KernelTransactionCallbackObject for System { fn init( store: &mut S, executable: &ExecutableTransaction, - init_input: SystemInit, + init_input: SystemInit, ) -> Result<(Self, Vec>), Self::Receipt> { // Dump executable #[cfg(not(feature = "alloc"))] - if init_input.enable_kernel_trace { + if init_input.self_init.enable_kernel_trace { Self::print_executable(executable); } - let (logic_version, mut modules) = Self::resolve_modules(store, executable, &init_input)?; + let (logic_version, mut modules) = + Self::resolve_modules(store, executable, init_input.self_init)?; // NOTE: Have to use match pattern rather than map_err to appease the borrow checker - let callback = match C::init(store, init_input.callback_init) { + let callback = match V::init(store, init_input.callback_init) { Ok(callback) => callback, Err(error) => return Err(Self::create_rejection_receipt(error, modules)), }; @@ -1559,7 +1569,7 @@ impl KernelTransactionCallbackObject for System { fn create_receipt( mut self, - track: Track, + track: Track, interpretation_result: Result, TransactionExecutionError>, ) -> TransactionReceipt { // Panic if an error is encountered in the system layer or below. The following code @@ -1598,7 +1608,7 @@ impl KernelTransactionCallbackObject for System { } } -impl KernelCallbackObject for System { +impl KernelCallbackObject for System { type LockData = SystemLockData; type CallFrameData = Actor; @@ -1804,7 +1814,7 @@ impl KernelCallbackObject for System { .expect("Schema should have validated this exists") .clone(); let output = - { C::invoke(&blueprint_id.package_address, export, input, &mut system)? }; + { V::invoke(&blueprint_id.package_address, export, input, &mut system)? }; // Validate output system.validate_blueprint_payload( @@ -1834,7 +1844,7 @@ impl KernelCallbackObject for System { // Input is not validated as they're created by system. // Invoke the export - let output = C::invoke( + let output = V::invoke( &blueprint_id.package_address, export.clone(), &input, diff --git a/radix-engine/src/system/system_db_reader.rs b/radix-engine/src/system/system_db_reader.rs index 1a64471ea11..ef72d26064f 100644 --- a/radix-engine/src/system/system_db_reader.rs +++ b/radix-engine/src/system/system_db_reader.rs @@ -2,20 +2,10 @@ use crate::internal_prelude::*; use radix_engine_interface::api::{AttachedModuleId, CollectionIndex, ModuleId}; use radix_engine_interface::blueprints::package::*; use radix_engine_interface::types::*; -use radix_substate_store_interface::db_key_mapper::{ - MappedCommittableSubstateDatabase, SubstateKeyContent, -}; -use radix_substate_store_interface::interface::{ - CommittableSubstateDatabase, ListableSubstateDatabase, -}; -use radix_substate_store_interface::{ - db_key_mapper::{DatabaseKeyMapper, MappedSubstateDatabase, SpreadPrefixKeyMapper}, - interface::SubstateDatabase, -}; +use radix_substate_store_interface::interface::*; use sbor::{validate_payload_against_schema, LocalTypeId, LocatedValidationError}; use crate::blueprints::package::PackageBlueprintVersionDefinitionEntrySubstate; -use crate::internal_prelude::{IndexEntrySubstate, SortedIndexEntrySubstate}; use crate::system::payload_validation::{SchemaOrigin, TypeInfoForValidation, ValidationContext}; use crate::system::system_substates::FieldSubstate; use crate::system::system_substates::KeyValueEntrySubstate; @@ -122,7 +112,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { } pub fn get_type_info(&self, node_id: &NodeId) -> Result { - self.fetch_substate::( + self.fetch_substate::( node_id, TYPE_INFO_FIELD_PARTITION, &TypeInfoField::TypeInfo.into(), @@ -134,20 +124,19 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { &self, package_address: PackageAddress, ) -> BTreeMap { - let entries = self.substate_db - .list_mapped::( + let entries = self + .substate_db + .list_map_values::( package_address.as_node_id(), MAIN_BASE_PARTITION .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET) .unwrap(), + None::, ); let mut blueprints = BTreeMap::new(); for (key, blueprint_definition) in entries { - let bp_version_key: BlueprintVersionKey = match key { - SubstateKey::Map(v) => scrypto_decode(&v).unwrap(), - _ => panic!("Unexpected"), - }; + let bp_version_key: BlueprintVersionKey = scrypto_decode(&key).unwrap(); blueprints.insert( bp_version_key, @@ -201,11 +190,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { let substate: FieldSubstate = self .substate_db - .get_mapped::( - node_id, - partition_number, - &SubstateKey::Field(field_index), - ) + .get_substate(node_id, partition_number, SubstateKey::Field(field_index)) .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?; Ok(( @@ -219,14 +204,13 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { node_id: &NodeId, key: &K, ) -> Option { - let substate = self - .substate_db - .get_mapped::>( + self.substate_db + .get_substate::>( node_id, MAIN_BASE_PARTITION, - &SubstateKey::Map(scrypto_encode(key).unwrap()), - ); - substate.and_then(|v| v.into_value()) + SubstateKey::Map(scrypto_encode(key).unwrap()), + ) + .and_then(|v| v.into_value()) } pub fn read_typed_object_field( @@ -259,11 +243,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { let substate: FieldSubstate = self .substate_db - .get_mapped::( - node_id, - partition_number, - &SubstateKey::Field(field_index), - ) + .get_substate(node_id, partition_number, SubstateKey::Field(field_index)) .ok_or_else(|| SystemReaderError::FieldDoesNotExist)?; Ok(substate.into_payload()) @@ -310,26 +290,26 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { let entry = match collection_key { ObjectCollectionKey::KeyValue(_, key) => self .substate_db - .get_mapped::>( + .get_substate::>( node_id, partition_number, - &SubstateKey::Map(scrypto_encode(key).unwrap()), + SubstateKey::Map(scrypto_encode(key).unwrap()), ) .and_then(|value| value.into_value()), ObjectCollectionKey::Index(_, key) => self .substate_db - .get_mapped::>( + .get_substate::>( node_id, partition_number, - &SubstateKey::Map(scrypto_encode(key).unwrap()), + SubstateKey::Map(scrypto_encode(key).unwrap()), ) .map(|value| value.into_value()), ObjectCollectionKey::SortedIndex(_, sort, key) => self .substate_db - .get_mapped::>( + .get_substate::>( node_id, partition_number, - &SubstateKey::Sorted((sort.to_be_bytes(), scrypto_encode(key).unwrap())), + SubstateKey::Sorted((sort.to_be_bytes(), scrypto_encode(key).unwrap())), ) .map(|value| value.into_value()), }; @@ -343,7 +323,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { from_key: Option<&MapKey>, ) -> Result)> + '_>, SystemReaderError> { if self.state_updates.is_some() { - panic!("substates_iter with overlay not supported."); + panic!("key_value_store_iter with overlay not supported."); } match self.get_type_info(node_id)? { @@ -351,27 +331,21 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { _ => return Err(SystemReaderError::NotAKeyValueStore), } - let partition_key = - SpreadPrefixKeyMapper::to_db_partition_key(node_id, MAIN_BASE_PARTITION); - - let from_key = from_key.map(|from_key| SpreadPrefixKeyMapper::map_to_db_sort_key(from_key)); - let iter = self + let iterable = self .substate_db - .list_entries_from(&partition_key, from_key.as_ref()) - .filter_map(move |entry| { - let substate_key = SpreadPrefixKeyMapper::from_db_sort_key::(&entry.0); - let key = match substate_key { - SubstateKey::Map(map_key) => map_key, - _ => panic!("Unexpected SubstateKey"), - }; - let value: KeyValueEntrySubstate = scrypto_decode(&entry.1).unwrap(); - let value = value.into_value()?; + .list_map_values::>( + node_id, + MAIN_BASE_PARTITION, + from_key, + ) + .filter_map(move |(map_key, substate)| { + let value = substate.into_value()?; let value = scrypto_encode(&value).unwrap(); - Some((key, value)) + Some((map_key, value)) }); - Ok(Box::new(iter)) + Ok(Box::new(iterable)) } pub fn collection_iter( @@ -384,21 +358,21 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { .map(|x| x.0) } - pub fn collection_iter_advanced( - &self, - node_id: &NodeId, + pub fn collection_iter_advanced<'s, 'x>( + &'s self, + node_id: &'x NodeId, module_id: ModuleId, collection_index: CollectionIndex, - from_substate_key: Option<&SubstateKey>, + from_substate_key: Option<&'x SubstateKey>, ) -> Result< ( - Box)> + '_>, + Box)> + 's>, PartitionNumber, ), SystemReaderError, > { if self.state_updates.is_some() { - panic!("substates_iter with overlay not supported."); + panic!("collection_iter_advanced with overlay not supported."); } let blueprint_id = self.get_blueprint_id(node_id, module_id)?; @@ -419,38 +393,58 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { } }; - let partition_key = SpreadPrefixKeyMapper::to_db_partition_key(node_id, partition_number); - let from_sort_key = from_substate_key - .map(|substate_key| SpreadPrefixKeyMapper::to_db_sort_key(substate_key)); - let iter = self - .substate_db - .list_entries_from(&partition_key, from_sort_key.as_ref()) - .filter_map(move |entry| { - let key = match schema { - BlueprintCollectionSchema::KeyValueStore(..) - | BlueprintCollectionSchema::Index(..) => { - SpreadPrefixKeyMapper::from_db_sort_key::(&entry.0) - } - BlueprintCollectionSchema::SortedIndex(..) => { - SpreadPrefixKeyMapper::from_db_sort_key::(&entry.0) - } - }; - - let value = match schema { - BlueprintCollectionSchema::KeyValueStore(..) => { - let value: KeyValueEntrySubstate = - scrypto_decode(&entry.1).unwrap(); - let value = value.into_value()?; - scrypto_encode(&value).unwrap() - } - BlueprintCollectionSchema::SortedIndex(..) - | BlueprintCollectionSchema::Index(..) => entry.1, - }; - - Some((key, value)) - }); + let iterable: Box)> + 's> = match schema { + BlueprintCollectionSchema::KeyValueStore(..) => { + let iterable = self + .substate_db + .list_map_values::>( + node_id, + partition_number, + from_substate_key, + ) + .filter_map(|(map_key, substate)| { + Some(( + SubstateKey::Map(map_key), + scrypto_encode(&substate.into_value()?).unwrap(), + )) + }); + Box::new(iterable) + } + BlueprintCollectionSchema::Index(..) => { + let iterable = self + .substate_db + .list_map_values::>( + node_id, + partition_number, + from_substate_key, + ) + .map(|(map_key, substate)| { + ( + SubstateKey::Map(map_key), + scrypto_encode(&substate.into_value()).unwrap(), + ) + }); + Box::new(iterable) + } + BlueprintCollectionSchema::SortedIndex(..) => { + let iterable = self + .substate_db + .list_sorted_values::>( + node_id, + partition_number, + from_substate_key, + ) + .map(|(key, substate)| { + ( + SubstateKey::Sorted(key), + scrypto_encode(&substate.into_value()).unwrap(), + ) + }); + Box::new(iterable) + } + }; - Ok((Box::new(iter), partition_number)) + Ok((iterable, partition_number)) } pub fn get_object_info>( @@ -458,7 +452,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { node_id: A, ) -> Result { let type_info = self - .fetch_substate::( + .fetch_substate::( &node_id.into(), TYPE_INFO_FIELD_PARTITION, &TypeInfoField::TypeInfo.into(), @@ -477,7 +471,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { module_id: ModuleId, ) -> Result { let type_info = self - .fetch_substate::( + .fetch_substate::( node_id, TYPE_INFO_FIELD_PARTITION, &TypeInfoField::TypeInfo.into(), @@ -524,14 +518,19 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { } let bp_version_key = BlueprintVersionKey::new_default(blueprint_id.blueprint_name.clone()); - let definition = Rc::new(self - .fetch_substate::( + let definition = Rc::new( + self.fetch_substate::( blueprint_id.package_address.as_node_id(), MAIN_BASE_PARTITION .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET) .unwrap(), &SubstateKey::Map(scrypto_encode(&bp_version_key).unwrap()), - ).ok_or_else(|| SystemReaderError::BlueprintDoesNotExist)?.into_value().unwrap().fully_update_and_into_latest_version()); + ) + .ok_or_else(|| SystemReaderError::BlueprintDoesNotExist)? + .into_value() + .unwrap() + .fully_update_and_into_latest_version(), + ); self.blueprint_cache .borrow_mut() @@ -545,7 +544,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { node_id: &NodeId, ) -> Result { let type_info = self - .fetch_substate::( + .fetch_substate::( node_id, TYPE_INFO_FIELD_PARTITION, &TypeInfoField::TypeInfo.into(), @@ -569,7 +568,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { module_id: ModuleId, ) -> Result { let type_info = self - .fetch_substate::( + .fetch_substate::( node_id, TYPE_INFO_FIELD_PARTITION, &TypeInfoField::TypeInfo.into(), @@ -804,14 +803,16 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { } } - let schema = Rc::new(self - .fetch_substate::>( + let schema = Rc::new( + self.fetch_substate::>( node_id, SCHEMAS_PARTITION, &SubstateKey::Map(scrypto_encode(schema_hash).unwrap()), ) - .ok_or_else(|| SystemReaderError::SchemaDoesNotExist)?.into_value() - .expect("Schema should exist if substate exists")); + .ok_or_else(|| SystemReaderError::SchemaDoesNotExist)? + .into_value() + .expect("Schema should exist if substate exists"), + ); self.schema_cache .borrow_mut() @@ -850,7 +851,7 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { ) -> Result { let bp_version_key = BlueprintVersionKey::new_default(blueprint_id.blueprint_name.clone()); let definition = self - .fetch_substate::( + .fetch_substate::( blueprint_id.package_address.as_node_id(), MAIN_BASE_PARTITION .at_offset(PACKAGE_BLUEPRINTS_PARTITION_OFFSET) @@ -888,34 +889,34 @@ impl<'a, S: SubstateDatabase + ?Sized> SystemDatabaseReader<'a, S> { ) } - pub fn fetch_substate( + pub fn fetch_substate( &self, node_id: &NodeId, partition_num: PartitionNumber, key: &SubstateKey, ) -> Option { if let Some(result) = - self.fetch_substate_from_state_updates::(node_id, partition_num, key) + self.fetch_substate_from_state_updates::(node_id, partition_num, key) { // If result can be determined from the state updates. result } else { // Otherwise, read from the substate database. - self.fetch_substate_from_database::(node_id, partition_num, key) + self.fetch_substate_from_database::(node_id, partition_num, key) } } - pub fn fetch_substate_from_database( + pub fn fetch_substate_from_database( &self, node_id: &NodeId, partition_num: PartitionNumber, key: &SubstateKey, ) -> Option { self.substate_db - .get_mapped::(node_id, partition_num, key) + .get_substate::(node_id, partition_num, key) } - pub fn fetch_substate_from_state_updates( + pub fn fetch_substate_from_state_updates( &self, node_id: &NodeId, partition_num: PartitionNumber, @@ -1097,22 +1098,40 @@ impl<'a, S: SubstateDatabase> SystemDatabaseReader<'a, S> { Ok(descriptors) } - pub fn substates_iter( + pub fn field_iter( &self, node_id: &NodeId, partition_number: PartitionNumber, - ) -> Box)> + '_> { + ) -> Box)> + '_> { if self.state_updates.is_some() { - panic!("substates_iter with overlay not supported."); + panic!("fields_iter with overlay not supported."); } + self.substate_db + .list_field_raw_values(node_id, partition_number, None::) + } - let partition_key = SpreadPrefixKeyMapper::to_db_partition_key(node_id, partition_number); - let iter = self.substate_db.list_entries(&partition_key).map(|entry| { - let substate_key = SpreadPrefixKeyMapper::from_db_sort_key::(&entry.0); - (substate_key, entry.1) - }); + pub fn map_iter( + &self, + node_id: &NodeId, + partition_number: PartitionNumber, + ) -> Box)> + '_> { + if self.state_updates.is_some() { + panic!("map_iter with overlay not supported."); + } + self.substate_db + .list_map_raw_values(node_id, partition_number, None::) + } - Box::new(iter) + pub fn sorted_iter( + &self, + node_id: &NodeId, + partition_number: PartitionNumber, + ) -> Box)> + '_> { + if self.state_updates.is_some() { + panic!("sorted_iter with overlay not supported."); + } + self.substate_db + .list_sorted_raw_values(node_id, partition_number, None::) } } @@ -1169,11 +1188,7 @@ impl<'a, S: SubstateDatabase + ListableSubstateDatabase> SystemDatabaseReader<'a panic!("partitions_iter with overlay not supported."); } - let iter = self.substate_db.list_partition_keys().map(|partition_key| { - let canonical_partition = SpreadPrefixKeyMapper::from_db_partition_key(&partition_key); - canonical_partition - }); - Box::new(iter) + self.substate_db.read_partition_keys() } } @@ -1216,11 +1231,11 @@ impl<'a, S: SubstateDatabase + CommittableSubstateDatabase> SystemDatabaseWriter PartitionDescription::Physical(partition_number) => *partition_number, }; - self.substate_db.put_mapped::( + self.substate_db.update_substate_typed( node_id, partition_number, - &SubstateKey::Field(field_index), - &FieldSubstate::new_field(value, LockStatus::Unlocked), + SubstateKey::Field(field_index), + FieldSubstate::new_field(value, LockStatus::Unlocked), ); Ok(()) diff --git a/radix-engine/src/system/system_type_checker.rs b/radix-engine/src/system/system_type_checker.rs index 69eef11c6a8..b254e248d22 100644 --- a/radix-engine/src/system/system_type_checker.rs +++ b/radix-engine/src/system/system_type_checker.rs @@ -459,7 +459,7 @@ impl SystemMapper { FieldTransience::NotTransient => {} } - let payload: ScryptoValue = + let value: ScryptoRawValue = scrypto_decode(&field.value).expect("Checked by payload-schema validation"); let lock_status = if field.locked { @@ -468,7 +468,7 @@ impl SystemMapper { LockStatus::Unlocked }; - let substate = FieldSubstate::new_field(payload, lock_status); + let substate = FieldSubstate::new_field(value, lock_status); let value = IndexedScryptoValue::from_typed(&substate); field_partition.insert(SubstateKey::Field(index), value); @@ -490,7 +490,7 @@ impl SystemMapper { for (key, kv_entry) in substates { let kv_entry = if let Some(value) = kv_entry.value { - let value: ScryptoValue = scrypto_decode(&value).unwrap(); + let value: ScryptoRawValue = scrypto_decode(&value).unwrap(); let kv_entry = if kv_entry.locked { KeyValueEntrySubstate::locked_entry(value) } else { diff --git a/radix-engine/src/track/interface.rs b/radix-engine/src/track/interface.rs index 162b0c33083..b58f7eec5ed 100644 --- a/radix-engine/src/track/interface.rs +++ b/radix-engine/src/track/interface.rs @@ -149,7 +149,7 @@ pub trait CommitableSubstateStore { /// Otherwise, behavior is undefined. /// /// Returns list of substate keys and database access info - fn scan_keys Result<(), E>>( + fn scan_keys Result<(), E>>( &mut self, node_id: &NodeId, partition_num: PartitionNumber, @@ -165,7 +165,7 @@ pub trait CommitableSubstateStore { /// Otherwise, behavior is undefined. /// /// Returns list of removed substates with their associated keys and values, as well as database access info - fn drain_substates Result<(), E>>( + fn drain_substates Result<(), E>>( &mut self, node_id: &NodeId, partition_num: PartitionNumber, diff --git a/radix-engine/src/track/state_updates.rs b/radix-engine/src/track/state_updates.rs index 61da85ca1a3..a7112539c64 100644 --- a/radix-engine/src/track/state_updates.rs +++ b/radix-engine/src/track/state_updates.rs @@ -1,8 +1,6 @@ use crate::internal_prelude::*; use radix_rust::rust::{iter::*, mem}; -use radix_substate_store_interface::{db_key_mapper::DatabaseKeyMapper, interface::DbSortKey}; - -use super::TrackedSubstates; +use radix_substate_store_interface::interface::*; #[derive(Clone, Debug)] pub struct RuntimeSubstate { @@ -258,48 +256,6 @@ impl TrackedNode { } } -pub fn to_state_updates( - tracked: TrackedSubstates, -) -> (IndexSet, StateUpdates) { - let mut new_nodes = index_set_new(); - let mut system_updates = index_map_new(); - for (node_id, tracked_node) in tracked.tracked_nodes { - if tracked_node.is_new { - new_nodes.insert(node_id); - } - - for (partition_num, tracked_partition) in tracked_node.tracked_partitions { - let mut partition_updates = index_map_new(); - for tracked in tracked_partition.substates.into_values() { - let update = match tracked.substate_value { - TrackedSubstateValue::ReadOnly(..) | TrackedSubstateValue::Garbage => None, - TrackedSubstateValue::ReadNonExistAndWrite(substate) - | TrackedSubstateValue::New(substate) => { - Some(DatabaseUpdate::Set(substate.value.into())) - } - TrackedSubstateValue::ReadExistAndWrite(_, write) - | TrackedSubstateValue::WriteOnly(write) => match write { - Write::Delete => Some(DatabaseUpdate::Delete), - Write::Update(substate) => Some(DatabaseUpdate::Set(substate.value.into())), - }, - }; - if let Some(update) = update { - partition_updates.insert(tracked.substate_key, update); - } - } - system_updates.insert((node_id.clone(), partition_num), partition_updates); - } - } - - ( - new_nodes, - StateUpdates::from(LegacyStateUpdates { - partition_deletions: tracked.deleted_partitions, - system_updates, - }), - ) -} - pub struct IterationCountedIter<'a, E> { pub iter: Box> + 'a>, diff --git a/radix-engine/src/track/track.rs b/radix-engine/src/track/track.rs index ca14e451992..4e3e19dae6f 100644 --- a/radix-engine/src/track/track.rs +++ b/radix-engine/src/track/track.rs @@ -6,7 +6,7 @@ use crate::track::interface::{ use crate::track::state_updates::*; use crate::track::BootStore; use radix_engine_interface::types::*; -use radix_substate_store_interface::db_key_mapper::SubstateKeyContent; +use radix_substate_store_interface::db_key_mapper::{SpreadPrefixKeyMapper, SubstateKeyContent}; use radix_substate_store_interface::interface::DbPartitionKey; use radix_substate_store_interface::{ db_key_mapper::DatabaseKeyMapper, @@ -23,8 +23,10 @@ pub enum TrackFinalizeError { TransientSubstateOwnsNode, } +pub type Track<'s, S> = MappedTrack<'s, S, SpreadPrefixKeyMapper>; + /// Transaction-wide states and side effects -pub struct Track<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> { +pub struct MappedTrack<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> { /// Substate database, use `get_substate_from_db` and `list_entries_from_db` for access substate_db: &'s S, @@ -38,7 +40,7 @@ pub struct Track<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> { phantom_data: PhantomData, } -impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> BootStore for Track<'s, S, M> { +impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> BootStore for MappedTrack<'s, S, M> { fn read_boot_substate( &self, node_id: &NodeId, @@ -49,7 +51,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> BootStore for Trac let db_sort_key = M::to_db_sort_key(&substate_key); self.substate_db - .get_substate(&db_partition_key, &db_sort_key) + .get_raw_substate_by_db_key(&db_partition_key, &db_sort_key) .map(|e| IndexedScryptoValue::from_vec(e).expect("Failed to decode substate")) } } @@ -62,7 +64,51 @@ pub struct TrackedSubstates { pub deleted_partitions: IndexSet<(NodeId, PartitionNumber)>, } -impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { +impl TrackedSubstates { + pub fn to_state_updates(self) -> (IndexSet, StateUpdates) { + let mut new_nodes = index_set_new(); + let mut system_updates = index_map_new(); + for (node_id, tracked_node) in self.tracked_nodes { + if tracked_node.is_new { + new_nodes.insert(node_id); + } + + for (partition_num, tracked_partition) in tracked_node.tracked_partitions { + let mut partition_updates = index_map_new(); + for tracked in tracked_partition.substates.into_values() { + let update = match tracked.substate_value { + TrackedSubstateValue::ReadOnly(..) | TrackedSubstateValue::Garbage => None, + TrackedSubstateValue::ReadNonExistAndWrite(substate) + | TrackedSubstateValue::New(substate) => { + Some(DatabaseUpdate::Set(substate.value.into())) + } + TrackedSubstateValue::ReadExistAndWrite(_, write) + | TrackedSubstateValue::WriteOnly(write) => match write { + Write::Delete => Some(DatabaseUpdate::Delete), + Write::Update(substate) => { + Some(DatabaseUpdate::Set(substate.value.into())) + } + }, + }; + if let Some(update) = update { + partition_updates.insert(tracked.substate_key, update); + } + } + system_updates.insert((node_id.clone(), partition_num), partition_updates); + } + } + + ( + new_nodes, + StateUpdates::from(LegacyStateUpdates { + partition_deletions: self.deleted_partitions, + system_updates, + }), + ) + } +} + +impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper> MappedTrack<'s, S, M> { pub fn new(substate_db: &'s S) -> Self { Self { substate_db, @@ -83,7 +129,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { canonical_substate_key: CanonicalSubstateKey, ) -> Result, E> { let result = substate_db - .get_substate(partition_key, sort_key) + .get_raw_substate_by_db_key(partition_key, sort_key) .map(|e| IndexedScryptoValue::from_vec(e).expect("Failed to decode substate")); if let Some(x) = &result { on_io_access(IOAccess::ReadFromDb(canonical_substate_key, x.len()))?; @@ -98,7 +144,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { 'x, E: 'x, F: FnMut(IOAccess) -> Result<(), E> + 'x, - K: SubstateKeyContent + 'static, + K: SubstateKeyContent, >( substate_db: &'x S, partition_key: &DbPartitionKey, @@ -111,7 +157,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { E, F: FnMut(IOAccess) -> Result<(), E>, M: DatabaseKeyMapper + 'static, - K: SubstateKeyContent + 'static, + K: SubstateKeyContent, > { iterator: Box + 'a>, on_io_access: &'a mut F, @@ -126,7 +172,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { E, F: FnMut(IOAccess) -> Result<(), E>, M: DatabaseKeyMapper + 'static, - K: SubstateKeyContent + 'static, + K: SubstateKeyContent, > Iterator for TracedIterator<'a, E, F, M, K> { type Item = Result<(DbSortKey, (SubstateKey, IndexedScryptoValue)), E>; @@ -160,7 +206,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { } Box::new(TracedIterator { - iterator: substate_db.list_entries(partition_key), + iterator: substate_db.list_raw_values_from_db_key(partition_key, None), on_io_access, canonical_partition, errored_out: false, @@ -338,8 +384,8 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> Track<'s, S, M> { } } -impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> CommitableSubstateStore - for Track<'s, S, M> +impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper> CommitableSubstateStore + for MappedTrack<'s, S, M> { fn mark_as_transient( &mut self, @@ -571,7 +617,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> CommitableSubstate Ok(taken) } - fn scan_keys Result<(), E>>( + fn scan_keys Result<(), E>>( &mut self, node_id: &NodeId, partition_number: PartitionNumber, @@ -644,7 +690,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> CommitableSubstate Ok(items) } - fn drain_substates Result<(), E>>( + fn drain_substates Result<(), E>>( &mut self, node_id: &NodeId, partition_number: PartitionNumber, @@ -911,7 +957,7 @@ impl<'s, S: SubstateDatabase, M: DatabaseKeyMapper + 'static> CommitableSubstate TrackedSubstateValue::WriteOnly(write) => { let old_size = self .substate_db - .get_substate( + .get_raw_substate_by_db_key( &M::to_db_partition_key(node_id, *partition_number), db_sort_key, ) diff --git a/radix-engine/src/transaction/state_update_summary.rs b/radix-engine/src/transaction/state_update_summary.rs index c823e6bf283..e0342b8073a 100644 --- a/radix-engine/src/transaction/state_update_summary.rs +++ b/radix-engine/src/transaction/state_update_summary.rs @@ -4,10 +4,7 @@ use crate::system::system_db_reader::SystemDatabaseReader; use radix_common::data::scrypto::model::*; use radix_common::math::*; use radix_engine_interface::types::*; -use radix_substate_store_interface::db_key_mapper::DatabaseKeyMapper; -use radix_substate_store_interface::{ - db_key_mapper::SpreadPrefixKeyMapper, interface::SubstateDatabase, -}; +use radix_substate_store_interface::interface::*; use sbor::rust::prelude::*; #[derive(Default, Debug, Clone, ScryptoSbor, PartialEq, Eq)] @@ -80,13 +77,7 @@ impl StateUpdateSummary { return false; } let node_previously_existed = base_substate_db - .get_substate( - &SpreadPrefixKeyMapper::to_db_partition_key( - node_id, - type_id_partition_number, - ), - &SpreadPrefixKeyMapper::to_db_sort_key(&type_id_substate_key), - ) + .get_raw_substate(node_id, type_id_partition_number, type_id_substate_key) .is_some(); return !node_previously_existed; }) @@ -249,7 +240,7 @@ impl<'a, S: SubstateDatabase> BalanceAccounter<'a, S> { fn calculate_fungible_vault_balance_change(&self, vault_id: &NodeId) -> Option { self .system_reader - .fetch_substate::>( + .fetch_substate::>( vault_id, MAIN_BASE_PARTITION, &FungibleVaultField::Balance.into(), @@ -258,7 +249,7 @@ impl<'a, S: SubstateDatabase> BalanceAccounter<'a, S> { .map(|new_balance| { let old_balance = self .system_reader - .fetch_substate_from_database::>( + .fetch_substate_from_database::>( vault_id, MAIN_BASE_PARTITION, &FungibleVaultField::Balance.into(), @@ -295,9 +286,9 @@ impl<'a, S: SubstateDatabase> BalanceAccounter<'a, S> { for (substate_key, substate_update) in by_substate { let id: NonFungibleLocalId = scrypto_decode(substate_key.for_map().unwrap()).unwrap(); - let previous_value = self + let previous_value = self .system_reader - .fetch_substate_from_database::( + .fetch_substate_from_database::( vault_id, partition_num, substate_key, diff --git a/radix-engine/src/transaction/transaction_executor.rs b/radix-engine/src/transaction/transaction_executor.rs index 57a79302e82..4378674a390 100644 --- a/radix-engine/src/transaction/transaction_executor.rs +++ b/radix-engine/src/transaction/transaction_executor.rs @@ -3,14 +3,14 @@ use crate::internal_prelude::*; use crate::kernel::id_allocator::IdAllocator; use crate::kernel::kernel::BootLoader; use crate::kernel::kernel_callback_api::*; -use crate::system::system_callback::{System, SystemInit}; +use crate::system::system_callback::*; use crate::system::system_callback_api::SystemCallbackObject; use crate::track::Track; use crate::transaction::*; use crate::vm::*; use radix_common::constants::*; use radix_engine_interface::blueprints::transaction_processor::InstructionOutput; -use radix_substate_store_interface::{db_key_mapper::SpreadPrefixKeyMapper, interface::*}; +use radix_substate_store_interface::interface::*; use radix_transactions::model::*; /// Protocol-defined costing parameters @@ -296,15 +296,14 @@ where } } - pub fn execute(&mut self, executable: V::Executable) -> V::Receipt { - let kernel_boot = BootLoader { + pub fn execute(self, executable: V::Executable) -> V::Receipt { + BootLoader { id_allocator: IdAllocator::new(executable.unique_seed_for_id_allocator()), - track: Track::<_, SpreadPrefixKeyMapper>::new(self.substate_db), - init: self.system_init.clone(), + track: Track::new(self.substate_db), + init: self.system_init, phantom: PhantomData::::default(), - }; - - kernel_boot.execute(executable) + } + .execute(executable) } } @@ -315,12 +314,14 @@ pub fn execute_transaction_with_configuration TransactionReceipt { let system_init = SystemInit { - enable_kernel_trace: execution_config.enable_kernel_trace, - enable_cost_breakdown: execution_config.enable_cost_breakdown, - enable_debug_information: execution_config.enable_debug_information, - execution_trace: execution_config.execution_trace, + self_init: SystemSelfInit { + enable_kernel_trace: execution_config.enable_kernel_trace, + enable_cost_breakdown: execution_config.enable_cost_breakdown, + enable_debug_information: execution_config.enable_debug_information, + execution_trace: execution_config.execution_trace, + system_overrides: execution_config.system_overrides.clone(), + }, callback_init: vm_init, - system_overrides: execution_config.system_overrides.clone(), }; TransactionExecutor::<_, System>::new(substate_db, system_init).execute(executable) } @@ -353,11 +354,7 @@ pub fn execute_and_commit_transaction<'s, V: VmInitialize>( executable, ); if let TransactionResult::Commit(commit) = &receipt.result { - substate_db.commit( - &commit - .state_updates - .create_database_updates::(), - ); + substate_db.commit(&commit.state_updates.create_database_updates()); } receipt } diff --git a/radix-engine/src/updates/cuttlefish.rs b/radix-engine/src/updates/cuttlefish.rs index 8bf79140b39..44daf40ccb3 100644 --- a/radix-engine/src/updates/cuttlefish.rs +++ b/radix-engine/src/updates/cuttlefish.rs @@ -2,9 +2,6 @@ use super::*; use crate::system::system_callback::{ SystemBoot, VersionedSystemLogic, BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY, }; -use radix_substate_store_interface::db_key_mapper::{ - MappedSubstateDatabase, SpreadPrefixKeyMapper, -}; #[derive(Clone)] pub struct CuttlefishSettings { @@ -92,10 +89,10 @@ fn generate_principal_batch( fn generate_system_logic_v2_updates(db: &S) -> StateUpdates { let system_boot: SystemBoot = db - .get_mapped::( - &TRANSACTION_TRACKER.into_node_id(), + .get_substate( + TRANSACTION_TRACKER, BOOT_LOADER_PARTITION, - &SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY), + SubstateKey::Field(BOOT_LOADER_SYSTEM_SUBSTATE_FIELD_KEY), ) .unwrap(); diff --git a/radix-engine/src/updates/protocol_builder.rs b/radix-engine/src/updates/protocol_builder.rs index 344e7801a7e..b3ad01814a6 100644 --- a/radix-engine/src/updates/protocol_builder.rs +++ b/radix-engine/src/updates/protocol_builder.rs @@ -1,4 +1,3 @@ -use radix_substate_store_interface::db_key_mapper::{DatabaseKeyMapper, SpreadPrefixKeyMapper}; use radix_transactions::{model::*, validation::TransactionValidator}; use crate::{ @@ -66,9 +65,7 @@ impl ProtocolUpdateExecutor { for (transaction_index, transaction) in batch.transactions.into_iter().enumerate() { let receipt = match &transaction { ProtocolUpdateTransactionDetails::FlashV1Transaction(flash) => { - let db_updates = flash - .state_updates - .create_database_updates::(); + let db_updates = flash.state_updates.create_database_updates(); let receipt = if H::IS_ENABLED { let before_store = &*store; FlashReceipt::from_state_updates( @@ -302,12 +299,10 @@ impl ProtocolExecutor { pub fn is_bootstrapped(store: &mut impl SubstateDatabase) -> bool { store - .get_substate( - &SpreadPrefixKeyMapper::to_db_partition_key( - PACKAGE_PACKAGE.as_node_id(), - TYPE_INFO_FIELD_PARTITION, - ), - &SpreadPrefixKeyMapper::to_db_sort_key(&TypeInfoField::TypeInfo.into()), + .get_raw_substate( + PACKAGE_PACKAGE, + TYPE_INFO_FIELD_PARTITION, + TypeInfoField::TypeInfo, ) .is_some() } diff --git a/radix-substate-store-impls/src/memory_db.rs b/radix-substate-store-impls/src/memory_db.rs index d155f1e44d1..667e9cbfd30 100644 --- a/radix-substate-store-impls/src/memory_db.rs +++ b/radix-substate-store-impls/src/memory_db.rs @@ -15,7 +15,7 @@ impl InMemorySubstateDatabase { } impl SubstateDatabase for InMemorySubstateDatabase { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -26,7 +26,7 @@ impl SubstateDatabase for InMemorySubstateDatabase { .cloned() } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, diff --git a/radix-substate-store-impls/src/rocks_db.rs b/radix-substate-store-impls/src/rocks_db.rs index 27cccecd888..3c1d3a9f0be 100644 --- a/radix-substate-store-impls/src/rocks_db.rs +++ b/radix-substate-store-impls/src/rocks_db.rs @@ -43,7 +43,7 @@ impl RocksdbSubstateStore { } impl SubstateDatabase for RocksdbSubstateStore { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -52,7 +52,7 @@ impl SubstateDatabase for RocksdbSubstateStore { self.db.get_cf(self.cf(), &key_bytes).expect("IO Error") } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, diff --git a/radix-substate-store-impls/src/rocks_db_with_merkle_tree/mod.rs b/radix-substate-store-impls/src/rocks_db_with_merkle_tree/mod.rs index dedca56a10c..8c9775da5bc 100644 --- a/radix-substate-store-impls/src/rocks_db_with_merkle_tree/mod.rs +++ b/radix-substate-store-impls/src/rocks_db_with_merkle_tree/mod.rs @@ -92,7 +92,7 @@ impl RocksDBWithMerkleTreeSubstateStore { } impl SubstateDatabase for RocksDBWithMerkleTreeSubstateStore { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -103,7 +103,7 @@ impl SubstateDatabase for RocksDBWithMerkleTreeSubstateStore { .expect("IO Error") } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, diff --git a/radix-substate-store-impls/src/state_tree_support.rs b/radix-substate-store-impls/src/state_tree_support.rs index a8dfd19dfea..3ebf397cb60 100644 --- a/radix-substate-store-impls/src/state_tree_support.rs +++ b/radix-substate-store-impls/src/state_tree_support.rs @@ -44,21 +44,22 @@ impl StateTreeUpdatingDatabase { } impl SubstateDatabase for StateTreeUpdatingDatabase { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, ) -> Option { - self.underlying.get_substate(partition_key, sort_key) + self.underlying + .get_raw_substate_by_db_key(partition_key, sort_key) } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, ) -> Box + '_> { self.underlying - .list_entries_from(partition_key, from_sort_key) + .list_raw_values_from_db_key(partition_key, from_sort_key) } } @@ -91,7 +92,7 @@ where for (db_partition_key, by_db_sort_key) in hashes_from_tree { if by_db_sort_key.into_iter().collect::>() != self - .list_entries(&db_partition_key) + .list_raw_values_from_db_key(&db_partition_key, None) .map(|(db_sort_key, substate_value)| (db_sort_key, hash(substate_value))) .collect::>() { diff --git a/radix-substate-store-impls/src/substate_database_overlay.rs b/radix-substate-store-impls/src/substate_database_overlay.rs index fd1a908e689..af70624abbd 100644 --- a/radix-substate-store-impls/src/substate_database_overlay.rs +++ b/radix-substate-store-impls/src/substate_database_overlay.rs @@ -80,7 +80,7 @@ impl, D: CommittableSubstateDatabase> SubstateDatabaseOverlay, D: SubstateDatabase> SubstateDatabase for SubstateDatabaseOverlay { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key @ DbPartitionKey { node_key, @@ -136,11 +136,11 @@ impl, D: SubstateDatabase> SubstateDatabase for SubstateDatabaseOve OverlayLookupResult::Found(substate_value) => substate_value.cloned(), OverlayLookupResult::NotFound => self .get_readable_root() - .get_substate(partition_key, sort_key), + .get_raw_substate_by_db_key(partition_key, sort_key), } } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key @ DbPartitionKey { node_key, @@ -187,7 +187,7 @@ impl, D: SubstateDatabase> SubstateDatabase for SubstateDatabaseOve Some(StagingPartitionDatabaseUpdates::Delta { substate_updates }) => { let underlying = self .get_readable_root() - .list_entries_from(partition_key, from_sort_key.as_ref()); + .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref()); match from_sort_key { // A `from_sort_key` is specified. Only return sort keys that are larger @@ -224,14 +224,14 @@ impl, D: SubstateDatabase> SubstateDatabase for SubstateDatabaseOve // iterator over the data in the root store. None => self .get_readable_root() - .list_entries_from(partition_key, from_sort_key.as_ref()), + .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref()), } } // Overlay doesn't contain anything for the provided node key. Return an iterator over // the data in the root store. None => self .get_readable_root() - .list_entries_from(partition_key, from_sort_key.as_ref()), + .list_raw_values_from_db_key(partition_key, from_sort_key.as_ref()), } } } diff --git a/radix-substate-store-interface/src/db_key_mapper.rs b/radix-substate-store-interface/src/db_key_mapper.rs index 96db906e8d0..a22b6925b24 100644 --- a/radix-substate-store-interface/src/db_key_mapper.rs +++ b/radix-substate-store-interface/src/db_key_mapper.rs @@ -1,12 +1,9 @@ -use crate::interface::{ - CommittableSubstateDatabase, DatabaseUpdates, DbNodeKey, DbPartitionKey, DbPartitionNum, - DbSortKey, SubstateDatabase, -}; +use crate::interface::*; use radix_common::prelude::*; use radix_rust::copy_u8_array; /// A mapper between the business ReNode / Partition / Substate IDs and database keys. -pub trait DatabaseKeyMapper { +pub trait DatabaseKeyMapper: 'static { /// Converts the given Node ID and Partition number to the database partition's key. fn to_db_partition_key(node_id: &NodeId, partition_num: PartitionNumber) -> DbPartitionKey { DbPartitionKey { @@ -46,21 +43,39 @@ pub trait DatabaseKeyMapper { } } + /// Converts the given [`SubstateKeyRef`] to the database's sort key. + /// This is a convenience method, which simply unwraps the [`SubstateKeyRef`] and maps any specific + /// type found inside (see `*_to_db_sort_key()` family). + fn to_db_sort_key_from_ref(key: SubstateKeyRef) -> DbSortKey { + match key { + SubstateKeyRef::Field(fields_key) => Self::field_to_db_sort_key(fields_key), + SubstateKeyRef::Map(map_key) => Self::map_to_db_sort_key(map_key), + SubstateKeyRef::Sorted(sorted_key) => Self::sorted_to_db_sort_key(sorted_key), + } + } + /// Converts the given database's sort key to a [`SubstateKey`]. /// This is a convenience method, which simply wraps the type-specific result of an appropriate /// `*_from_db_sort_key()` method into a [`SubstateKey`]. - fn from_db_sort_key(db_sort_key: &DbSortKey) -> SubstateKey { - match K::get_type() { - SubstateKeyTypeContentType::Tuple => { - SubstateKey::Field(Self::field_from_db_sort_key(db_sort_key)) - } - SubstateKeyTypeContentType::Map => { - SubstateKey::Map(Self::map_from_db_sort_key(db_sort_key)) - } - SubstateKeyTypeContentType::Sorted => { - SubstateKey::Sorted(Self::sorted_from_db_sort_key(db_sort_key)) - } - } + /// + /// ## Examples + /// ```ignore + /// Mapper::from_db_sort_key::(&db_sort_key); + /// Mapper::from_db_sort_key::(&db_sort_key); + /// Mapper::from_db_sort_key::(&db_sort_key); + /// ``` + fn from_db_sort_key(db_sort_key: &DbSortKey) -> SubstateKey { + K::from_db_key::(db_sort_key).into_typed_key() + } + + /// ## Examples + /// ```ignore + /// Mapper::from_db_sort_key_to_inner::(&db_sort_key); + /// Mapper::from_db_sort_key_to_inner::(&db_sort_key); + /// Mapper::from_db_sort_key_to_inner::(&db_sort_key); + /// ``` + fn from_db_sort_key_to_inner(db_sort_key: &DbSortKey) -> K { + K::from_db_key::(db_sort_key) } // Type-specific methods for mapping the `SubstateKey` inner data to/from `DbSortKey`: @@ -163,113 +178,40 @@ impl SpreadPrefixKeyMapper { } } -/// Convenience methods for direct `SubstateDatabase` readers. -pub trait MappedSubstateDatabase { - /// Gets a scrypto-decoded value by the given business key. - fn get_mapped( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - ) -> Option; - - /// Lists fully-mapped entries (i.e. business substate keys and scrypto-decoded values) of the - /// given node partition. - fn list_mapped( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - ) -> Box + '_>; -} - -impl MappedSubstateDatabase for S { - fn get_mapped( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - ) -> Option { - self.get_substate( - &M::to_db_partition_key(node_id, partition_num), - &M::to_db_sort_key(substate_key), - ) - .map(|buf| scrypto_decode(&buf).unwrap()) - } - - fn list_mapped( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - ) -> Box + '_> { - let mapped_value_iter = self - .list_entries(&M::to_db_partition_key(node_id, partition_num)) - .map(|(db_sort_key, db_value)| { - ( - M::from_db_sort_key::(&db_sort_key), - scrypto_decode(&db_value).unwrap(), - ) - }); - Box::new(mapped_value_iter) - } -} - -/// Convenience methods for direct `SubstateDatabase` writers. -pub trait MappedCommittableSubstateDatabase { - /// Puts a scrypto-encoded value by the given business key. - fn put_mapped( - &mut self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - value: &E, - ); -} - -impl MappedCommittableSubstateDatabase for S { - fn put_mapped( - &mut self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - value: &E, - ) { - self.commit(&DatabaseUpdates::from_delta_maps(indexmap!( - M::to_db_partition_key(node_id, partition_num) => indexmap!( - M::to_db_sort_key(substate_key) => DatabaseUpdate::Set( - scrypto_encode(value).unwrap() - ) - ) - ))) - } -} - // Internal-only trait enabling the concrete `DatabaseKeyMapper` implementations to drive their // logic by `SubstateKey`'s inner data type. -pub trait SubstateKeyContent { - fn get_type() -> SubstateKeyTypeContentType; -} - -pub enum SubstateKeyTypeContentType { - Tuple, - Map, - Sorted, +pub trait SubstateKeyContent: Sized + 'static { + fn from_db_key(db_sort_key: &DbSortKey) -> Self; + fn into_typed_key(self) -> SubstateKey; } impl SubstateKeyContent for MapKey { - fn get_type() -> SubstateKeyTypeContentType { - SubstateKeyTypeContentType::Map + fn from_db_key(db_sort_key: &DbSortKey) -> Self { + M::map_from_db_sort_key(db_sort_key) + } + + fn into_typed_key(self) -> SubstateKey { + SubstateKey::Map(self) } } impl SubstateKeyContent for FieldKey { - fn get_type() -> SubstateKeyTypeContentType { - SubstateKeyTypeContentType::Tuple + fn from_db_key(db_sort_key: &DbSortKey) -> Self { + M::field_from_db_sort_key(db_sort_key) + } + + fn into_typed_key(self) -> SubstateKey { + SubstateKey::Field(self) } } impl SubstateKeyContent for SortedKey { - fn get_type() -> SubstateKeyTypeContentType { - SubstateKeyTypeContentType::Sorted + fn from_db_key(db_sort_key: &DbSortKey) -> Self { + M::sorted_from_db_sort_key(db_sort_key) + } + + fn into_typed_key(self) -> SubstateKey { + SubstateKey::Sorted(self) } } diff --git a/radix-substate-store-interface/src/interface.rs b/radix-substate-store-interface/src/interface.rs index fee1ee96fd9..fff4931e7a5 100644 --- a/radix-substate-store-interface/src/interface.rs +++ b/radix-substate-store-interface/src/interface.rs @@ -1,4 +1,4 @@ -use super::db_key_mapper::DatabaseKeyMapper; +use crate::db_key_mapper::*; use radix_common::prelude::*; pub type DbNodeKey = Vec; @@ -30,8 +30,13 @@ pub type PartitionEntry = (DbSortKey, DbSubstateValue); pub trait CreateDatabaseUpdates { type DatabaseUpdates; + /// Uses the default [`DatabaseKeyMapper`], [`SpreadPrefixKeyMapper`], to express self using database-level key encoding. + fn create_database_updates(&self) -> Self::DatabaseUpdates { + self.create_database_updates_with_mapper::() + } + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. - fn create_database_updates(&self) -> Self::DatabaseUpdates; + fn create_database_updates_with_mapper(&self) -> Self::DatabaseUpdates; } /// A canonical description of all database updates to be applied. @@ -43,10 +48,18 @@ pub struct DatabaseUpdates { pub node_updates: IndexMap, } +impl DatabaseUpdates { + pub fn node_ids(&self) -> impl Iterator + '_ { + self.node_updates + .keys() + .map(|key| SpreadPrefixKeyMapper::from_db_node_key(key)) + } +} + impl CreateDatabaseUpdates for StateUpdates { type DatabaseUpdates = DatabaseUpdates; - fn create_database_updates(&self) -> DatabaseUpdates { + fn create_database_updates_with_mapper(&self) -> DatabaseUpdates { DatabaseUpdates { node_updates: self .by_node @@ -54,7 +67,7 @@ impl CreateDatabaseUpdates for StateUpdates { .map(|(node_id, node_state_updates)| { ( M::to_db_node_key(node_id), - node_state_updates.create_database_updates::(), + node_state_updates.create_database_updates_with_mapper::(), ) }) .collect(), @@ -74,7 +87,7 @@ pub struct NodeDatabaseUpdates { impl CreateDatabaseUpdates for NodeStateUpdates { type DatabaseUpdates = NodeDatabaseUpdates; - fn create_database_updates(&self) -> NodeDatabaseUpdates { + fn create_database_updates_with_mapper(&self) -> NodeDatabaseUpdates { match self { NodeStateUpdates::Delta { by_partition } => NodeDatabaseUpdates { partition_updates: by_partition @@ -82,7 +95,7 @@ impl CreateDatabaseUpdates for NodeStateUpdates { .map(|(partition_num, partition_state_updates)| { ( M::to_db_partition_num(*partition_num), - partition_state_updates.create_database_updates::(), + partition_state_updates.create_database_updates_with_mapper::(), ) }) .collect(), @@ -132,7 +145,9 @@ impl PartitionDatabaseUpdates { impl CreateDatabaseUpdates for PartitionStateUpdates { type DatabaseUpdates = PartitionDatabaseUpdates; - fn create_database_updates(&self) -> PartitionDatabaseUpdates { + fn create_database_updates_with_mapper( + &self, + ) -> PartitionDatabaseUpdates { match self { PartitionStateUpdates::Delta { by_substate } => PartitionDatabaseUpdates::Delta { substate_updates: by_substate @@ -140,7 +155,7 @@ impl CreateDatabaseUpdates for PartitionStateUpdates { .map(|(key, update)| (M::to_db_sort_key(key), update.clone())) .collect(), }, - PartitionStateUpdates::Batch(batch) => batch.create_database_updates::(), + PartitionStateUpdates::Batch(batch) => batch.create_database_updates_with_mapper::(), } } } @@ -148,7 +163,9 @@ impl CreateDatabaseUpdates for PartitionStateUpdates { impl CreateDatabaseUpdates for BatchPartitionStateUpdate { type DatabaseUpdates = PartitionDatabaseUpdates; - fn create_database_updates(&self) -> PartitionDatabaseUpdates { + fn create_database_updates_with_mapper( + &self, + ) -> PartitionDatabaseUpdates { match self { BatchPartitionStateUpdate::Reset { new_substate_values, @@ -204,8 +221,16 @@ impl DatabaseUpdates { /// A read interface between Track and a database vendor. pub trait SubstateDatabase { - /// Reads a substate value by its partition and sort key, or [`Option::None`] if missing. - fn get_substate( + /// Reads a substate value by its db partition and db sort key, or [`Option::None`] if missing. + /// + /// ## Alternatives + /// + /// It's likely easier to use the [`get_substate`][SubstateDatabaseExtensions::get_substate] or + /// [`get_raw_substate`][SubstateDatabaseExtensions::get_raw_substate] methods instead, which + /// allow providing logical keys. + /// These methods should also exist on the database type as long as the + /// [`SubstateDatabaseExtensions`] trait is in scope. + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -215,22 +240,375 @@ pub trait SubstateDatabase { /// from the given [`DbSortKey`]), in a lexicographical order (ascending) of the [`DbSortKey`]s. /// Note: If the exact given starting key does not exist, the iteration starts with its /// immediate successor. - fn list_entries_from( + /// + /// ## Alternatives + /// + /// There are lots of methods starting `list_` which allow iterating using more intuitive abstractions. + /// These methods are present as long as the [`SubstateDatabaseExtensions`] trait is in scope. + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, ) -> Box + '_>; +} + +impl SubstateDatabaseExtensions for T {} - /// Iterates over all entries of the given partition, in a lexicographical order (ascending) - /// of the [`DbSortKey`]s. - /// This is a convenience method, equivalent to [`Self::list_entries_from()`] with the starting - /// key set to [`None`]. - fn list_entries( +/// These are a separate trait so that [`SubstateDatabase`] stays object-safe, +/// and can be used as `dyn SubstateDatabase`. +/// +/// Generic parameters aren't permitted on object-safe traits. +pub trait SubstateDatabaseExtensions: SubstateDatabase { + /// Gets the raw bytes of the substate's value, if it exists. + /// + /// # Example + /// ```ignore + /// let is_bootstrapped = db.read_substate( + /// PACKAGE_PACKAGE, + /// TYPE_INFO_FIELD_PARTITION, + /// TypeInfoField::TypeInfo, + /// ).is_some(); + /// ``` + fn get_raw_substate<'a>( &self, - partition_key: &DbPartitionKey, - ) -> Box + '_> { - self.list_entries_from(partition_key, None) + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + ) -> Option> { + self.get_raw_substate_by_db_key( + &db_partition_key(node_id, partition_number), + &db_sort_key(substate_key), + ) + } + + /// Gets the substate's value, if it exists, and returns it decoded as `V`. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the value into the `V`. + /// + /// # Example use: + /// ```ignore + /// let type_info_substate = db.get_substate::( + /// PACKAGE_PACKAGE, + /// TYPE_INFO_FIELD_PARTITION, + /// TypeInfoField::TypeInfo, + /// )?; + /// ``` + fn get_substate<'a, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + ) -> Option { + let raw = self.get_raw_substate(node_id, partition_number, substate_key)?; + Some(decode_value(&raw)) + } + + // ------------------------------------------------------------------------------------ + // LIST RAW + // ------------------------------------------------------------------------------------ + + /// Returns an iterator of the substates of a partition from an inclusive start cursor. + /// + /// The iterator returns raw keys and values. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + #[inline] + fn list_raw_values<'a>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box)> + '_> { + self.list_raw_values_from_db_key( + &db_partition_key(node_id, partition_number), + optional_db_sort_key(from_substate_key_inclusive).as_ref(), + ) + } + + // ------------------------------------------------------------------------------------ + // LIST KINDED PARTITIONS (OF A KNOWN BUT GENERIC KIND) + // ------------------------------------------------------------------------------------ + // NOTE: There is not `list_kinded_entries` because mapping of the key requires knowing + // the specific kind of the substate key. + // ------------------------------------------------------------------------------------ + + /// Returns an iterator of the substates of a partition from an inclusive start cursor. + /// + /// The iterator returns `K` and the raw value for each substate. + /// The caller must specify `K` as [`FieldKey`], [`MapKey`] or [`SortedKey`]. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + fn list_kinded_raw_values<'a, K: SubstateKeyContent>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box)> + '_> { + let iterable = self + .list_raw_values_from_db_key( + &db_partition_key(node_id, partition_number), + optional_db_sort_key(from_substate_key_inclusive).as_ref(), + ) + .map(|(db_sort_key, raw_value)| { + ( + SpreadPrefixKeyMapper::from_db_sort_key_to_inner::(&db_sort_key), + raw_value, + ) + }); + Box::new(iterable) + } + + /// Returns an iterator of the substates of a partition from an inclusive start cursor. + /// + /// The iterator returns `K` and `V` for each substate. + /// The caller must specify `K` as [`FieldKey`], [`MapKey`] or [`SortedKey`]. + /// The value type `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the value bytes into `V`. + fn list_kinded_values<'a, K: SubstateKeyContent, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + let iterator = self + .list_raw_values(node_id, partition_number, from_substate_key_inclusive) + .map(|(db_sort_key, raw_value)| { + ( + SpreadPrefixKeyMapper::from_db_sort_key_to_inner::(&db_sort_key), + decode_value::(&raw_value), + ) + }); + Box::new(iterator) + } + + // ------------------------------------------------------------------------------------ + // LIST FIELD PARTITIONS + // ------------------------------------------------------------------------------------ + + /// Returns an iterator of the substates of a field partition from an inclusive start cursor. + /// + /// The iterator returns the `FieldKey = u8` and the raw value for each substate. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + fn list_field_raw_values<'a>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box)> + '_> { + self.list_kinded_raw_values::( + node_id, + partition_number, + from_substate_key_inclusive, + ) + } + + /// Returns an iterator of the substates of a field partition from an inclusive start cursor. + /// + /// The iterator returns the `FieldKey = u8` and the decoded value `V` for each substate. + /// The value type `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the value bytes into `V`. + fn list_field_values<'a, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + self.list_kinded_values::( + node_id, + partition_number, + from_substate_key_inclusive, + ) + } + + /// Returns an iterator of the substates of a field partition from an inclusive start cursor. + /// + /// The iterator returns the decoded key type `K` and the decoded value `V` for each substate. + /// The key type `K` and value types `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error converting the field key byte into `K`. + /// * There is an error decoding the value bytes into `V`. + fn list_field_entries<'a, K: TryFrom, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + let iterator = self + .list_raw_values(node_id, partition_number, from_substate_key_inclusive) + .map(|(db_sort_key, raw_value)| { + ( + K::try_from(SpreadPrefixKeyMapper::from_db_sort_key_to_inner::(&db_sort_key)) + .unwrap_or_else(|_| panic!("The field key type should be able to be decoded from the substate's key")), + decode_value::(&raw_value), + ) + }); + Box::new(iterator) + } + + // ------------------------------------------------------------------------------------ + // LIST MAP PARTITIONS + // ------------------------------------------------------------------------------------ + + /// Returns an iterator of the substates of a map partition from an inclusive start cursor. + /// + /// The iterator returns the `MapKey = Vec` and the raw value for each substate. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + fn list_map_raw_values<'a>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box)> + '_> { + self.list_kinded_raw_values::( + node_id, + partition_number, + from_substate_key_inclusive, + ) + } + + /// Returns an iterator of the substates of a map partition from an inclusive start cursor. + /// + /// The iterator returns the `MapKey = Vec` and the decoded value `V` for each substate. + /// The value type `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the value bytes into `V`. + fn list_map_values<'a, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + self.list_kinded_values::(node_id, partition_number, from_substate_key_inclusive) } + + /// Returns an iterator of the substates of a map partition from an inclusive start cursor. + /// + /// The iterator returns the decoded key type `K` and the decoded value `V` for each substate. + /// The key type `K` and value types `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the field bytes into `K`. + /// * There is an error decoding the value bytes into `V`. + fn list_map_entries<'a, K: ScryptoDecode, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + let iterator = self + .list_map_raw_values(node_id, partition_number, from_substate_key_inclusive) + .map(|(raw_key, raw_value)| (decode_key::(&raw_key), decode_value::(&raw_value))); + Box::new(iterator) + } + + // ------------------------------------------------------------------------------------ + // LIST SORTED PARTITIONS + // ------------------------------------------------------------------------------------ + + /// Returns an iterator of the substates of a sorted partition from an inclusive start cursor. + /// + /// The iterator returns the `SortedKey = ([u8; 2], Vec)` and the raw value for each substate. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + fn list_sorted_raw_values<'a>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box)> + '_> { + self.list_kinded_raw_values::( + node_id, + partition_number, + from_substate_key_inclusive, + ) + } + + /// Returns an iterator of the substates of a sorted partition from an inclusive start cursor. + /// + /// The iterator returns the `SortedKey = ([u8; 2], Vec)` and the decoded value `V` + /// for each substate. The value type `V` can be specified or inferred. + /// + /// Pass `None::` as the cursor to iterate from the start of the partition. + /// + /// # Panics + /// This method panics if: + /// * There is an error decoding the value bytes into `V`. + fn list_sorted_values<'a, V: ScryptoDecode>( + &self, + node_id: impl AsRef, + partition_number: PartitionNumber, + from_substate_key_inclusive: impl ResolvableOptionalSubstateKey<'a>, + ) -> Box + '_> { + self.list_kinded_values::( + node_id, + partition_number, + from_substate_key_inclusive, + ) + } +} + +fn db_partition_key( + node_id: impl AsRef, + partition_number: PartitionNumber, +) -> DbPartitionKey { + SpreadPrefixKeyMapper::to_db_partition_key(node_id.as_ref(), partition_number) +} + +fn db_sort_key<'a>(substate_key: impl ResolvableSubstateKey<'a>) -> DbSortKey { + SpreadPrefixKeyMapper::to_db_sort_key_from_ref(substate_key.into_substate_key_or_ref().as_ref()) +} + +fn optional_db_sort_key<'a>( + optional_substate_key: impl ResolvableOptionalSubstateKey<'a>, +) -> Option { + optional_substate_key + .into_optional_substate_key_or_ref() + .map(|key_or_ref| SpreadPrefixKeyMapper::to_db_sort_key_from_ref(key_or_ref.as_ref())) +} + +fn decode_key(raw: &[u8]) -> K { + scrypto_decode::(&raw).unwrap_or_else(|err| { + panic!( + "Expected key to be decodable as {}. Error: {:?}.", + core::any::type_name::(), + err, + ) + }) +} + +fn decode_value(raw: &[u8]) -> V { + scrypto_decode::(&raw).unwrap_or_else(|err| { + panic!( + "Expected value to be decodable as {}. Error: {:?}.", + core::any::type_name::(), + err, + ) + }) } /// A write interface between Track and a database vendor. @@ -239,8 +617,88 @@ pub trait CommittableSubstateDatabase { fn commit(&mut self, database_updates: &DatabaseUpdates); } +impl CommittableSubstateDatabaseExtensions for T {} + +pub trait CommittableSubstateDatabaseExtensions: CommittableSubstateDatabase { + fn update_substate<'a>( + &mut self, + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + value: Vec, + ) { + self.commit(&DatabaseUpdates::from_delta_maps(indexmap!( + SpreadPrefixKeyMapper::to_db_partition_key( + node_id.as_ref(), + partition_number, + ) => indexmap!( + SpreadPrefixKeyMapper::to_db_sort_key_from_ref( + substate_key.into_substate_key_or_ref().as_ref(), + ) => DatabaseUpdate::Set( + value + ) + ) + ))) + } + + fn delete_substate<'a>( + &mut self, + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + ) { + self.commit(&DatabaseUpdates::from_delta_maps(indexmap!( + SpreadPrefixKeyMapper::to_db_partition_key( + node_id.as_ref(), + partition_number, + ) => indexmap!( + SpreadPrefixKeyMapper::to_db_sort_key_from_ref( + substate_key.into_substate_key_or_ref().as_ref(), + ) => DatabaseUpdate::Delete, + ) + ))) + } + + fn update_substate_typed<'a, E: ScryptoEncode>( + &mut self, + node_id: impl AsRef, + partition_number: PartitionNumber, + substate_key: impl ResolvableSubstateKey<'a>, + value: E, + ) { + let encoded_value = scrypto_encode(&value).unwrap_or_else(|err| { + panic!( + "Expected value to be encodable as {}. Error: {:?}.", + core::any::type_name::(), + err, + ) + }); + self.update_substate(node_id, partition_number, substate_key, encoded_value) + } +} + /// A partition listing interface between Track and a database vendor. pub trait ListableSubstateDatabase { /// Iterates over all partition keys, in an arbitrary order. + /// + /// ## Alternatives + /// You likely want to use the [`read_partition_keys`][ListableSubstateDatabaseExtensions::read_partition_keys] + /// method instead, which returns an unmapped key. This is available if + /// the trait [`ListableSubstateDatabaseExtensions`] is in scope. fn list_partition_keys(&self) -> Box + '_>; } + +impl ListableSubstateDatabaseExtensions for T {} + +/// These are a separate trait so that [`ListableSubstateDatabase`] stays object-safe, +/// and can be used as `dyn ListableSubstateDatabase`. +/// +/// Generic parameters aren't permitted on object-safe traits. +pub trait ListableSubstateDatabaseExtensions: ListableSubstateDatabase { + fn read_partition_keys(&self) -> Box + '_> { + let iterator = self + .list_partition_keys() + .map(|key| SpreadPrefixKeyMapper::from_db_partition_key(&key)); + Box::new(iterator) + } +} diff --git a/radix-transaction-scenarios/src/executor.rs b/radix-transaction-scenarios/src/executor.rs index 2ed890165e4..a4abcd2313c 100644 --- a/radix-transaction-scenarios/src/executor.rs +++ b/radix-transaction-scenarios/src/executor.rs @@ -6,7 +6,6 @@ use radix_engine::blueprints::consensus_manager::*; use radix_engine::system::system_db_reader::*; use radix_engine::updates::*; use radix_engine::vm::*; -use radix_substate_store_interface::db_key_mapper::*; use radix_substate_store_interface::interface::*; use radix_transactions::errors::*; use radix_transactions::validation::*; @@ -322,9 +321,7 @@ where ); if let TransactionResult::Commit(commit) = &receipt.result { - let database_updates = commit - .state_updates - .create_database_updates::(); + let database_updates = commit.state_updates.create_database_updates(); self.database.commit(&database_updates); }; diff --git a/scrypto-test/src/environment/builder.rs b/scrypto-test/src/environment/builder.rs index eced465acad..3b900d09cbb 100644 --- a/scrypto-test/src/environment/builder.rs +++ b/scrypto-test/src/environment/builder.rs @@ -23,8 +23,6 @@ use radix_engine::vm::*; use radix_engine_interface::blueprints::package::*; use radix_engine_interface::prelude::*; use radix_substate_store_impls::memory_db::*; -use radix_substate_store_interface::db_key_mapper::DatabaseKeyMapper; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::*; use crate::sdk::PackageFactory; @@ -112,9 +110,7 @@ where /* Global references found in the NodeKeys */ .add_global_references( database_updates - .node_updates - .keys() - .map(SpreadPrefixKeyMapper::from_db_node_key) + .node_ids() .filter_map(|item| GlobalAddress::try_from(item).ok()), ) /* Global references found in the Substate Values */ @@ -211,17 +207,12 @@ where id_allocator, |substate_database| Track::new(substate_database), |scrypto_vm, database| { - let db_partition_key = SpreadPrefixKeyMapper::to_db_partition_key( - TRANSACTION_TRACKER.as_node_id(), - BOOT_LOADER_PARTITION, - ); - let db_sort_key = SpreadPrefixKeyMapper::to_db_sort_key(&SubstateKey::Field( - BOOT_LOADER_VM_BOOT_FIELD_KEY, - )); - let vm_boot = database - .get_substate(&db_partition_key, &db_sort_key) - .map(|v| scrypto_decode(v.as_slice()).unwrap()) + .get_substate( + TRANSACTION_TRACKER, + BOOT_LOADER_PARTITION, + BOOT_LOADER_VM_BOOT_FIELD_KEY, + ) .unwrap_or(VmBoot::babylon()); let transaction_runtime_module = TransactionRuntimeModule::new( @@ -424,7 +415,7 @@ impl FlashSubstateDatabase { } impl SubstateDatabase for FlashSubstateDatabase { - fn get_substate( + fn get_raw_substate_by_db_key( &self, partition_key: &DbPartitionKey, sort_key: &DbSortKey, @@ -435,7 +426,7 @@ impl SubstateDatabase for FlashSubstateDatabase { .cloned() } - fn list_entries_from( + fn list_raw_values_from_db_key( &self, partition_key: &DbPartitionKey, from_sort_key: Option<&DbSortKey>, diff --git a/scrypto-test/src/environment/types.rs b/scrypto-test/src/environment/types.rs index 64ac8db8f98..bfb526a0bfe 100644 --- a/scrypto-test/src/environment/types.rs +++ b/scrypto-test/src/environment/types.rs @@ -4,7 +4,7 @@ use crate::prelude::*; pub type TestVm<'g> = Vm<'g, DefaultWasmEngine, NoExtension>; -pub type TestTrack<'g, D> = Track<'g, D, SpreadPrefixKeyMapper>; +pub type TestTrack<'g, D> = Track<'g, D>; pub type TestSystemConfig<'g> = System>; pub type TestKernel<'g, D> = Kernel<'g, TestSystemConfig<'g>, TestTrack<'g, D>>; pub type TestSystemService<'g, D> = SystemService<'g, TestKernel<'g, D>>; diff --git a/scrypto-test/src/ledger_simulator/inject_costing_err.rs b/scrypto-test/src/ledger_simulator/inject_costing_err.rs index ca1f53fe588..0fa1c45b4ec 100644 --- a/scrypto-test/src/ledger_simulator/inject_costing_err.rs +++ b/scrypto-test/src/ledger_simulator/inject_costing_err.rs @@ -13,7 +13,7 @@ use radix_engine::vm::wasm::DefaultWasmEngine; use radix_engine::vm::Vm; use radix_engine_interface::blueprints::transaction_processor::InstructionOutput; use radix_engine_interface::prelude::*; -use radix_substate_store_interface::db_key_mapper::{SpreadPrefixKeyMapper, SubstateKeyContent}; +use radix_substate_store_interface::db_key_mapper::SubstateKeyContent; use radix_substate_store_interface::interface::SubstateDatabase; use radix_transactions::model::ExecutableTransaction; @@ -102,7 +102,7 @@ impl KernelTransactionCallbackObject for InjectCostingE fn create_receipt( self, - track: Track, + track: Track, result: Result, TransactionExecutionError>, ) -> TransactionReceipt { self.system.create_receipt(track, result) @@ -460,7 +460,7 @@ impl<'a, M: SystemCallbackObject, Y: KernelApi( + fn kernel_scan_keys( &mut self, node_id: &NodeId, partition_num: PartitionNumber, @@ -470,7 +470,7 @@ impl<'a, M: SystemCallbackObject, Y: KernelApi(node_id, partition_num, count) } - fn kernel_drain_substates( + fn kernel_drain_substates( &mut self, node_id: &NodeId, partition_num: PartitionNumber, diff --git a/scrypto-test/src/ledger_simulator/ledger_simulator.rs b/scrypto-test/src/ledger_simulator/ledger_simulator.rs index 849497d9263..7714289076d 100644 --- a/scrypto-test/src/ledger_simulator/ledger_simulator.rs +++ b/scrypto-test/src/ledger_simulator/ledger_simulator.rs @@ -23,8 +23,6 @@ use radix_engine_interface::blueprints::pool::{ use radix_engine_interface::prelude::{dec, freeze_roles, rule}; use radix_substate_store_impls::memory_db::InMemorySubstateDatabase; use radix_substate_store_impls::state_tree_support::StateTreeUpdatingDatabase; -use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; -use radix_substate_store_interface::db_key_mapper::{DatabaseKeyMapper, MappedSubstateDatabase}; use radix_substate_store_interface::interface::*; use radix_substate_store_queries::query::{ResourceAccounter, StateTreeTraverser, VaultFinder}; use radix_substate_store_queries::typed_native_events::to_typed_native_event; @@ -460,12 +458,10 @@ impl LedgerSimulator { } pub fn find_all_nodes(&self) -> IndexSet { - let mut node_ids = index_set_new(); - for pk in self.database.list_partition_keys() { - let (node_id, _) = SpreadPrefixKeyMapper::from_db_partition_key(&pk); - node_ids.insert(node_id); - } - node_ids + self.database + .read_partition_keys() + .map(|(node_id, _)| node_id) + .collect() } pub fn find_all_components(&self) -> Vec { @@ -642,13 +638,11 @@ impl LedgerSimulator { pub fn component_state(&self, component_address: ComponentAddress) -> T { let node_id: &NodeId = component_address.as_node_id(); - let component_state = self - .substate_db() - .get_mapped::>( - node_id, - MAIN_BASE_PARTITION, - &ComponentField::State0.into(), - ); + let component_state = self.substate_db().get_substate::>( + node_id, + MAIN_BASE_PARTITION, + ComponentField::State0, + ); component_state.unwrap().into_payload() } @@ -685,10 +679,10 @@ impl LedgerSimulator { pub fn get_fungible_resource_total_supply(&self, resource: ResourceAddress) -> Decimal { let total_supply = self .substate_db() - .get_mapped::( - &resource.as_node_id(), + .get_substate::( + resource, MAIN_BASE_PARTITION, - &FungibleResourceManagerField::TotalSupply.into(), + FungibleResourceManagerField::TotalSupply, ) .unwrap() .into_payload() @@ -1215,16 +1209,19 @@ impl LedgerSimulator { let execution_config = ExecutionConfig::for_test_transaction().with_kernel_trace(self.with_kernel_trace); - let mut executor = TransactionExecutor::<_, InjectSystemCostingError<'_, E>>::new( + + let executor = TransactionExecutor::<_, InjectSystemCostingError<'_, E>>::new( &self.database, InjectCostingErrorInput { system_input: SystemInit { - enable_kernel_trace: execution_config.enable_kernel_trace, - enable_cost_breakdown: execution_config.enable_cost_breakdown, - enable_debug_information: execution_config.enable_debug_information, - execution_trace: execution_config.execution_trace, + self_init: SystemSelfInit { + enable_kernel_trace: execution_config.enable_kernel_trace, + enable_cost_breakdown: execution_config.enable_cost_breakdown, + enable_debug_information: execution_config.enable_debug_information, + execution_trace: execution_config.execution_trace, + system_overrides: execution_config.system_overrides.clone(), + }, callback_init: vm_init, - system_overrides: execution_config.system_overrides.clone(), }, error_after_count, }, @@ -1233,9 +1230,7 @@ impl LedgerSimulator { let transaction_receipt = executor.execute(executable); if let TransactionResult::Commit(commit) = &transaction_receipt.result { - let database_updates = commit - .state_updates - .create_database_updates::(); + let database_updates = commit.state_updates.create_database_updates(); self.database.commit(&database_updates); self.collected_events .push(commit.application_events.clone()); @@ -1312,9 +1307,7 @@ impl LedgerSimulator { executable, ); if let TransactionResult::Commit(commit) = &transaction_receipt.result { - let database_updates = commit - .state_updates - .create_database_updates::(); + let database_updates = commit.state_updates.create_database_updates(); self.database.commit(&database_updates); self.collected_events .push(commit.application_events.clone());