From 472ece94e79bd349c86af9dc8ae93f337107c11b Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 10 Aug 2024 04:58:00 +0100 Subject: [PATCH] refactor: Moves all transaction models into `radix-transactions` --- radix-clis/src/replay/cmd_alloc_dump.rs | 22 +- radix-clis/src/replay/cmd_execute.rs | 3 +- .../src/replay/cmd_execute_in_memory.rs | 3 +- radix-clis/src/replay/cmd_measure.rs | 7 +- radix-clis/src/replay/cmd_sync.rs | 8 +- .../replay/ledger_transaction_execution.rs | 10 +- radix-clis/src/replay/mod.rs | 1 - radix-clis/src/resim/addressing.rs | 1 - radix-clis/src/resim/cmd_publish.rs | 2 +- radix-clis/src/rtmd/mod.rs | 1 + .../model/manifest_address_reservation.rs | 5 + .../data/manifest/model/manifest_bucket.rs | 1 + .../data/manifest/model/manifest_decimal.rs | 3 +- .../model/manifest_precise_decimal.rs | 7 +- .../src/data/manifest/model/manifest_proof.rs | 1 + radix-common/src/lib.rs | 6 +- radix-common/src/macros.rs | 21 +- radix-common/src/math/precise_decimal.rs | 4 +- radix-common/src/state/mod.rs | 3 + radix-common/src/state/state_updates.rs | 282 +++++++++ .../tests/fuzz_kernel.rs | 1 + .../tests/blueprints/transaction_tracker.rs | 1 - .../tests/flash/seconds_precision.rs | 2 +- .../tests/system/schema_sanity_check.rs | 1 + .../tests/system/system_actor_collection.rs | 1 - .../tests/system/system_db_checker.rs | 4 +- radix-engine/src/system/bootstrap.rs | 9 +- radix-engine/src/system/system_db_reader.rs | 10 +- .../src/track/legacy_state_updates.rs | 82 --- radix-engine/src/track/mod.rs | 2 - radix-engine/src/track/state_updates.rs | 260 +-------- .../src/transaction/state_update_summary.rs | 2 - .../src/transaction/system_structure.rs | 3 - .../src/transaction/transaction_executor.rs | 22 +- .../src/transaction/transaction_receipt.rs | 17 +- radix-engine/src/updates/anemone.rs | 1 - radix-engine/src/updates/bottlenose.rs | 1 - radix-engine/src/updates/mod.rs | 2 +- radix-substate-store-impls/src/memory_db.rs | 2 +- radix-substate-store-impls/src/rocks_db.rs | 2 +- .../src/rocks_db_with_merkle_tree/mod.rs | 5 +- .../src/state_tree/substate_tier.rs | 7 +- .../src/state_tree/test.rs | 2 +- .../src/state_tree/tree_store.rs | 15 +- .../src/state_tree/types.rs | 2 +- .../src/state_tree_support.rs | 5 +- .../src/db_key_mapper.rs | 10 +- .../src/interface.rs | 114 +++- .../src/scenarios/maya_router.rs | 12 - .../non_fungible_resource_with_remote_type.rs | 2 - .../model/any_transaction_payload_schema.txt | 1 + .../src/model}/ledger_transaction.rs | 404 +++++-------- radix-transactions/src/model/mod.rs | 2 + .../src/model/preparation/traits.rs | 9 +- radix-transactions/src/model/v1/blobs.rs | 4 +- .../src/model/v1/dynamic_addresses.rs | 544 ++++++++++++++++++ .../src/model/v1/flash_transaction.rs | 65 +++ radix-transactions/src/model/v1/header.rs | 3 +- .../src/model/v1/instruction.rs | 521 +---------------- .../src/model/v1/instructions.rs | 2 +- radix-transactions/src/model/v1/intent.rs | 2 +- .../src/model/v1/intent_signatures.rs | 4 +- radix-transactions/src/model/v1/manifest.rs | 2 +- radix-transactions/src/model/v1/message.rs | 20 +- radix-transactions/src/model/v1/mod.rs | 6 + .../src/model/v1/notarized_transaction.rs | 6 +- .../v1/notarized_transaction_v1_schema.txt | 1 + .../src/model/v1/notary_signature.rs | 2 +- .../src/model/v1/preview_transaction.rs | 2 +- .../src/model/v1/round_update_transaction.rs | 134 +++++ .../src/model/v1/signed_intent.rs | 2 +- .../src/model/v1/system_transaction.rs | 2 +- radix-transactions/src/model/versioned.rs | 33 +- sbor-derive-common/src/sbor_assert.rs | 2 +- scrypto-derive/src/ast.rs | 3 + scrypto-derive/src/blueprint.rs | 3 + .../src/ledger_simulator/ledger_simulator.rs | 4 +- 77 files changed, 1443 insertions(+), 1330 deletions(-) create mode 100644 radix-common/src/state/mod.rs create mode 100644 radix-common/src/state/state_updates.rs delete mode 100644 radix-engine/src/track/legacy_state_updates.rs create mode 100644 radix-transactions/src/model/any_transaction_payload_schema.txt rename {radix-clis/src/replay => radix-transactions/src/model}/ledger_transaction.rs (62%) create mode 100644 radix-transactions/src/model/v1/dynamic_addresses.rs create mode 100644 radix-transactions/src/model/v1/flash_transaction.rs create mode 100644 radix-transactions/src/model/v1/notarized_transaction_v1_schema.txt create mode 100644 radix-transactions/src/model/v1/round_update_transaction.rs diff --git a/radix-clis/src/replay/cmd_alloc_dump.rs b/radix-clis/src/replay/cmd_alloc_dump.rs index 8a340a84182..00f39ad1f59 100644 --- a/radix-clis/src/replay/cmd_alloc_dump.rs +++ b/radix-clis/src/replay/cmd_alloc_dump.rs @@ -1,21 +1,17 @@ use super::ledger_transaction_execution::*; use super::txn_reader::TxnReader; use super::Error; -use crate::replay::ledger_transaction::PreparedLedgerTransactionInner; use clap::Parser; use flate2::read::GzDecoder; use flume; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::vm::wasm::*; use radix_engine::vm::ScryptoVm; 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::CommittableSubstateDatabase; -use radix_transactions::prelude::HasSystemTransactionHash; -use radix_transactions::prelude::IntentHash; -use radix_transactions::prelude::TransactionHashBech32Encoder; +use radix_substate_store_interface::interface::*; +use radix_transactions::prelude::*; use std::fs::File; use std::fs::OpenOptions; use std::io::prelude::*; @@ -194,6 +190,20 @@ impl TxnAllocDump { .map_err(Error::IOError)? } } + PreparedLedgerTransactionInner::FlashV1(tx) => { + if dump_round { + writeln!( + output, + "flash,{},{},{},{},{}", + tx.summary.hash, + execution_cost_units.unwrap_or_default(), + heap_allocations_sum, + heap_current_level, + heap_peak_memory + ) + .map_err(Error::IOError)? + } + } } let new_version = database.get_current_version(); diff --git a/radix-clis/src/replay/cmd_execute.rs b/radix-clis/src/replay/cmd_execute.rs index 6b4475edab4..aa503991f8a 100644 --- a/radix-clis/src/replay/cmd_execute.rs +++ b/radix-clis/src/replay/cmd_execute.rs @@ -4,13 +4,12 @@ use super::Error; use clap::Parser; use flate2::read::GzDecoder; use flume; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::vm::wasm::*; use radix_engine::vm::ScryptoVm; 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::CommittableSubstateDatabase; +use radix_substate_store_interface::interface::*; use std::fs::File; use std::path::PathBuf; use std::thread; diff --git a/radix-clis/src/replay/cmd_execute_in_memory.rs b/radix-clis/src/replay/cmd_execute_in_memory.rs index 0e5d7e55a3e..80c32875180 100644 --- a/radix-clis/src/replay/cmd_execute_in_memory.rs +++ b/radix-clis/src/replay/cmd_execute_in_memory.rs @@ -4,14 +4,13 @@ use super::Error; use clap::Parser; use flate2::read::GzDecoder; use flume; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::vm::wasm::*; use radix_engine::vm::ScryptoVm; 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::CommittableSubstateDatabase; +use radix_substate_store_interface::interface::*; use std::fs::File; use std::path::PathBuf; use std::thread; diff --git a/radix-clis/src/replay/cmd_measure.rs b/radix-clis/src/replay/cmd_measure.rs index 765ceebb9be..12c7864fa8f 100644 --- a/radix-clis/src/replay/cmd_measure.rs +++ b/radix-clis/src/replay/cmd_measure.rs @@ -1,19 +1,16 @@ use super::ledger_transaction_execution::*; use super::txn_reader::TxnReader; use super::Error; -use crate::replay::ledger_transaction::PreparedLedgerTransactionInner; use clap::Parser; use flate2::read::GzDecoder; use flume; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::vm::wasm::*; use radix_engine::vm::ScryptoVm; 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::CommittableSubstateDatabase; -use radix_transactions::prelude::IntentHash; -use radix_transactions::prelude::TransactionHashBech32Encoder; +use radix_substate_store_interface::interface::*; +use radix_transactions::prelude::*; use std::fs::File; use std::fs::OpenOptions; use std::io::prelude::*; diff --git a/radix-clis/src/replay/cmd_sync.rs b/radix-clis/src/replay/cmd_sync.rs index b1c966a26dc..a1730e65171 100644 --- a/radix-clis/src/replay/cmd_sync.rs +++ b/radix-clis/src/replay/cmd_sync.rs @@ -1,19 +1,15 @@ -use super::ledger_transaction::*; use super::ledger_transaction_execution::execute_ledger_transaction; use super::Error; use clap::Parser; use flume; use flume::Sender; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::vm::wasm::*; use radix_engine::vm::ScryptoVm; 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::CommittableSubstateDatabase; -use radix_transactions::prelude::{ - IntentHash, NotarizedTransactionHash, SignedIntentHash, SystemTransactionHash, -}; +use radix_substate_store_interface::interface::*; +use radix_transactions::prelude::*; use rocksdb::{Direction, IteratorMode, Options, DB}; use std::path::PathBuf; use std::thread; diff --git a/radix-clis/src/replay/ledger_transaction_execution.rs b/radix-clis/src/replay/ledger_transaction_execution.rs index 5cba77aa48a..b7b783d1681 100644 --- a/radix-clis/src/replay/ledger_transaction_execution.rs +++ b/radix-clis/src/replay/ledger_transaction_execution.rs @@ -1,8 +1,5 @@ -use super::ledger_transaction::*; -use radix_common::prelude::NetworkDefinition; use radix_common::prelude::*; use radix_engine::system::bootstrap::*; -use radix_engine::track::StateUpdates; use radix_engine::transaction::{ execute_transaction, ExecutionConfig, TransactionFeeSummary, TransactionReceipt, }; @@ -10,6 +7,7 @@ use radix_engine::vm::wasm::*; use radix_engine::vm::{NoExtension, ScryptoVm, VmInit}; use radix_engine_interface::prelude::system_execution; use radix_substate_store_interface::interface::SubstateDatabase; +use radix_transactions::prelude::*; use radix_transactions::validation::{ NotarizedTransactionValidator, TransactionValidator, ValidationConfig, }; @@ -17,6 +15,7 @@ use radix_transactions::validation::{ pub enum LedgerTransactionReceipt { Flash(FlashReceipt), Standard(TransactionReceipt), + ProtocolUpdateFlash(StateUpdates), } impl LedgerTransactionReceipt { @@ -26,6 +25,7 @@ impl LedgerTransactionReceipt { LedgerTransactionReceipt::Standard(receipt) => { receipt.into_commit_ignore_outcome().state_updates } + LedgerTransactionReceipt::ProtocolUpdateFlash(state_updates) => state_updates, } } @@ -33,6 +33,7 @@ impl LedgerTransactionReceipt { match self { LedgerTransactionReceipt::Flash(_) => None, LedgerTransactionReceipt::Standard(receipt) => Some(&receipt.fee_summary), + LedgerTransactionReceipt::ProtocolUpdateFlash(_) => None, } } } @@ -119,5 +120,8 @@ pub fn execute_prepared_ledger_transaction( ); LedgerTransactionReceipt::Standard(receipt) } + PreparedLedgerTransactionInner::FlashV1(tx) => { + LedgerTransactionReceipt::ProtocolUpdateFlash(tx.state_updates.clone()) + } } } diff --git a/radix-clis/src/replay/mod.rs b/radix-clis/src/replay/mod.rs index d492ba662b1..e82c6fc363b 100644 --- a/radix-clis/src/replay/mod.rs +++ b/radix-clis/src/replay/mod.rs @@ -1,4 +1,3 @@ -pub mod ledger_transaction; pub mod ledger_transaction_execution; pub mod txn_reader; diff --git a/radix-clis/src/resim/addressing.rs b/radix-clis/src/resim/addressing.rs index 23ba76f70ec..75b0ebe0948 100644 --- a/radix-clis/src/resim/addressing.rs +++ b/radix-clis/src/resim/addressing.rs @@ -16,7 +16,6 @@ pub enum AddressError { InvalidAddress(String), } -#[cfg(not(feature = "alloc"))] impl std::error::Error for AddressError {} impl fmt::Display for AddressError { diff --git a/radix-clis/src/resim/cmd_publish.rs b/radix-clis/src/resim/cmd_publish.rs index 0adc3fdd1e9..25e148f3b27 100644 --- a/radix-clis/src/resim/cmd_publish.rs +++ b/radix-clis/src/resim/cmd_publish.rs @@ -12,7 +12,7 @@ use radix_rust::ContextualDisplay; use radix_substate_store_interface::interface::DatabaseUpdates; use radix_substate_store_interface::{ db_key_mapper::{DatabaseKeyMapper, SpreadPrefixKeyMapper}, - interface::{CommittableSubstateDatabase, DatabaseUpdate}, + interface::*, }; use radix_substate_store_queries::typed_substate_layout::*; use std::ffi::OsStr; diff --git a/radix-clis/src/rtmd/mod.rs b/radix-clis/src/rtmd/mod.rs index 05553ff999d..2e5582eb1a9 100644 --- a/radix-clis/src/rtmd/mod.rs +++ b/radix-clis/src/rtmd/mod.rs @@ -98,6 +98,7 @@ pub fn run() -> Result<(), String> { blobs, .. }) => (instructions.0, blobs.blobs), + _ => return Err("Transaction type not currently supported".to_string()), }; let blobs: Vec> = blobs.into_iter().map(|item| item.0).collect(); diff --git a/radix-common/src/data/manifest/model/manifest_address_reservation.rs b/radix-common/src/data/manifest/model/manifest_address_reservation.rs index 24e1b90d95d..5b59786c077 100644 --- a/radix-common/src/data/manifest/model/manifest_address_reservation.rs +++ b/radix-common/src/data/manifest/model/manifest_address_reservation.rs @@ -60,6 +60,11 @@ manifest_type!( ManifestCustomValueKind::AddressReservation, 4 ); +scrypto_describe_for_manifest_type!( + ManifestAddressReservation, + OWN_GLOBAL_ADDRESS_RESERVATION_TYPE, + own_global_address_reservation_type_data, +); #[cfg(test)] mod tests { diff --git a/radix-common/src/data/manifest/model/manifest_bucket.rs b/radix-common/src/data/manifest/model/manifest_bucket.rs index 4e6bdb6352b..06524ee50bf 100644 --- a/radix-common/src/data/manifest/model/manifest_bucket.rs +++ b/radix-common/src/data/manifest/model/manifest_bucket.rs @@ -56,6 +56,7 @@ impl ManifestBucket { } manifest_type!(ManifestBucket, ManifestCustomValueKind::Bucket, 4); +scrypto_describe_for_manifest_type!(ManifestBucket, OWN_BUCKET_TYPE, own_bucket_type_data,); #[cfg(test)] mod tests { diff --git a/radix-common/src/data/manifest/model/manifest_decimal.rs b/radix-common/src/data/manifest/model/manifest_decimal.rs index 884b0f589c2..f1e24abd81c 100644 --- a/radix-common/src/data/manifest/model/manifest_decimal.rs +++ b/radix-common/src/data/manifest/model/manifest_decimal.rs @@ -61,8 +61,9 @@ impl ManifestDecimal { manifest_type!( ManifestDecimal, ManifestCustomValueKind::Decimal, - DECIMAL_SIZE + DECIMAL_SIZE, ); +scrypto_describe_for_manifest_type!(ManifestDecimal, DECIMAL_TYPE, decimal_type_data,); #[cfg(test)] mod tests { diff --git a/radix-common/src/data/manifest/model/manifest_precise_decimal.rs b/radix-common/src/data/manifest/model/manifest_precise_decimal.rs index b0dda25b598..ae8f39cf867 100644 --- a/radix-common/src/data/manifest/model/manifest_precise_decimal.rs +++ b/radix-common/src/data/manifest/model/manifest_precise_decimal.rs @@ -61,7 +61,12 @@ impl ManifestPreciseDecimal { manifest_type!( ManifestPreciseDecimal, ManifestCustomValueKind::PreciseDecimal, - PRECISE_DECIMAL_SIZE + PRECISE_DECIMAL_SIZE, +); +scrypto_describe_for_manifest_type!( + ManifestPreciseDecimal, + PRECISE_DECIMAL_TYPE, + precise_decimal_type_data, ); #[cfg(test)] diff --git a/radix-common/src/data/manifest/model/manifest_proof.rs b/radix-common/src/data/manifest/model/manifest_proof.rs index 5cbb763faba..7067b3ffa4b 100644 --- a/radix-common/src/data/manifest/model/manifest_proof.rs +++ b/radix-common/src/data/manifest/model/manifest_proof.rs @@ -56,6 +56,7 @@ impl ManifestProof { } manifest_type!(ManifestProof, ManifestCustomValueKind::Proof, 4); +scrypto_describe_for_manifest_type!(ManifestProof, OWN_PROOF_TYPE, own_proof_type_data); #[cfg(test)] mod tests { diff --git a/radix-common/src/lib.rs b/radix-common/src/lib.rs index 7ebd8b0c479..49338005913 100644 --- a/radix-common/src/lib.rs +++ b/radix-common/src/lib.rs @@ -18,6 +18,8 @@ pub mod data; pub mod math; /// RE network identifier model. pub mod network; +/// Common models for state changes in RE +pub mod state; /// RE time library. pub mod time; /// RE types. @@ -60,7 +62,8 @@ pub mod prelude { // Exports from upstream libraries pub use radix_sbor_derive::{ ManifestCategorize, ManifestDecode, ManifestEncode, ManifestSbor, ScryptoCategorize, - ScryptoDecode, ScryptoEncode, ScryptoEvent, ScryptoSbor, ScryptoSborAssertion, + ScryptoDecode, ScryptoDescribe, ScryptoEncode, ScryptoEvent, ScryptoSbor, + ScryptoSborAssertion, }; pub use sbor::prelude::*; pub use sbor::*; @@ -73,6 +76,7 @@ pub mod prelude { pub use super::data::scrypto::prelude::*; pub use super::math::*; pub use super::network::*; + pub use super::state::*; pub use super::time::*; pub use super::traits::*; pub use super::types::*; diff --git a/radix-common/src/macros.rs b/radix-common/src/macros.rs index 40fe781cd7f..d9fb0f23322 100644 --- a/radix-common/src/macros.rs +++ b/radix-common/src/macros.rs @@ -13,7 +13,7 @@ macro_rules! i { #[macro_export] macro_rules! well_known_scrypto_custom_type { // with describe - ($t:ty, $value_kind:expr, $schema_type:expr, $size:expr, $well_known_type:ident, $well_known_type_data_method:ident) => { + ($t:ty, $value_kind:expr, $schema_type:expr, $size:expr, $well_known_type:ident, $well_known_type_data_method:ident$(,)?) => { impl sbor::Categorize<$crate::data::scrypto::ScryptoCustomValueKind> for $t { #[inline] fn value_kind() -> sbor::ValueKind<$crate::data::scrypto::ScryptoCustomValueKind> { @@ -62,8 +62,8 @@ macro_rules! well_known_scrypto_custom_type { #[macro_export] macro_rules! manifest_type { - // without describe - ($t:ty, $value_kind:expr, $size: expr) => { + // Without describe - if you need describe, also use scrypto_describe_for_manifest_type! + ($t:ty, $value_kind:expr, $size: expr$(,)?) => { impl sbor::Categorize<$crate::data::manifest::ManifestCustomValueKind> for $t { #[inline] fn value_kind() -> sbor::ValueKind<$crate::data::manifest::ManifestCustomValueKind> { @@ -100,6 +100,21 @@ macro_rules! manifest_type { }; } +#[macro_export] +macro_rules! scrypto_describe_for_manifest_type { + ($t:ty, $well_known_type:ident, $well_known_type_data_method:ident$(,)?) => { + impl sbor::Describe<$crate::data::scrypto::ScryptoCustomTypeKind> for $t { + const TYPE_ID: sbor::RustTypeId = sbor::RustTypeId::WellKnown( + $crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type, + ); + + fn type_data() -> sbor::TypeData<$crate::data::scrypto::ScryptoCustomTypeKind, sbor::RustTypeId> { + $crate::data::scrypto::well_known_scrypto_custom_types::$well_known_type_data_method() + } + } + } +} + #[macro_export] macro_rules! count { () => {0usize}; diff --git a/radix-common/src/math/precise_decimal.rs b/radix-common/src/math/precise_decimal.rs index f34228f8117..b8f1ec4c0bf 100644 --- a/radix-common/src/math/precise_decimal.rs +++ b/radix-common/src/math/precise_decimal.rs @@ -761,13 +761,13 @@ well_known_scrypto_custom_type!( Type::PreciseDecimal, PreciseDecimal::BITS / 8, PRECISE_DECIMAL_TYPE, - precise_decimal_type_data + precise_decimal_type_data, ); manifest_type!( PreciseDecimal, ManifestCustomValueKind::PreciseDecimal, - PreciseDecimal::BITS / 8 + PreciseDecimal::BITS / 8, ); //====== diff --git a/radix-common/src/state/mod.rs b/radix-common/src/state/mod.rs new file mode 100644 index 00000000000..4f0f25ad5d8 --- /dev/null +++ b/radix-common/src/state/mod.rs @@ -0,0 +1,3 @@ +mod state_updates; + +pub use state_updates::*; diff --git a/radix-common/src/state/state_updates.rs b/radix-common/src/state/state_updates.rs new file mode 100644 index 00000000000..0d5a8e30c1b --- /dev/null +++ b/radix-common/src/state/state_updates.rs @@ -0,0 +1,282 @@ +use crate::internal_prelude::*; + +/// A tree-like description of all updates that happened to a stored state, to be included as a part +/// of a transaction receipt. +/// This structure is indexed (i.e. uses [`IndexMap`]s where [`Vec`]s could be used) for convenience +/// and performance, since both the source (i.e. Track) and the sink (i.e. Database and API) operate +/// on indexed structures too. +/// This structure maintains partial information on the order of operations (please see individual +/// fields for details), since the end users care about it. Please note that this means multiple +/// instances of [`StateUpdates`] can represent the same transform of state store (i.e. differing +/// only by order of some operations), and hence it is not 100% "canonical form". +#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)] +pub struct StateUpdates { + /// Indexed Node-level updates, captured in the order of first update operation to a Node. + pub by_node: IndexMap, +} + +impl StateUpdates { + /// Starts a Node-level update. + pub fn of_node(&mut self, node_id: NodeId) -> &mut NodeStateUpdates { + self.by_node + .entry(node_id) + .or_insert_with(|| NodeStateUpdates::Delta { + by_partition: index_map_new(), + }) + } + + pub fn rebuild_without_empty_entries(&self) -> Self { + Self { + by_node: self + .by_node + .iter() + .filter_map(|(node_id, by_partition)| { + let by_partition = by_partition.without_empty_entries()?; + Some((*node_id, by_partition)) + }) + .collect(), + } + } + + pub fn into_legacy(self) -> LegacyStateUpdates { + self.into() + } +} + +/// A description of all updates that happened to a state of a single Node. +/// Note: currently, we do not support any Node-wide changes (e.g. deleting entire Node); however, +/// we use an enum for potential future development. +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub enum NodeStateUpdates { + /// A "delta" update to a Node, touching only selected Partitions. + /// Contains indexed Partition-level updates, captured in the order of first update operation to + /// a Partition. + Delta { + by_partition: IndexMap, + }, +} + +impl Default for NodeStateUpdates { + fn default() -> Self { + NodeStateUpdates::Delta { + by_partition: index_map_new(), + } + } +} + +impl NodeStateUpdates { + /// Starts a Partition-level update. + pub fn of_partition(&mut self, partition_num: PartitionNumber) -> &mut PartitionStateUpdates { + match self { + NodeStateUpdates::Delta { by_partition } => { + by_partition.entry(partition_num).or_default() + } + } + } + + pub fn without_empty_entries(&self) -> Option { + match self { + NodeStateUpdates::Delta { by_partition } => { + let replaced = by_partition + .iter() + .filter_map(|(partition_num, partition_state_updates)| { + let new_substate = partition_state_updates.without_empty_entries()?; + Some((*partition_num, new_substate)) + }) + .collect::>(); + if replaced.len() > 0 { + Some(NodeStateUpdates::Delta { + by_partition: replaced, + }) + } else { + None + } + } + } + } +} + +/// A description of all updates that happened to a state of a single Partition. +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub enum PartitionStateUpdates { + /// A "delta" update to a Partition, touching only selected Substates. + /// Contains indexed Substate-level updates, captured in the order of first update operation to + /// a Substate. + Delta { + by_substate: IndexMap, + }, + /// A batch update. + Batch(BatchPartitionStateUpdate), +} + +impl Default for PartitionStateUpdates { + fn default() -> Self { + PartitionStateUpdates::Delta { + by_substate: index_map_new(), + } + } +} + +impl PartitionStateUpdates { + /// Resets the partition to an empty state. + pub fn delete(&mut self) { + *self = PartitionStateUpdates::Batch(BatchPartitionStateUpdate::Reset { + new_substate_values: index_map_new(), + }); + } + + /// Applies the given updates on top of the current updates to the partition. + pub fn update_substates( + &mut self, + updates: impl IntoIterator, + ) { + match self { + PartitionStateUpdates::Delta { by_substate } => by_substate.extend(updates), + PartitionStateUpdates::Batch(BatchPartitionStateUpdate::Reset { + new_substate_values, + }) => { + for (substate_key, database_update) in updates { + match database_update { + DatabaseUpdate::Set(new_value) => { + new_substate_values.insert(substate_key, new_value); + } + DatabaseUpdate::Delete => { + let existed = new_substate_values.swap_remove(&substate_key).is_some(); + if !existed { + panic!("inconsistent update: delete of substate {:?} not existing in reset partition", substate_key); + } + } + } + } + } + } + } + + pub fn without_empty_entries(&self) -> Option { + match self { + PartitionStateUpdates::Delta { by_substate } => { + if by_substate.len() > 0 { + Some(PartitionStateUpdates::Delta { + by_substate: by_substate.clone(), + }) + } else { + None + } + } + PartitionStateUpdates::Batch(x) => { + // We shouldn't filter out batch updates like resets, even if they set nothing new + Some(PartitionStateUpdates::Batch(x.clone())) + } + } + } +} + +/// A description of a batch update affecting an entire Partition. +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub enum BatchPartitionStateUpdate { + /// A reset, dropping all Substates of a partition and replacing them with a new set. + /// Contains indexed new Substate values, captured in the order of creation of a Substate. + Reset { + new_substate_values: IndexMap, + }, +} + +/// An update of a single substate's value. +#[derive(Debug, Clone, Hash, PartialEq, Eq, Sbor, PartialOrd, Ord)] +pub enum DatabaseUpdate { + Set(DbSubstateValue), + Delete, +} + +impl DatabaseUpdate { + pub fn as_ref(&self) -> DatabaseUpdateRef<'_> { + match self { + DatabaseUpdate::Set(update) => DatabaseUpdateRef::Set(update), + DatabaseUpdate::Delete => DatabaseUpdateRef::Delete, + } + } +} + +/// A 1:1 counterpart of [`DatabaseUpdate`], but operating on references. +pub enum DatabaseUpdateRef<'v> { + Set(&'v [u8]), + Delete, +} + +/// A raw substate value stored by the database. +pub type DbSubstateValue = Vec; + +/// A legacy format capturing the same information as new [`StateUpdates`]. +/// Note to migrators: this struct will live only temporarily. The new one should be preferred (and +/// should be the only persisted one). Please use the [`From`] utilities below for easy migration. +#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, Default)] +pub struct LegacyStateUpdates { + /// A set of partitions that were entirely deleted. + /// Note: this batch changes should be applied *before* the [`system_updates`] below (i.e. + /// allowing a latter individual substate creation to be applied). + pub partition_deletions: IndexSet<(NodeId, PartitionNumber)>, + + /// A set of individual substate updates (indexed by partition and substate key). + /// Note to migrators: the type seen below used to be named `SystemUpdates`. + pub system_updates: IndexMap<(NodeId, PartitionNumber), IndexMap>, +} + +impl From for StateUpdates { + fn from(legacy_state_updates: LegacyStateUpdates) -> Self { + let mut state_updates = StateUpdates { + by_node: index_map_new(), + }; + for (node_id, partition_num) in legacy_state_updates.partition_deletions { + state_updates + .of_node(node_id) + .of_partition(partition_num) + .delete(); + } + for ((node_id, partition_num), by_substate) in legacy_state_updates.system_updates { + state_updates + .of_node(node_id) + .of_partition(partition_num) + .update_substates(by_substate); + } + state_updates + } +} + +impl From for LegacyStateUpdates { + fn from(state_updates: StateUpdates) -> Self { + let mut partition_deletions = index_set_new(); + let mut system_updates = index_map_new(); + for (node_id, node_state_updates) in state_updates.by_node { + match node_state_updates { + NodeStateUpdates::Delta { by_partition } => { + for (partition_num, partition_state_updates) in by_partition { + let node_partition = (node_id.clone(), partition_num); + match partition_state_updates { + PartitionStateUpdates::Delta { by_substate } => { + system_updates.insert(node_partition, by_substate); + } + PartitionStateUpdates::Batch(batch) => match batch { + BatchPartitionStateUpdate::Reset { + new_substate_values, + } => { + partition_deletions.insert(node_partition.clone()); + let as_updates = new_substate_values + .into_iter() + .map(|(substate_key, value)| { + (substate_key, DatabaseUpdate::Set(value)) + }) + .collect(); + system_updates.insert(node_partition, as_updates); + } + }, + } + } + } + } + } + LegacyStateUpdates { + partition_deletions, + system_updates, + } + } +} diff --git a/radix-engine-monkey-tests/tests/fuzz_kernel.rs b/radix-engine-monkey-tests/tests/fuzz_kernel.rs index a1e419ea1dd..cc9dad56ef4 100644 --- a/radix-engine-monkey-tests/tests/fuzz_kernel.rs +++ b/radix-engine-monkey-tests/tests/fuzz_kernel.rs @@ -30,6 +30,7 @@ use rand_chacha::rand_core::SeedableRng; use rand_chacha::ChaCha8Rng; use rayon::iter::IntoParallelIterator; use rayon::iter::ParallelIterator; +use scrypto_test::prelude::CreateDatabaseUpdates; struct TestCallFrameData; diff --git a/radix-engine-tests/tests/blueprints/transaction_tracker.rs b/radix-engine-tests/tests/blueprints/transaction_tracker.rs index 249f36d0baf..85f8214fa8d 100644 --- a/radix-engine-tests/tests/blueprints/transaction_tracker.rs +++ b/radix-engine-tests/tests/blueprints/transaction_tracker.rs @@ -1,6 +1,5 @@ use radix_common::prelude::*; use radix_engine::errors::RejectionReason; -use radix_engine::track::{BatchPartitionStateUpdate, NodeStateUpdates, PartitionStateUpdates}; use radix_engine::transaction::ExecutionConfig; use radix_engine_interface::blueprints::consensus_manager::EpochChangeCondition; use radix_transactions::errors::TransactionValidationError; diff --git a/radix-engine-tests/tests/flash/seconds_precision.rs b/radix-engine-tests/tests/flash/seconds_precision.rs index 70598a4a69b..a80bc5cc680 100644 --- a/radix-engine-tests/tests/flash/seconds_precision.rs +++ b/radix-engine-tests/tests/flash/seconds_precision.rs @@ -13,7 +13,7 @@ use radix_engine_tests::common::PackageLoader; use radix_substate_store_interface::db_key_mapper::SpreadPrefixKeyMapper; use radix_substate_store_interface::interface::CommittableSubstateDatabase; use radix_transactions::builder::ManifestBuilder; -use scrypto_test::prelude::{CustomGenesis, LedgerSimulatorBuilder}; +use scrypto_test::prelude::{CreateDatabaseUpdates, CustomGenesis, LedgerSimulatorBuilder}; #[test] fn get_current_time_rounded_to_seconds_without_state_flash_should_fail() { diff --git a/radix-engine-tests/tests/system/schema_sanity_check.rs b/radix-engine-tests/tests/system/schema_sanity_check.rs index 1fe234b2c35..50c8c93703d 100644 --- a/radix-engine-tests/tests/system/schema_sanity_check.rs +++ b/radix-engine-tests/tests/system/schema_sanity_check.rs @@ -381,6 +381,7 @@ fn is_safe_well_known_type( #[derive(Debug, Clone)] pub enum CheckResult { Safe, + #[allow(dead_code)] // Fields are used by the Debug macro PossiblyUnsafe { type_kind: ScryptoTypeKind, type_validation: TypeValidation, diff --git a/radix-engine-tests/tests/system/system_actor_collection.rs b/radix-engine-tests/tests/system/system_actor_collection.rs index bfa110c9e6e..2c332126b56 100644 --- a/radix-engine-tests/tests/system/system_actor_collection.rs +++ b/radix-engine-tests/tests/system/system_actor_collection.rs @@ -7,7 +7,6 @@ use radix_engine_interface::api::{AttachedModuleId, SystemApi, LockFlags, ACTOR_ use radix_engine_interface::blueprints::package::PackageDefinition; use radix_native_sdk::modules::metadata::Metadata; use radix_native_sdk::modules::role_assignment::RoleAssignment; -use radix_substate_store_interface::interface::DatabaseUpdate; use radix_transactions::builder::ManifestBuilder; use scrypto_test::prelude::*; diff --git a/radix-engine-tests/tests/system/system_db_checker.rs b/radix-engine-tests/tests/system/system_db_checker.rs index 55091ea2fbc..a859dec5c18 100644 --- a/radix-engine-tests/tests/system/system_db_checker.rs +++ b/radix-engine-tests/tests/system/system_db_checker.rs @@ -8,9 +8,7 @@ use radix_engine::vm::*; 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::{ - CommittableSubstateDatabase, DatabaseUpdate, DatabaseUpdates, DbPartitionKey, -}; +use radix_substate_store_interface::interface::*; #[test] fn system_database_checker_should_report_missing_owner_error_on_broken_db() { diff --git a/radix-engine/src/system/bootstrap.rs b/radix-engine/src/system/bootstrap.rs index eb9937ddf83..6cacc322e91 100644 --- a/radix-engine/src/system/bootstrap.rs +++ b/radix-engine/src/system/bootstrap.rs @@ -19,10 +19,6 @@ use crate::object_modules::role_assignment::RoleAssignmentNativePackage; use crate::object_modules::royalty::RoyaltyNativePackage; use crate::system::system_db_reader::SystemDatabaseReader; use crate::system::type_info::TypeInfoSubstate; -use crate::track::{ - BatchPartitionStateUpdate, LegacyStateUpdates, NodeStateUpdates, PartitionStateUpdates, - StateUpdates, -}; use crate::transaction::{ execute_transaction, CommitResult, ExecutionConfig, StateUpdateSummary, SubstateSchemaMapper, SubstateSystemStructures, TransactionOutcome, TransactionReceipt, TransactionResult, @@ -44,10 +40,7 @@ use radix_engine_interface::object_modules::ModuleConfig; use radix_engine_interface::{ burn_roles, metadata, metadata_init, mint_roles, rule, withdraw_roles, }; -use radix_substate_store_interface::interface::{ - DatabaseUpdate, DatabaseUpdates, DbPartitionKey, DbSortKey, DbSubstateValue, - PartitionDatabaseUpdates, PartitionEntry, -}; +use radix_substate_store_interface::interface::*; use radix_substate_store_interface::{ db_key_mapper::{MappedSubstateDatabase, SpreadPrefixKeyMapper}, interface::{CommittableSubstateDatabase, SubstateDatabase}, diff --git a/radix-engine/src/system/system_db_reader.rs b/radix-engine/src/system/system_db_reader.rs index 4e787f190b6..1a64471ea11 100644 --- a/radix-engine/src/system/system_db_reader.rs +++ b/radix-engine/src/system/system_db_reader.rs @@ -1,9 +1,4 @@ use crate::internal_prelude::*; -use radix_common::data::scrypto::ScryptoDecode; -use radix_common::prelude::{ - scrypto_decode, scrypto_encode, ScryptoCustomExtension, ScryptoEncode, ScryptoValue, - VersionedScryptoSchema, -}; use radix_engine_interface::api::{AttachedModuleId, CollectionIndex, ModuleId}; use radix_engine_interface::blueprints::package::*; use radix_engine_interface::types::*; @@ -11,7 +6,7 @@ use radix_substate_store_interface::db_key_mapper::{ MappedCommittableSubstateDatabase, SubstateKeyContent, }; use radix_substate_store_interface::interface::{ - CommittableSubstateDatabase, DatabaseUpdate, ListableSubstateDatabase, + CommittableSubstateDatabase, ListableSubstateDatabase, }; use radix_substate_store_interface::{ db_key_mapper::{DatabaseKeyMapper, MappedSubstateDatabase, SpreadPrefixKeyMapper}, @@ -29,9 +24,6 @@ use crate::system::system_type_checker::{ BlueprintTypeTarget, KVStoreTypeTarget, SchemaValidationMeta, }; use crate::system::type_info::TypeInfoSubstate; -use crate::track::{ - BatchPartitionStateUpdate, NodeStateUpdates, PartitionStateUpdates, StateUpdates, -}; use crate::transaction::{ ObjectInstanceTypeReference, ObjectSubstateTypeReference, PackageTypeReference, }; diff --git a/radix-engine/src/track/legacy_state_updates.rs b/radix-engine/src/track/legacy_state_updates.rs deleted file mode 100644 index 8262847dda4..00000000000 --- a/radix-engine/src/track/legacy_state_updates.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::internal_prelude::*; -use crate::track::{ - BatchPartitionStateUpdate, NodeStateUpdates, PartitionStateUpdates, StateUpdates, -}; -use radix_common::types::{NodeId, PartitionNumber, SubstateKey}; -use radix_rust::prelude::{index_map_new, index_set_new, IndexMap, IndexSet}; -use radix_substate_store_interface::interface::DatabaseUpdate; - -/// A legacy format capturing the same information as new [`StateUpdates`]. -/// Note to migrators: this struct will live only temporarily. The new one should be preferred (and -/// should be the only persisted one). Please use the [`From`] utilities below for easy migration. -#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, Default)] -pub struct LegacyStateUpdates { - /// A set of partitions that were entirely deleted. - /// Note: this batch changes should be applied *before* the [`system_updates`] below (i.e. - /// allowing a latter individual substate creation to be applied). - pub partition_deletions: IndexSet<(NodeId, PartitionNumber)>, - - /// A set of individual substate updates (indexed by partition and substate key). - /// Note to migrators: the type seen below used to be named `SystemUpdates`. - pub system_updates: IndexMap<(NodeId, PartitionNumber), IndexMap>, -} - -impl From for StateUpdates { - fn from(legacy_state_updates: LegacyStateUpdates) -> Self { - let mut state_updates = StateUpdates { - by_node: index_map_new(), - }; - for (node_id, partition_num) in legacy_state_updates.partition_deletions { - state_updates - .of_node(node_id) - .of_partition(partition_num) - .delete(); - } - for ((node_id, partition_num), by_substate) in legacy_state_updates.system_updates { - state_updates - .of_node(node_id) - .of_partition(partition_num) - .update_substates(by_substate); - } - state_updates - } -} - -impl From for LegacyStateUpdates { - fn from(state_updates: StateUpdates) -> Self { - let mut partition_deletions = index_set_new(); - let mut system_updates = index_map_new(); - for (node_id, node_state_updates) in state_updates.by_node { - match node_state_updates { - NodeStateUpdates::Delta { by_partition } => { - for (partition_num, partition_state_updates) in by_partition { - let node_partition = (node_id.clone(), partition_num); - match partition_state_updates { - PartitionStateUpdates::Delta { by_substate } => { - system_updates.insert(node_partition, by_substate); - } - PartitionStateUpdates::Batch(batch) => match batch { - BatchPartitionStateUpdate::Reset { - new_substate_values, - } => { - partition_deletions.insert(node_partition.clone()); - let as_updates = new_substate_values - .into_iter() - .map(|(substate_key, value)| { - (substate_key, DatabaseUpdate::Set(value)) - }) - .collect(); - system_updates.insert(node_partition, as_updates); - } - }, - } - } - } - } - } - LegacyStateUpdates { - partition_deletions, - system_updates, - } - } -} diff --git a/radix-engine/src/track/mod.rs b/radix-engine/src/track/mod.rs index 45463323998..bff7811ddef 100644 --- a/radix-engine/src/track/mod.rs +++ b/radix-engine/src/track/mod.rs @@ -1,5 +1,4 @@ pub mod interface; -pub mod legacy_state_updates; pub mod state_updates; pub mod track; @@ -7,6 +6,5 @@ pub mod track; mod test; pub use interface::*; -pub use legacy_state_updates::*; pub use state_updates::*; pub use track::*; diff --git a/radix-engine/src/track/state_updates.rs b/radix-engine/src/track/state_updates.rs index 783b9468ad4..61da85ca1a3 100644 --- a/radix-engine/src/track/state_updates.rs +++ b/radix-engine/src/track/state_updates.rs @@ -1,265 +1,9 @@ use crate::internal_prelude::*; -use crate::track::LegacyStateUpdates; -use radix_substate_store_interface::interface::{ - DatabaseUpdates, DbSubstateValue, NodeDatabaseUpdates, PartitionDatabaseUpdates, -}; -use radix_substate_store_interface::{ - db_key_mapper::DatabaseKeyMapper, - interface::{DatabaseUpdate, DbSortKey}, -}; -use sbor::rust::{cmp::*, iter::*, mem}; +use radix_rust::rust::{iter::*, mem}; +use radix_substate_store_interface::{db_key_mapper::DatabaseKeyMapper, interface::DbSortKey}; use super::TrackedSubstates; -/// A tree-like description of all updates that happened to a stored state, to be included as a part -/// of a transaction receipt. -/// This structure is indexed (i.e. uses [`IndexMap`]s where [`Vec`]s could be used) for convenience -/// and performance, since both the source (i.e. Track) and the sink (i.e. Database and API) operate -/// on indexed structures too. -/// This structure maintains partial information on the order of operations (please see individual -/// fields for details), since the end users care about it. Please note that this means multiple -/// instances of [`StateUpdates`] can represent the same transform of state store (i.e. differing -/// only by order of some operations), and hence it is not 100% "canonical form". -#[derive(Debug, Clone, PartialEq, Eq, Sbor, Default)] -pub struct StateUpdates { - /// Indexed Node-level updates, captured in the order of first update operation to a Node. - pub by_node: IndexMap, -} - -impl StateUpdates { - /// Starts a Node-level update. - pub fn of_node(&mut self, node_id: NodeId) -> &mut NodeStateUpdates { - self.by_node - .entry(node_id) - .or_insert_with(|| NodeStateUpdates::Delta { - by_partition: index_map_new(), - }) - } - - pub fn rebuild_without_empty_entries(&self) -> Self { - Self { - by_node: self - .by_node - .iter() - .filter_map(|(node_id, by_partition)| { - let by_partition = by_partition.without_empty_entries()?; - Some((*node_id, by_partition)) - }) - .collect(), - } - } - - pub fn into_legacy(self) -> LegacyStateUpdates { - self.into() - } -} - -/// A description of all updates that happened to a state of a single Node. -/// Note: currently, we do not support any Node-wide changes (e.g. deleting entire Node); however, -/// we use an enum for potential future development. -#[derive(Debug, Clone, PartialEq, Eq, Sbor)] -pub enum NodeStateUpdates { - /// A "delta" update to a Node, touching only selected Partitions. - /// Contains indexed Partition-level updates, captured in the order of first update operation to - /// a Partition. - Delta { - by_partition: IndexMap, - }, -} - -impl Default for NodeStateUpdates { - fn default() -> Self { - NodeStateUpdates::Delta { - by_partition: index_map_new(), - } - } -} - -impl NodeStateUpdates { - /// Starts a Partition-level update. - pub fn of_partition(&mut self, partition_num: PartitionNumber) -> &mut PartitionStateUpdates { - match self { - NodeStateUpdates::Delta { by_partition } => { - by_partition.entry(partition_num).or_default() - } - } - } - - pub fn without_empty_entries(&self) -> Option { - match self { - NodeStateUpdates::Delta { by_partition } => { - let replaced = by_partition - .iter() - .filter_map(|(partition_num, partition_state_updates)| { - let new_substate = partition_state_updates.without_empty_entries()?; - Some((*partition_num, new_substate)) - }) - .collect::>(); - if replaced.len() > 0 { - Some(NodeStateUpdates::Delta { - by_partition: replaced, - }) - } else { - None - } - } - } - } -} - -/// A description of all updates that happened to a state of a single Partition. -#[derive(Debug, Clone, PartialEq, Eq, Sbor)] -pub enum PartitionStateUpdates { - /// A "delta" update to a Partition, touching only selected Substates. - /// Contains indexed Substate-level updates, captured in the order of first update operation to - /// a Substate. - Delta { - by_substate: IndexMap, - }, - /// A batch update. - Batch(BatchPartitionStateUpdate), -} - -impl Default for PartitionStateUpdates { - fn default() -> Self { - PartitionStateUpdates::Delta { - by_substate: index_map_new(), - } - } -} - -impl PartitionStateUpdates { - /// Resets the partition to an empty state. - pub fn delete(&mut self) { - *self = PartitionStateUpdates::Batch(BatchPartitionStateUpdate::Reset { - new_substate_values: index_map_new(), - }); - } - - /// Applies the given updates on top of the current updates to the partition. - pub fn update_substates( - &mut self, - updates: impl IntoIterator, - ) { - match self { - PartitionStateUpdates::Delta { by_substate } => by_substate.extend(updates), - PartitionStateUpdates::Batch(BatchPartitionStateUpdate::Reset { - new_substate_values, - }) => { - for (substate_key, database_update) in updates { - match database_update { - DatabaseUpdate::Set(new_value) => { - new_substate_values.insert(substate_key, new_value); - } - DatabaseUpdate::Delete => { - let existed = new_substate_values.swap_remove(&substate_key).is_some(); - if !existed { - panic!("inconsistent update: delete of substate {:?} not existing in reset partition", substate_key); - } - } - } - } - } - } - } - - pub fn without_empty_entries(&self) -> Option { - match self { - PartitionStateUpdates::Delta { by_substate } => { - if by_substate.len() > 0 { - Some(PartitionStateUpdates::Delta { - by_substate: by_substate.clone(), - }) - } else { - None - } - } - PartitionStateUpdates::Batch(x) => { - // We shouldn't filter out batch updates like resets, even if they set nothing new - Some(PartitionStateUpdates::Batch(x.clone())) - } - } - } -} - -/// A description of a batch update affecting an entire Partition. -#[derive(Debug, Clone, PartialEq, Eq, Sbor)] -pub enum BatchPartitionStateUpdate { - /// A reset, dropping all Substates of a partition and replacing them with a new set. - /// Contains indexed new Substate values, captured in the order of creation of a Substate. - Reset { - new_substate_values: IndexMap, - }, -} - -impl StateUpdates { - /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. - pub fn create_database_updates(&self) -> DatabaseUpdates { - DatabaseUpdates { - node_updates: self - .by_node - .iter() - .map(|(node_id, node_state_updates)| { - ( - M::to_db_node_key(node_id), - node_state_updates.create_database_updates::(), - ) - }) - .collect(), - } - } -} - -impl NodeStateUpdates { - /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. - pub fn create_database_updates(&self) -> NodeDatabaseUpdates { - match self { - NodeStateUpdates::Delta { by_partition } => NodeDatabaseUpdates { - partition_updates: by_partition - .iter() - .map(|(partition_num, partition_state_updates)| { - ( - M::to_db_partition_num(*partition_num), - partition_state_updates.create_database_updates::(), - ) - }) - .collect(), - }, - } - } -} - -impl PartitionStateUpdates { - /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. - pub fn create_database_updates(&self) -> PartitionDatabaseUpdates { - match self { - PartitionStateUpdates::Delta { by_substate } => PartitionDatabaseUpdates::Delta { - substate_updates: by_substate - .iter() - .map(|(key, update)| (M::to_db_sort_key(key), update.clone())) - .collect(), - }, - PartitionStateUpdates::Batch(batch) => batch.create_database_updates::(), - } - } -} - -impl BatchPartitionStateUpdate { - /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. - pub fn create_database_updates(&self) -> PartitionDatabaseUpdates { - match self { - BatchPartitionStateUpdate::Reset { - new_substate_values, - } => PartitionDatabaseUpdates::Reset { - new_substate_values: new_substate_values - .iter() - .map(|(key, value)| (M::to_db_sort_key(key), value.clone())) - .collect(), - }, - } - } -} - #[derive(Clone, Debug)] pub struct RuntimeSubstate { pub value: IndexedScryptoValue, diff --git a/radix-engine/src/transaction/state_update_summary.rs b/radix-engine/src/transaction/state_update_summary.rs index c036f477898..9c015870a1e 100644 --- a/radix-engine/src/transaction/state_update_summary.rs +++ b/radix-engine/src/transaction/state_update_summary.rs @@ -1,11 +1,9 @@ use crate::blueprints::resource::{FungibleVaultBalanceFieldPayload, FungibleVaultField}; use crate::internal_prelude::*; use crate::system::system_db_reader::SystemDatabaseReader; -use crate::track::{NodeStateUpdates, PartitionStateUpdates, StateUpdates}; use radix_common::data::scrypto::model::*; use radix_common::math::*; use radix_engine_interface::types::*; -use radix_substate_store_interface::interface::DatabaseUpdate; use radix_substate_store_interface::{ db_key_mapper::SpreadPrefixKeyMapper, interface::SubstateDatabase, }; diff --git a/radix-engine/src/transaction/system_structure.rs b/radix-engine/src/transaction/system_structure.rs index e4f882a7394..90c95869aed 100644 --- a/radix-engine/src/transaction/system_structure.rs +++ b/radix-engine/src/transaction/system_structure.rs @@ -4,9 +4,6 @@ use crate::system::system_callback::*; use crate::system::system_db_reader::*; use crate::system::system_type_checker::BlueprintTypeTarget; use crate::system::type_info::TypeInfoSubstate; -use crate::track::{ - BatchPartitionStateUpdate, NodeStateUpdates, PartitionStateUpdates, StateUpdates, -}; use crate::vm::*; use radix_engine_interface::blueprints::package::*; use radix_substate_store_interface::interface::SubstateDatabase; diff --git a/radix-engine/src/transaction/transaction_executor.rs b/radix-engine/src/transaction/transaction_executor.rs index 8e244ac1a10..39502dee60e 100644 --- a/radix-engine/src/transaction/transaction_executor.rs +++ b/radix-engine/src/transaction/transaction_executor.rs @@ -5,13 +5,12 @@ use crate::kernel::kernel::BootLoader; use crate::kernel::kernel_callback_api::*; use crate::system::system_callback::{System, SystemInit}; use crate::system::system_callback_api::SystemCallbackObject; -use crate::track::{BootStore, Track}; +use crate::track::Track; use crate::transaction::*; use crate::vm::wasm::WasmEngine; use crate::vm::{NativeVmExtension, Vm, VmInit}; use radix_common::constants::*; use radix_engine_interface::blueprints::transaction_processor::InstructionOutput; -use radix_substate_store_interface::db_key_mapper::DatabaseKeyMapper; use radix_substate_store_interface::{db_key_mapper::SpreadPrefixKeyMapper, interface::*}; use radix_transactions::model::*; @@ -264,25 +263,6 @@ impl ExecutionConfig { } } -pub struct SubstateBootStore<'a, S: SubstateDatabase> { - boot_store: &'a S, -} - -impl<'a, S: SubstateDatabase> BootStore for SubstateBootStore<'a, S> { - fn read_boot_substate( - &self, - node_id: &NodeId, - partition_num: PartitionNumber, - substate_key: &SubstateKey, - ) -> Option { - let db_partition_key = SpreadPrefixKeyMapper::to_db_partition_key(node_id, partition_num); - let db_sort_key = SpreadPrefixKeyMapper::to_db_sort_key(&substate_key); - self.boot_store - .get_substate(&db_partition_key, &db_sort_key) - .map(|v| IndexedScryptoValue::from_vec(v.to_vec()).unwrap()) - } -} - pub struct TransactionExecutor<'s, S, V: KernelCallbackObject> where S: SubstateDatabase, diff --git a/radix-engine/src/transaction/transaction_receipt.rs b/radix-engine/src/transaction/transaction_receipt.rs index 5dbda8835ff..cad90f496f7 100644 --- a/radix-engine/src/transaction/transaction_receipt.rs +++ b/radix-engine/src/transaction/transaction_receipt.rs @@ -7,14 +7,9 @@ use crate::system::system_db_reader::SystemDatabaseReader; use crate::system::system_modules::costing::*; use crate::system::system_modules::execution_trace::*; use crate::system::system_substate_schemas::*; -use crate::track::BatchPartitionStateUpdate; -use crate::track::NodeStateUpdates; -use crate::track::PartitionStateUpdates; -use crate::track::StateUpdates; use crate::transaction::SystemStructure; use colored::*; use radix_engine_interface::blueprints::transaction_processor::InstructionOutput; -use radix_substate_store_interface::interface::DatabaseUpdate; use radix_transactions::model::Executable; use radix_transactions::prelude::TransactionCostingParametersReceipt; use sbor::representations::*; @@ -1100,7 +1095,7 @@ impl<'a> ContextualDisplay> for Transaction node_id, partition_number, substate_key, - update.as_change(), + update.as_ref(), )?; } } @@ -1125,7 +1120,7 @@ impl<'a> ContextualDisplay> for Transaction node_id, partition_number, substate_key, - SubstateChange::Upsert(value), + DatabaseUpdateRef::Set(value), )?; } } @@ -1229,7 +1224,7 @@ fn display_substate_change<'a, F: fmt::Write>( node_id: &NodeId, partition_number: &PartitionNumber, substate_key: &SubstateKey, - change: SubstateChange, + change: DatabaseUpdateRef, ) -> Result<(), fmt::Error> { let substate_structure = system_structure .substate_system_structures @@ -1240,13 +1235,13 @@ fn display_substate_change<'a, F: fmt::Write>( .get(substate_key) .unwrap(); match change { - SubstateChange::Upsert(substate_value) => { + DatabaseUpdateRef::Set(substate_value) => { write!(f, "\n {prefix} Set: ")?; format_substate_key(f, substate_structure, receipt_context, substate_key)?; write!(f, "\n Value: ")?; format_substate_value(f, substate_structure, receipt_context, substate_value)?; } - SubstateChange::Delete => { + DatabaseUpdateRef::Delete => { write!(f, "\n {prefix} Delete: ")?; format_substate_key(f, substate_structure, receipt_context, substate_key)?; } @@ -1327,7 +1322,7 @@ fn format_substate_value<'a, F: fmt::Write>( f: &mut F, substate_structure: &SubstateSystemStructure, receipt_context: &TransactionReceiptDisplayContext<'a>, - substate_value: &DbSubstateValue, + substate_value: &[u8], ) -> Result<(), fmt::Error> { let print_mode = PrintMode::MultiLine { indent_size: 2, diff --git a/radix-engine/src/updates/anemone.rs b/radix-engine/src/updates/anemone.rs index af7e9bcf19f..a43e20c56d7 100644 --- a/radix-engine/src/updates/anemone.rs +++ b/radix-engine/src/updates/anemone.rs @@ -4,7 +4,6 @@ use crate::blueprints::models::KeyValueEntryContentSource; use crate::blueprints::package::*; use crate::blueprints::pool::v1::constants::*; use crate::system::system_db_reader::*; -use crate::track::*; use crate::vm::*; use sbor::{generate_full_schema, TypeAggregator}; diff --git a/radix-engine/src/updates/bottlenose.rs b/radix-engine/src/updates/bottlenose.rs index 5088459393e..290c9478c01 100644 --- a/radix-engine/src/updates/bottlenose.rs +++ b/radix-engine/src/updates/bottlenose.rs @@ -9,7 +9,6 @@ use crate::object_modules::role_assignment::*; use crate::system::system_callback::*; use crate::system::system_db_reader::*; use crate::system::system_modules::costing::CostingModuleConfig; -use crate::track::*; use crate::transaction::*; use crate::vm::*; use radix_engine_interface::blueprints::access_controller::*; diff --git a/radix-engine/src/updates/mod.rs b/radix-engine/src/updates/mod.rs index 9fcc3829b6e..6553f3730a7 100644 --- a/radix-engine/src/updates/mod.rs +++ b/radix-engine/src/updates/mod.rs @@ -1,4 +1,4 @@ -use crate::{internal_prelude::*, track::StateUpdates}; +use crate::internal_prelude::*; mod anemone; mod bottlenose; mod protocol_builder; diff --git a/radix-substate-store-impls/src/memory_db.rs b/radix-substate-store-impls/src/memory_db.rs index 55f63cea791..d155f1e44d1 100644 --- a/radix-substate-store-impls/src/memory_db.rs +++ b/radix-substate-store-impls/src/memory_db.rs @@ -1,5 +1,5 @@ +use radix_common::prelude::*; use radix_substate_store_interface::interface::*; -use sbor::rust::prelude::*; #[derive(Debug, PartialEq, Eq, Clone)] pub struct InMemorySubstateDatabase { diff --git a/radix-substate-store-impls/src/rocks_db.rs b/radix-substate-store-impls/src/rocks_db.rs index 6c7703f54dc..27cccecd888 100644 --- a/radix-substate-store-impls/src/rocks_db.rs +++ b/radix-substate-store-impls/src/rocks_db.rs @@ -1,5 +1,6 @@ use itertools::Itertools; use radix_common::constants::MAX_SUBSTATE_KEY_SIZE; +use radix_common::prelude::*; use radix_rust::copy_u8_array; use radix_substate_store_interface::interface::*; pub use rocksdb::{BlockBasedOptions, LogLevel, Options}; @@ -7,7 +8,6 @@ use rocksdb::{ ColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, Direction, IteratorMode, SingleThreaded, DB, }; -use sbor::rust::prelude::*; use std::path::PathBuf; pub struct RocksdbSubstateStore { 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 7f96c085f0f..dedca56a10c 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 @@ -1,16 +1,13 @@ use crate::state_tree::tree_store::*; use itertools::Itertools; use radix_common::constants::MAX_SUBSTATE_KEY_SIZE; -use radix_common::data::scrypto::{scrypto_decode, scrypto_encode}; -use radix_common::prelude::Hash; -use radix_common::ScryptoSbor; +use radix_common::prelude::*; use radix_substate_store_interface::interface::*; pub use rocksdb::{BlockBasedOptions, LogLevel, Options}; use rocksdb::{ ColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, Direction, IteratorMode, SingleThreaded, WriteBatch, DB, }; -use sbor::prelude::*; use std::path::PathBuf; mod state_tree; diff --git a/radix-substate-store-impls/src/state_tree/substate_tier.rs b/radix-substate-store-impls/src/state_tree/substate_tier.rs index 16ab3d85463..1409ce778f9 100644 --- a/radix-substate-store-impls/src/state_tree/substate_tier.rs +++ b/radix-substate-store-impls/src/state_tree/substate_tier.rs @@ -2,8 +2,7 @@ use super::jellyfish::TreeUpdateBatch; use super::tier_framework::*; use super::tree_store::*; use super::types::*; -use radix_common::crypto::{hash, Hash}; -use radix_rust::prelude::*; +use radix_common::prelude::*; use radix_substate_store_interface::interface::*; /// The bottom tier of the 3-tier JMT, corresponding to the `DbSortKey` part of a substate key. @@ -219,8 +218,8 @@ impl<'s, S: ReadableTreeStore + WriteableTreeStore> SubstateTier<'s, S> { let substate_value = substate_updates .get_substate_change(&sort_key) .map(|change| match change { - SubstateChange::Upsert(value) => AssociatedSubstateValue::Upserted(value), - SubstateChange::Delete => { + DatabaseUpdateRef::Set(value) => AssociatedSubstateValue::Upserted(value), + DatabaseUpdateRef::Delete => { panic!("deletes are not represented by new tree leafs") } }) diff --git a/radix-substate-store-impls/src/state_tree/test.rs b/radix-substate-store-impls/src/state_tree/test.rs index a4cc4a95fe4..a90d226fafe 100644 --- a/radix-substate-store-impls/src/state_tree/test.rs +++ b/radix-substate-store-impls/src/state_tree/test.rs @@ -7,7 +7,7 @@ use crate::state_tree::substate_tier::SubstateSummary; use itertools::Itertools; use radix_common::crypto::{hash, Hash}; use radix_common::data::scrypto::{scrypto_decode, scrypto_encode}; -use radix_rust::prelude::*; +use radix_common::prelude::*; use radix_substate_store_interface::interface::*; use sbor::prelude::indexmap::indexmap; use std::ops::Deref; diff --git a/radix-substate-store-impls/src/state_tree/tree_store.rs b/radix-substate-store-impls/src/state_tree/tree_store.rs index 9ca9fdab71a..44d036782b8 100644 --- a/radix-substate-store-impls/src/state_tree/tree_store.rs +++ b/radix-substate-store-impls/src/state_tree/tree_store.rs @@ -3,17 +3,10 @@ use super::tier_framework::StoredNode; pub use super::types::{Nibble, NibblePath, TreeNodeKey, Version}; use super::{Node, StorageError, TreeReader}; -use radix_common::crypto::Hash; -use radix_common::data::scrypto::{scrypto_decode, scrypto_encode}; -use radix_rust::rust::collections::VecDeque; -use radix_rust::rust::collections::{hash_map_new, HashMap}; -use radix_rust::rust::vec::Vec; -use radix_substate_store_interface::interface::{ - DbPartitionKey, DbSortKey, DbSubstateKey, DbSubstateValue, -}; +use radix_common::prelude::*; +use radix_substate_store_interface::interface::*; use sbor::rust::cell::Ref; use sbor::rust::cell::RefCell; -use sbor::*; define_single_versioned! { #[derive(Clone, PartialEq, Eq, Hash, Debug, Sbor)] @@ -177,7 +170,7 @@ pub trait WriteableTreeStore { /// avoid this potential performance implication by having an explicit way of associating an /// "unchanged" Substate with its new tree leaf. pub enum AssociatedSubstateValue<'v> { - Upserted(&'v DbSubstateValue), + Upserted(&'v [u8]), Unchanged, } @@ -256,7 +249,7 @@ impl WriteableTreeStore for TypedInMemoryTreeStore { ) { if self.store_associated_substates { let substate_value = match substate_value { - AssociatedSubstateValue::Upserted(value) => Some(value.clone()), + AssociatedSubstateValue::Upserted(value) => Some(value.to_owned()), AssociatedSubstateValue::Unchanged => None, }; self.associated_substates.borrow_mut().insert( diff --git a/radix-substate-store-impls/src/state_tree/types.rs b/radix-substate-store-impls/src/state_tree/types.rs index 1e4218a3828..2671b022474 100644 --- a/radix-substate-store-impls/src/state_tree/types.rs +++ b/radix-substate-store-impls/src/state_tree/types.rs @@ -1169,7 +1169,7 @@ impl From> for Node { impl Node

{ /// Creates the [`Internal`](Node::Internal) variant. - #[cfg(any(test, feature = "fuzzing"))] + #[cfg(test)] pub fn new_internal(children: Children) -> Self { Node::Internal(InternalNode::new(children)) } diff --git a/radix-substate-store-impls/src/state_tree_support.rs b/radix-substate-store-impls/src/state_tree_support.rs index 2876ad2adb8..a8dfd19dfea 100644 --- a/radix-substate-store-impls/src/state_tree_support.rs +++ b/radix-substate-store-impls/src/state_tree_support.rs @@ -1,10 +1,7 @@ use crate::state_tree::tree_store::{TypedInMemoryTreeStore, Version}; use crate::state_tree::{list_substate_hashes_at_version, put_at_next_version}; use radix_common::prelude::*; -use radix_substate_store_interface::interface::{ - CommittableSubstateDatabase, DatabaseUpdates, DbPartitionKey, DbSortKey, DbSubstateValue, - ListableSubstateDatabase, PartitionEntry, SubstateDatabase, -}; +use radix_substate_store_interface::interface::*; #[derive(Debug, PartialEq, Eq, Clone)] pub struct StateTreeUpdatingDatabase { diff --git a/radix-substate-store-interface/src/db_key_mapper.rs b/radix-substate-store-interface/src/db_key_mapper.rs index bf2b159b79c..96db906e8d0 100644 --- a/radix-substate-store-interface/src/db_key_mapper.rs +++ b/radix-substate-store-interface/src/db_key_mapper.rs @@ -1,13 +1,9 @@ use crate::interface::{ - CommittableSubstateDatabase, DatabaseUpdate, DatabaseUpdates, DbNodeKey, DbPartitionKey, - DbPartitionNum, DbSortKey, SubstateDatabase, + CommittableSubstateDatabase, DatabaseUpdates, DbNodeKey, DbPartitionKey, DbPartitionNum, + DbSortKey, SubstateDatabase, }; -use radix_common::crypto::hash; -use radix_common::data::scrypto::{scrypto_decode, scrypto_encode, ScryptoDecode, ScryptoEncode}; -use radix_common::types::{FieldKey, MapKey, PartitionNumber, SortedKey}; -use radix_common::types::{NodeId, SubstateKey}; +use radix_common::prelude::*; use radix_rust::copy_u8_array; -use sbor::rust::prelude::*; /// A mapper between the business ReNode / Partition / Substate IDs and database keys. pub trait DatabaseKeyMapper { diff --git a/radix-substate-store-interface/src/interface.rs b/radix-substate-store-interface/src/interface.rs index 540861a83e9..7d1773a51d7 100644 --- a/radix-substate-store-interface/src/interface.rs +++ b/radix-substate-store-interface/src/interface.rs @@ -1,3 +1,4 @@ +use super::db_key_mapper::DatabaseKeyMapper; use radix_common::prelude::*; pub type DbNodeKey = Vec; @@ -23,12 +24,16 @@ pub struct DbSortKey(pub Vec); /// A fully-specified key of a substate (i.e. specifying its partition and sort key). pub type DbSubstateKey = (DbPartitionKey, DbSortKey); -/// A raw substate value stored by the database. -pub type DbSubstateValue = Vec; - /// A key-value entry of a substate within a known partition. pub type PartitionEntry = (DbSortKey, DbSubstateValue); +pub trait CreateDatabaseUpdates { + type DatabaseUpdates; + + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. + fn create_database_updates(&self) -> Self::DatabaseUpdates; +} + /// A canonical description of all database updates to be applied. /// Note: this struct can be migrated to an enum if we ever have a need for database-wide batch /// changes (see [`PartitionDatabaseUpdates`] enum). @@ -38,6 +43,26 @@ pub struct DatabaseUpdates { pub node_updates: IndexMap, } +impl CreateDatabaseUpdates for StateUpdates { + type DatabaseUpdates = DatabaseUpdates; + + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. + fn create_database_updates(&self) -> DatabaseUpdates { + DatabaseUpdates { + node_updates: self + .by_node + .iter() + .map(|(node_id, node_state_updates)| { + ( + M::to_db_node_key(node_id), + node_state_updates.create_database_updates::(), + ) + }) + .collect(), + } + } +} + /// A canonical description of specific Node's updates to be applied. /// Note: this struct can be migrated to an enum if we ever have a need for Node-wide batch changes /// (see [`PartitionDatabaseUpdates`] enum). @@ -47,6 +72,27 @@ pub struct NodeDatabaseUpdates { pub partition_updates: IndexMap, } +impl CreateDatabaseUpdates for NodeStateUpdates { + type DatabaseUpdates = NodeDatabaseUpdates; + + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. + fn create_database_updates(&self) -> NodeDatabaseUpdates { + match self { + NodeStateUpdates::Delta { by_partition } => NodeDatabaseUpdates { + partition_updates: by_partition + .iter() + .map(|(partition_num, partition_state_updates)| { + ( + M::to_db_partition_num(*partition_num), + partition_state_updates.create_database_updates::(), + ) + }) + .collect(), + }, + } + } +} + /// A canonical description of specific Partition's updates to be applied. #[derive(Debug, Clone, PartialEq, Eq, Sbor)] pub enum PartitionDatabaseUpdates { @@ -67,51 +113,63 @@ impl PartitionDatabaseUpdates { /// /// This method is useful for index-updating logic which does not care about the nature of the /// Partition update (i.e. delta vs reset). - pub fn get_substate_change(&self, sort_key: &DbSortKey) -> Option { + pub fn get_substate_change(&self, sort_key: &DbSortKey) -> Option { match self { Self::Delta { substate_updates } => { substate_updates.get(sort_key).map(|update| match update { - DatabaseUpdate::Set(value) => SubstateChange::Upsert(value), - DatabaseUpdate::Delete => SubstateChange::Delete, + DatabaseUpdate::Set(value) => DatabaseUpdateRef::Set(value), + DatabaseUpdate::Delete => DatabaseUpdateRef::Delete, }) } Self::Reset { new_substate_values, } => new_substate_values .get(sort_key) - .map(|value| SubstateChange::Upsert(value)) - .or_else(|| Some(SubstateChange::Delete)), + .map(|value| DatabaseUpdateRef::Set(value)) + .or_else(|| Some(DatabaseUpdateRef::Delete)), } } } -/// A change applied to a Substate - see [`PartitionDatabaseUpdates::get_substate_change`]. -/// Technically, this is a 1:1 counterpart of [`DatabaseUpdate`], but operating on references. -pub enum SubstateChange<'v> { - Upsert(&'v DbSubstateValue), - Delete, -} +impl CreateDatabaseUpdates for PartitionStateUpdates { + type DatabaseUpdates = PartitionDatabaseUpdates; -impl Default for PartitionDatabaseUpdates { - fn default() -> Self { - Self::Delta { - substate_updates: index_map_new(), + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. + fn create_database_updates(&self) -> PartitionDatabaseUpdates { + match self { + PartitionStateUpdates::Delta { by_substate } => PartitionDatabaseUpdates::Delta { + substate_updates: by_substate + .iter() + .map(|(key, update)| (M::to_db_sort_key(key), update.clone())) + .collect(), + }, + PartitionStateUpdates::Batch(batch) => batch.create_database_updates::(), } } } -/// An update of a single substate's value. -#[derive(Debug, Clone, Hash, PartialEq, Eq, Sbor, PartialOrd, Ord)] -pub enum DatabaseUpdate { - Set(DbSubstateValue), - Delete, -} +impl CreateDatabaseUpdates for BatchPartitionStateUpdate { + type DatabaseUpdates = PartitionDatabaseUpdates; -impl DatabaseUpdate { - pub fn as_change(&self) -> SubstateChange<'_> { + /// Uses the given [`DatabaseKeyMapper`] to express self using database-level key encoding. + fn create_database_updates(&self) -> PartitionDatabaseUpdates { match self { - DatabaseUpdate::Set(update) => SubstateChange::Upsert(update), - DatabaseUpdate::Delete => SubstateChange::Delete, + BatchPartitionStateUpdate::Reset { + new_substate_values, + } => PartitionDatabaseUpdates::Reset { + new_substate_values: new_substate_values + .iter() + .map(|(key, value)| (M::to_db_sort_key(key), value.clone())) + .collect(), + }, + } + } +} + +impl Default for PartitionDatabaseUpdates { + fn default() -> Self { + Self::Delta { + substate_updates: index_map_new(), } } } diff --git a/radix-transaction-scenarios/src/scenarios/maya_router.rs b/radix-transaction-scenarios/src/scenarios/maya_router.rs index 82127d64320..bfd3f16087f 100644 --- a/radix-transaction-scenarios/src/scenarios/maya_router.rs +++ b/radix-transaction-scenarios/src/scenarios/maya_router.rs @@ -9,25 +9,13 @@ use radix_engine_interface::*; pub struct MayaRouterScenarioConfig { pub owner_private_key: PrivateKey, pub swapper_private_key: PrivateKey, - pub asgard_vault_1_private_key: PrivateKey, - pub asgard_vault_2_private_key: PrivateKey, - pub asgard_vault_1_public_key: PublicKey, - pub asgard_vault_2_public_key: PublicKey, } impl Default for MayaRouterScenarioConfig { fn default() -> Self { - let key_1 = new_secp256k1_private_key(2); - let key_2 = new_ed25519_private_key(2); - let pub_key_1 = key_1.public_key(); - let pub_key_2 = key_2.public_key(); Self { owner_private_key: new_ed25519_private_key(3).into(), swapper_private_key: new_secp256k1_private_key(1).into(), - asgard_vault_1_private_key: key_1.into(), - asgard_vault_2_private_key: key_2.into(), - asgard_vault_1_public_key: pub_key_1.into(), - asgard_vault_2_public_key: pub_key_2.into(), } } } diff --git a/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs b/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs index a4ec485d646..bd25057fe91 100644 --- a/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs +++ b/radix-transaction-scenarios/src/scenarios/non_fungible_resource_with_remote_type.rs @@ -8,7 +8,6 @@ use radix_engine_interface::*; #[allow(deprecated)] pub struct NonFungibleResourceWithRemoteTypeScenarioConfig { pub main_account: PreallocatedAccount, - pub occasional_recipient_account: PreallocatedAccount, } #[derive(Default)] @@ -22,7 +21,6 @@ impl Default for NonFungibleResourceWithRemoteTypeScenarioConfig { fn default() -> Self { Self { main_account: secp256k1_account_1(), - occasional_recipient_account: secp256k1_account_2(), } } } diff --git a/radix-transactions/src/model/any_transaction_payload_schema.txt b/radix-transactions/src/model/any_transaction_payload_schema.txt new file mode 100644 index 00000000000..87d0b15c3db --- /dev/null +++ b/radix-transactions/src/model/any_transaction_payload_schema.txt @@ -0,0 +1 @@ +5c210222000121032022360f012307200701220401010a010000000000000001010a030000000000000001010a060000000000000001010a080000000000000002220201010a130000000000000001010a140000000000000003220201010a1a0000000000000001010a1b0000000000000004220401010a030000000000000001010a060000000000000001010a1c0000000000000001010a1f000000000000000522040001070501010a020000000000000001010a200000000000000001010a210000000000000007220101010a22000000000000000822020001070c01010a28000000000000000e012022070001070701010a020000000000000001010a020000000000000000010709000107d000010701000107080a000d012201010a04000000000000000f012307201e0222010001078500220200010785000107c00122020001078501010a0500000000000000032201000107a10622010001078504220200010785000107c00522020001078501010a0500000000000000102200112201000107a414220200010785000107c01522020001078501010a050000000000000016220100010785122200132200172200212202000107a1000107c0222202000107a101010a0500000000000000232201000107a1242201000107a1302201000107a4312201000107a4402204000107830001070c0001070c00010740412203000107810001070c00010740422203000107810001070c00010740432203000107810001070c00010740442203000107810001070c00010740452203000107820001070c00010740522200502200512202000107830001070c0d0122000107c20d012201010a07000000000000000d0122000107070f012307200300220001220101010a090000000000000002220101010a0b000000000000000e012022020001070c01010a0a000000000000000f01230720020022010001070c012201000107410e0120220201010a0c0000000000000001010a0d000000000000000d01220001070710022201010a0e000000000000002201010a0f000000000000000f01230720020022000122000f0123072002002202000107d201010a1000000000000000012202000107d101010a100000000000000010022201010a11000000000000002201010a12000000000000000d0122000107070d0122000107070e0120220401010a010000000000000001010a030000000000000001010a060000000000000001010a08000000000000000d012201010a15000000000000000f012307200200220101010a1600000000000000012202000107d201010a18000000000000000e0120220101010a17000000000000000d0122000107070e0120220101010a19000000000000000d0122000107070e0120220201010a130000000000000001010a14000000000000000f012307200200220101010a160000000000000001220101010a18000000000000000d012201010a1d000000000000000e0120220201010a1e00000000000000000107810e01202202000107830001070c0d0122000107070a000e012022030001074100010707000107010f012307200400220101010a230000000000000001220101010a250000000000000002220101010a260000000000000003220101010a27000000000000000f012307200200220001220101010a24000000000000000e0120220401010a030000000000000001010a060000000000000001010a1c0000000000000001010a1f000000000000000e0120220201010a1a0000000000000001010a1b000000000000000e012022040001070501010a020000000000000001010a200000000000000001010a21000000000000000e012022020001070c01010a28000000000000000e0120220101010a290000000000000010022201010a2a000000000000002201010a2b000000000000000d0122000107070f012307200100220101010a2c0000000000000010022201010a2d000000000000002201010a2e0000000000000007000f012307200200220101010a2f0000000000000001220101010a340000000000000010022201010a30000000000000002201010a33000000000000000f0123072003002201000107070122010001074102220101010a31000000000000000e0120220201010a3200000000000000000107410d0122000107070f0123072002002201000107410122000f012307200100220101010a350000000000000010022201010a30000000000000002200010741202136022201010c1b56657273696f6e65645472616e73616374696f6e5061796c6f61642201012201012307210701022201010c08496e74656e745631220101220001200c04066865616465720c696e737472756374696f6e7305626c6f6273076d65737361676502022201010c0e5369676e6564496e74656e745631220101220001200c0206696e74656e7411696e74656e745f7369676e61747572657303022201010c164e6f746172697a65645472616e73616374696f6e5631220101220001200c020d7369676e65645f696e74656e74106e6f746172795f7369676e617475726504022201010c1353797374656d5472616e73616374696f6e5631220101220001200c040c696e737472756374696f6e7305626c6f6273177072655f616c6c6f63617465645f61646472657373657312686173685f666f725f657865637574696f6e05022201010c18526f756e645570646174655472616e73616374696f6e5631220101220001200c041570726f706f7365725f74696d657374616d705f6d730565706f636805726f756e64176c65616465725f70726f706f73616c5f686973746f727907022201010c114c65646765725472616e73616374696f6e22000008022201010c12466c6173685472616e73616374696f6e5631220101220001200c02046e616d650d73746174655f75706461746573022201010c135472616e73616374696f6e4865616465725631220101220001200c070a6e6574776f726b5f69641573746172745f65706f63685f696e636c757369766513656e645f65706f63685f6578636c7573697665056e6f6e6365116e6f746172795f7075626c69635f6b6579136e6f746172795f69735f7369676e61746f72790e7469705f70657263656e74616765022201010c0545706f6368220000022201010c0e496e737472756374696f6e735631220000022201010c0d496e737472756374696f6e56312201012201012307211e02022201010c1254616b65416c6c46726f6d576f726b746f70220101220001200c01107265736f757263655f6164647265737300022201010c0f54616b6546726f6d576f726b746f70220101220001200c02107265736f757263655f6164647265737306616d6f756e7401022201010c1b54616b654e6f6e46756e6769626c657346726f6d576f726b746f70220101220001200c02107265736f757263655f616464726573730369647303022201010c0f52657475726e546f576f726b746f70220101220001200c01096275636b65745f696406022201010c18417373657274576f726b746f70436f6e7461696e73416e79220101220001200c01107265736f757263655f6164647265737304022201010c15417373657274576f726b746f70436f6e7461696e73220101220001200c02107265736f757263655f6164647265737306616d6f756e7405022201010c21417373657274576f726b746f70436f6e7461696e734e6f6e46756e6769626c6573220101220001200c02107265736f757263655f616464726573730369647310022201010c0f506f7046726f6d417574685a6f6e6522000011022201010c0e50757368546f417574685a6f6e65220101220001200c010870726f6f665f696414022201010c1f43726561746550726f6f6646726f6d417574685a6f6e654f66416d6f756e74220101220001200c02107265736f757263655f6164647265737306616d6f756e7415022201010c2543726561746550726f6f6646726f6d417574685a6f6e654f664e6f6e46756e6769626c6573220101220001200c02107265736f757263655f616464726573730369647316022201010c1c43726561746550726f6f6646726f6d417574685a6f6e654f66416c6c220101220001200c01107265736f757263655f6164647265737312022201010c1244726f70417574685a6f6e6550726f6f667322000013022201010c1944726f70417574685a6f6e65526567756c617250726f6f667322000017022201010c1b44726f70417574685a6f6e655369676e617475726550726f6f667322000021022201010c1d43726561746550726f6f6646726f6d4275636b65744f66416d6f756e74220101220001200c02096275636b65745f696406616d6f756e7422022201010c2343726561746550726f6f6646726f6d4275636b65744f664e6f6e46756e6769626c6573220101220001200c02096275636b65745f69640369647323022201010c1a43726561746550726f6f6646726f6d4275636b65744f66416c6c220101220001200c01096275636b65745f696424022201010c0c4275726e5265736f75726365220101220001200c01096275636b65745f696430022201010c0a436c6f6e6550726f6f66220101220001200c010870726f6f665f696431022201010c0944726f7050726f6f66220101220001200c010870726f6f665f696440022201010c0c43616c6c46756e6374696f6e220101220001200c040f7061636b6167655f616464726573730e626c75657072696e745f6e616d650d66756e6374696f6e5f6e616d65046172677341022201010c0a43616c6c4d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677342022201010c1143616c6c526f79616c74794d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677343022201010c1243616c6c4d657461646174614d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677344022201010c1843616c6c526f6c6541737369676e6d656e744d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677345022201010c1543616c6c4469726563745661756c744d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677352022201010c0f44726f704e616d656450726f6f667322000050022201010c0d44726f70416c6c50726f6f667322000051022201010c15416c6c6f63617465476c6f62616c41646472657373220101220001200c020f7061636b6167655f616464726573730e626c75657072696e745f6e616d6502220000220000022201010c07426c6f62735631220000022201010c06426c6f625631220000022201010c094d65737361676556312201012201012307210300022201010c044e6f6e6522000001022201010c09506c61696e7465787422000002022201010c09456e63727970746564220000022201010c12506c61696e746578744d6573736167655631220101220001200c02096d696d655f74797065076d657373616765022201010c114d657373616765436f6e74656e747356312201012201012307210200022201010c06537472696e6722000001022201010c054279746573220000022201010c12456e637279707465644d6573736167655631220101220001200c0209656e6372797074656413646563727970746f72735f62795f6375727665022201010c0d41657347636d5061796c6f616422000002220000220000022201010c094375727665547970652201012201012307210200022201010c074564323535313922000001022201010c09536563703235366b31220000022201010c11446563727970746f7273427943757276652201012201012307210200022201010c0745643235353139220101220001200c021764685f657068656d6572616c5f7075626c69635f6b65790a646563727970746f727301022201010c09536563703235366b31220101220001200c021764685f657068656d6572616c5f7075626c69635f6b65790a646563727970746f727302220000220000022201010c145075626c69634b657946696e6765727072696e74220000022201010c13416573577261707065643132384269744b6579220000022201010c08496e74656e745631220101220001200c04066865616465720c696e737472756374696f6e7305626c6f6273076d657373616765022201010c12496e74656e745369676e6174757265735631220000022201010c11496e74656e745369676e617475726556312201012201012307210200022201010c09536563703235366b31220101220001200c01097369676e617475726501022201010c0745643235353139220101220001200c020a7075626c69635f6b6579097369676e6174757265022201010c12536563703235366b315369676e617475726522000002220000220000022201010c10456432353531395369676e617475726522000002220000220000022201010c0e5369676e6564496e74656e745631220101220001200c0206696e74656e7411696e74656e745f7369676e617475726573022201010c114e6f746172795369676e617475726556312201012201012307210200022201010c09536563703235366b3122000001022201010c074564323535313922000002220000220000022201010c13507265416c6c6f636174656441646472657373220101220001200c020c626c75657072696e745f69640761646472657373022201010c0b426c75657072696e744964220101220001200c020f7061636b6167655f616464726573730e626c75657072696e745f6e616d65022201010c0448617368220000022201010c05526f756e64220000022201010c154c656164657250726f706f73616c486973746f7279220101220001200c03116761705f726f756e645f6c6561646572730e63757272656e745f6c65616465720b69735f66616c6c6261636b022201010c114c65646765725472616e73616374696f6e2201012201012307210400022201010c0747656e6573697322000001022201010c0655736572563122000002022201010c0d526f756e64557064617465563122000003022201010c07466c6173685631220000022201010c1247656e657369735472616e73616374696f6e2201012201012307210200022201010c05466c61736822000001022201010c0b5472616e73616374696f6e220000022201010c1353797374656d5472616e73616374696f6e5631220101220001200c040c696e737472756374696f6e7305626c6f6273177072655f616c6c6f63617465645f61646472657373657312686173685f666f725f657865637574696f6e022201010c164e6f746172697a65645472616e73616374696f6e5631220101220001200c020d7369676e65645f696e74656e74106e6f746172795f7369676e6174757265022201010c18526f756e645570646174655472616e73616374696f6e5631220101220001200c041570726f706f7365725f74696d657374616d705f6d730565706f636805726f756e64176c65616465725f70726f706f73616c5f686973746f7279022201010c12466c6173685472616e73616374696f6e5631220101220001200c02046e616d650d73746174655f75706461746573022201010c0c537461746555706461746573220101220001200c010762795f6e6f646502220000220000022201010c064e6f64654964220000022201010c104e6f64655374617465557064617465732201012201012307210100022201010c0544656c7461220101220001200c010c62795f706172746974696f6e02220000220000022201010c0f506172746974696f6e4e756d626572220000022201010c15506172746974696f6e5374617465557064617465732201012201012307210200022201010c0544656c7461220101220001200c010b62795f737562737461746501022201010c05426174636822000002220000220000022201010c0b53756273746174654b65792201012201012307210300022201010c054669656c6422000001022201010c034d617022000002022201010c06536f727465642200000222000022000002220000220000022201010c0e44617461626173655570646174652201012201012307210200022201010c0353657422000001022201010c0644656c657465220000022201010c194261746368506172746974696f6e53746174655570646174652201012201012307210100022201010c055265736574220101220001200c01136e65775f73756273746174655f76616c75657302220000220000202236000000000000000000000000000000000000000000000000000000000000000000000c012102220101090800000022010109080000000c0121022201010918000000220101091800000000000000000000000c0121022201010941000000220101094100000000000c01210222010109400000002201010940000000000000000000000000000c0121022201010920000000220101092000000000000000000000000000000000000000000000000c012102220101091e000000220101091e00000000000000000000000000000000000c012102220101090200000022010109020000000000000000002201010a0000000000000000 \ No newline at end of file diff --git a/radix-clis/src/replay/ledger_transaction.rs b/radix-transactions/src/model/ledger_transaction.rs similarity index 62% rename from radix-clis/src/replay/ledger_transaction.rs rename to radix-transactions/src/model/ledger_transaction.rs index 7e2828617ad..5cf033895d6 100644 --- a/radix-clis/src/replay/ledger_transaction.rs +++ b/radix-transactions/src/model/ledger_transaction.rs @@ -1,220 +1,7 @@ -use radix_common::prelude::*; -use radix_engine_interface::blueprints::consensus_manager::*; -use radix_engine_interface::prelude::system_execution; -use radix_transactions::define_raw_transaction_payload; -use radix_transactions::prelude::*; -use sbor::SborFixedEnumVariant; - -#[derive(Debug, Clone, Categorize, Encode, Decode, PartialEq, Eq)] -pub struct RoundUpdateTransactionV1 { - pub proposer_timestamp_ms: i64, - pub epoch: Epoch, - pub round: Round, - pub leader_proposal_history: LeaderProposalHistory, -} - -impl RoundUpdateTransactionV1 { - pub fn create_instructions(&self) -> Vec { - vec![InstructionV1::CallMethod { - address: CONSENSUS_MANAGER.into(), - method_name: CONSENSUS_MANAGER_NEXT_ROUND_IDENT.to_string(), - args: to_manifest_value(&ConsensusManagerNextRoundInput { - round: self.round, - proposer_timestamp_ms: self.proposer_timestamp_ms, - leader_proposal_history: self.leader_proposal_history.clone(), - }) - .expect("round update input encoding should succeed"), - }] - } - - pub fn prepare(&self) -> Result { - let prepared_instructions = InstructionsV1(self.create_instructions()).prepare_partial()?; - let encoded_source = manifest_encode(&self)?; - // Minor TODO - for a slight performance improvement, change this to be read from the decoder - // As per the other hashes, don't include the prefix byte - let source_hash = hash(&encoded_source[1..]); - let instructions_hash = prepared_instructions.summary.hash; - let round_update_hash = HashAccumulator::new() - .update([ - TRANSACTION_HASHABLE_PAYLOAD_PREFIX, - TransactionDiscriminator::V1RoundUpdate as u8, - ]) - // We include the full source transaction contents - .update(source_hash) - // We also include the instructions hash, so the exact instructions can be proven - .update(instructions_hash) - .finalize(); - Ok(PreparedRoundUpdateTransactionV1 { - encoded_instructions: manifest_encode(&prepared_instructions.inner.0)?, - references: prepared_instructions.references, - blobs: index_map_new(), - summary: Summary { - effective_length: prepared_instructions.summary.effective_length, - total_bytes_hashed: prepared_instructions.summary.total_bytes_hashed, - hash: round_update_hash, - }, - }) - } -} - -impl TransactionPayload for RoundUpdateTransactionV1 { - type Prepared = PreparedRoundUpdateTransactionV1; - type Raw = RawRoundUpdateTransactionV1; -} - -// This shouldn't be implemented manually -// Instead we should move/consolidate all transactions into the transaction crate, -// including fixing VersionedTransactionPayload to be comprehensive -impl SborEnumVariantFor - for RoundUpdateTransactionV1 -{ - const DISCRIMINATOR: u8 = { TransactionDiscriminator::V1Ledger as u8 }; - const IS_FLATTENED: bool = true; - - type VariantFields = Self; - fn from_variant_fields(variant_fields: Self::VariantFields) -> Self { - variant_fields - } - - type VariantFieldsRef<'a> = &'a Self; - fn as_variant_fields_ref(&self) -> Self::VariantFieldsRef<'_> { - self - } - - /// For use Decoding from the enum to its fields - type OwnedVariant = sbor::SborFixedEnumVariant< - { TransactionDiscriminator::V1Ledger as u8 }, - Self::VariantFields, - >; - /// For use Encoding to the enum from a reference to its fields - type BorrowedVariant<'a> = sbor::SborFixedEnumVariant< - { TransactionDiscriminator::V1Ledger as u8 }, - Self::VariantFieldsRef<'a>, - >; - - fn into_enum(self) -> VersionedTransactionPayload { - unimplemented!() - } -} - -pub struct PreparedRoundUpdateTransactionV1 { - pub encoded_instructions: Vec, - pub references: IndexSet, - pub blobs: IndexMap>, - pub summary: Summary, -} - -impl HasSummary for PreparedRoundUpdateTransactionV1 { - fn get_summary(&self) -> &Summary { - &self.summary - } -} - -define_raw_transaction_payload!(RawRoundUpdateTransactionV1); - -impl TransactionPayloadPreparable for PreparedRoundUpdateTransactionV1 { - type Raw = RawRoundUpdateTransactionV1; - - fn prepare_for_payload(decoder: &mut TransactionDecoder) -> Result { - let decoded_variant = decoder.decode()?; - RoundUpdateTransactionV1::from_decoded_variant(decoded_variant).prepare() - } -} - -impl TransactionFullChildPreparable for PreparedRoundUpdateTransactionV1 { - fn prepare_as_full_body_child(decoder: &mut TransactionDecoder) -> Result { - let decoded = decoder.decode::()?; - decoded.prepare() - } -} - -impl PreparedRoundUpdateTransactionV1 { - pub fn get_executable(&self) -> Executable<'_> { - Executable::new( - &self.encoded_instructions, - &self.references, - &self.blobs, - ExecutionContext { - intent_hash: TransactionIntentHash::NotToCheck { - intent_hash: self.summary.hash, - }, - epoch_range: None, - payload_size: 0, - num_of_signature_validations: 0, - auth_zone_params: AuthZoneParams { - initial_proofs: btreeset!(system_execution(SystemExecution::Validator)), - virtual_resources: BTreeSet::new(), - }, - costing_parameters: TransactionCostingParameters { - tip_percentage: 0, - free_credit_in_xrd: Decimal::ZERO, - abort_when_loan_repaid: false, - }, - pre_allocated_addresses: vec![], - }, - true, - ) - } -} +use super::*; +use crate::internal_prelude::*; -define_wrapped_hash!(RoundUpdateTransactionHash); - -impl HasRoundUpdateTransactionHash for PreparedRoundUpdateTransactionV1 { - fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash { - RoundUpdateTransactionHash::from_hash(self.summary.hash) - } -} - -pub trait HasRoundUpdateTransactionHash { - fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash; -} - -#[derive(Debug, Clone, PartialEq, Eq, Sbor)] -pub struct PayloadIdentifiers { - pub ledger_transaction_hash: LedgerTransactionHash, - pub typed: TypedTransactionIdentifiers, -} - -#[derive(Debug, Clone, PartialEq, Eq, Sbor)] -pub enum TypedTransactionIdentifiers { - Genesis { - system_transaction_hash: SystemTransactionHash, - }, - User { - intent_hash: IntentHash, - signed_intent_hash: SignedIntentHash, - notarized_transaction_hash: NotarizedTransactionHash, - }, - RoundUpdateV1 { - round_update_hash: RoundUpdateTransactionHash, - }, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct UserTransactionIdentifiers<'a> { - pub intent_hash: &'a IntentHash, - pub signed_intent_hash: &'a SignedIntentHash, - pub notarized_transaction_hash: &'a NotarizedTransactionHash, -} - -impl TypedTransactionIdentifiers { - pub fn user(&self) -> Option { - match self { - TypedTransactionIdentifiers::User { - intent_hash, - signed_intent_hash, - notarized_transaction_hash, - } => Some(UserTransactionIdentifiers { - intent_hash, - signed_intent_hash, - notarized_transaction_hash, - }), - _ => None, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, ManifestCategorize, ManifestEncode, ManifestDecode)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub enum LedgerTransaction { #[sbor(discriminator(GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR))] Genesis(Box), @@ -222,53 +9,23 @@ pub enum LedgerTransaction { UserV1(Box), #[sbor(discriminator(ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] RoundUpdateV1(Box), + #[sbor(discriminator(FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] + FlashV1(Box), } const GENESIS_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 0; const USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 1; const ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 2; +const FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR: u8 = 3; define_raw_transaction_payload!(RawLedgerTransaction); -impl LedgerTransaction { - pub fn to_raw(&self) -> Result { - Ok(self.to_payload_bytes()?.into()) - } - - pub fn to_payload_bytes(&self) -> Result, EncodeError> { - manifest_encode(&SborFixedEnumVariant::< - { TransactionDiscriminator::V1Ledger as u8 }, - (&LedgerTransaction,), - >::new((self,))) - } - - pub fn from_raw(raw: &RawLedgerTransaction) -> Result { - Self::from_payload_bytes(&raw.0) - } - - pub fn from_raw_user(raw: &RawNotarizedTransaction) -> Result { - Ok(LedgerTransaction::UserV1(Box::new( - NotarizedTransactionV1::from_raw(raw)?, - ))) - } - - pub fn from_payload_bytes(payload_bytes: &[u8]) -> Result { - Ok(manifest_decode::< - SborFixedEnumVariant< - { TransactionDiscriminator::V1Ledger as u8 }, - (LedgerTransaction,), - >, - >(payload_bytes)? - .into_fields() - .0) - } - - pub fn prepare(&self) -> Result { - PreparedLedgerTransaction::prepare_from_payload(&self.to_payload_bytes()?) - } +impl TransactionPayload for LedgerTransaction { + type Prepared = PreparedLedgerTransaction; + type Raw = RawLedgerTransaction; } -#[derive(Debug, Clone, PartialEq, Eq, ManifestCategorize, ManifestEncode, ManifestDecode)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub enum GenesisTransaction { #[sbor(discriminator(GENESIS_TRANSACTION_FLASH_DISCRIMINATOR))] Flash, @@ -318,6 +75,11 @@ impl PreparedLedgerTransaction { round_update_hash: t.round_update_transaction_hash(), } } + PreparedLedgerTransactionInner::FlashV1(t) => { + TypedTransactionIdentifiers::FlashV1 { + flash_transaction_hash: t.flash_transaction_hash(), + } + } }, } } @@ -337,6 +99,8 @@ pub enum PreparedLedgerTransactionInner { UserV1(Box), #[sbor(discriminator(ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] RoundUpdateV1(Box), + #[sbor(discriminator(FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] + FlashV1(Box), } impl PreparedLedgerTransactionInner { @@ -351,6 +115,7 @@ impl HasSummary for PreparedLedgerTransactionInner { Self::Genesis(t) => t.get_summary(), Self::UserV1(t) => t.get_summary(), Self::RoundUpdateV1(t) => t.get_summary(), + Self::FlashV1(t) => t.get_summary(), } } } @@ -393,6 +158,11 @@ impl TransactionFullChildPreparable for PreparedLedgerTransactionInner { PreparedRoundUpdateTransactionV1::prepare_as_full_body_child(decoder)?; PreparedLedgerTransactionInner::RoundUpdateV1(Box::new(prepared)) } + FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR => { + check_length(length, 1)?; + let prepared = PreparedFlashTransactionV1::prepare_as_full_body_child(decoder)?; + PreparedLedgerTransactionInner::FlashV1(Box::new(prepared)) + } _ => return Err(unknown_discriminator(discriminator)), }; decoder.track_stack_depth_decrease()?; @@ -473,6 +243,8 @@ pub enum ValidatedLedgerTransactionInner { UserV1(Box), #[sbor(discriminator(ROUND_UPDATE_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] RoundUpdateV1(Box), + #[sbor(discriminator(FLASH_V1_LEDGER_TRANSACTION_DISCRIMINATOR))] + FlashV1(Box), } impl ValidatedLedgerTransaction { @@ -481,19 +253,11 @@ impl ValidatedLedgerTransaction { ValidatedLedgerTransactionInner::Genesis(_) => None, ValidatedLedgerTransactionInner::UserV1(t) => Some(t.intent_hash()), ValidatedLedgerTransactionInner::RoundUpdateV1(_) => None, + ValidatedLedgerTransactionInner::FlashV1(_) => None, } } - pub fn as_genesis_flash(&self) -> Option<&Summary> { - match &self.inner { - ValidatedLedgerTransactionInner::Genesis(genesis) => match genesis.as_ref() { - PreparedGenesisTransaction::Flash(summary) => Some(summary), - PreparedGenesisTransaction::Transaction(_) => None, - }, - _ => None, - } - } - + /// Note - panics if it's a genesis flash pub fn get_executable(&self) -> Executable<'_> { match &self.inner { ValidatedLedgerTransactionInner::Genesis(genesis) => match genesis.as_ref() { @@ -506,6 +270,9 @@ impl ValidatedLedgerTransaction { }, ValidatedLedgerTransactionInner::UserV1(t) => t.get_executable(), ValidatedLedgerTransactionInner::RoundUpdateV1(t) => t.get_executable(), + ValidatedLedgerTransactionInner::FlashV1(_) => { + panic!("Should not call get_executable on a flash transaction") + } } } @@ -528,11 +295,64 @@ impl ValidatedLedgerTransaction { round_update_hash: t.round_update_transaction_hash(), } } + ValidatedLedgerTransactionInner::FlashV1(t) => { + TypedTransactionIdentifiers::FlashV1 { + flash_transaction_hash: t.flash_transaction_hash(), + } + } }, } } } +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub struct PayloadIdentifiers { + pub ledger_transaction_hash: LedgerTransactionHash, + pub typed: TypedTransactionIdentifiers, +} + +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub enum TypedTransactionIdentifiers { + Genesis { + system_transaction_hash: SystemTransactionHash, + }, + User { + intent_hash: IntentHash, + signed_intent_hash: SignedIntentHash, + notarized_transaction_hash: NotarizedTransactionHash, + }, + RoundUpdateV1 { + round_update_hash: RoundUpdateTransactionHash, + }, + FlashV1 { + flash_transaction_hash: FlashTransactionHash, + }, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UserTransactionIdentifiers<'a> { + pub intent_hash: &'a IntentHash, + pub signed_intent_hash: &'a SignedIntentHash, + pub notarized_transaction_hash: &'a NotarizedTransactionHash, +} + +impl TypedTransactionIdentifiers { + pub fn user(&self) -> Option { + match self { + TypedTransactionIdentifiers::User { + intent_hash, + signed_intent_hash, + notarized_transaction_hash, + } => Some(UserTransactionIdentifiers { + intent_hash, + signed_intent_hash, + notarized_transaction_hash, + }), + _ => None, + } + } +} + impl HasLedgerTransactionHash for ValidatedLedgerTransaction { fn ledger_transaction_hash(&self) -> LedgerTransactionHash { LedgerTransactionHash::from_hash(self.summary.hash) @@ -583,3 +403,61 @@ impl HasLedgerTransactionHash for PreparedLedgerTransaction { LedgerTransactionHash::from_hash(self.summary.hash) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn v1_ledger_transaction_structure() { + let sig_1_private_key = Secp256k1PrivateKey::from_u64(1).unwrap(); + let sig_2_private_key = Ed25519PrivateKey::from_u64(2).unwrap(); + let notary_private_key = Ed25519PrivateKey::from_u64(3).unwrap(); + + let notarized = TransactionBuilder::new() + .header(TransactionHeaderV1 { + network_id: 21, + start_epoch_inclusive: Epoch::of(0), + end_epoch_exclusive: Epoch::of(100), + nonce: 0, + notary_public_key: notary_private_key.public_key().into(), + notary_is_signatory: true, + tip_percentage: 0, + }) + .manifest(ManifestBuilder::new().drop_all_proofs().build()) + .sign(&sig_1_private_key) + .sign(&sig_2_private_key) + .notarize(¬ary_private_key) + .build(); + + let prepared_notarized = notarized.prepare().expect("Notarized can be prepared"); + + let ledger = LedgerTransaction::UserV1(Box::new(notarized)); + let ledger_transaction_bytes = ledger.to_payload_bytes().expect("Can be encoded"); + LedgerTransaction::from_payload_bytes(&ledger_transaction_bytes).expect("Can be decoded"); + let prepared_ledger_transaction = + PreparedLedgerTransaction::prepare_from_payload(&ledger_transaction_bytes) + .expect("Can be prepared"); + + let expected_intent_hash = LedgerTransactionHash::from_hash(hash( + [ + [ + TRANSACTION_HASHABLE_PAYLOAD_PREFIX, + TransactionDiscriminator::V1Ledger as u8, + USER_V1_LEDGER_TRANSACTION_DISCRIMINATOR, + ] + .as_slice(), + prepared_notarized.notarized_transaction_hash().0.as_slice(), + ] + .concat(), + )); + assert_eq!( + prepared_ledger_transaction.ledger_transaction_hash(), + expected_intent_hash + ); + assert_eq!( + LedgerTransactionHash::for_user_v1(&prepared_notarized.notarized_transaction_hash()), + expected_intent_hash + ); + } +} diff --git a/radix-transactions/src/model/mod.rs b/radix-transactions/src/model/mod.rs index afb63071786..f6f1a0abd79 100644 --- a/radix-transactions/src/model/mod.rs +++ b/radix-transactions/src/model/mod.rs @@ -1,6 +1,7 @@ mod concepts; mod executable; mod hash; +mod ledger_transaction; mod preparation; mod v1; mod versioned; @@ -8,6 +9,7 @@ mod versioned; pub use concepts::*; pub use executable::*; pub use hash::*; +pub use ledger_transaction::*; pub use preparation::*; pub use v1::*; pub use versioned::*; diff --git a/radix-transactions/src/model/preparation/traits.rs b/radix-transactions/src/model/preparation/traits.rs index ec06df1ac14..f04c8636f6a 100644 --- a/radix-transactions/src/model/preparation/traits.rs +++ b/radix-transactions/src/model/preparation/traits.rs @@ -6,7 +6,6 @@ pub trait TransactionPayload: ManifestEncode + ManifestDecode + ManifestCategorize - + ManifestSborTuple + ManifestSborEnumVariantFor where Self::OwnedVariant: ManifestDecode, @@ -15,6 +14,10 @@ where type Prepared: TransactionPayloadPreparable; type Raw: RawTransactionPayload; + fn discriminator() -> u8 { + Self::DISCRIMINATOR + } + fn to_raw(&self) -> Result { Ok(self.to_payload_bytes()?.into()) } @@ -31,6 +34,10 @@ where Ok(Self::from_decoded_variant(manifest_decode(payload_bytes)?)) } + fn from_payload_variant(payload_variant: Self::OwnedVariant) -> Self { + Self::from_decoded_variant(payload_variant) + } + fn prepare(&self) -> Result { Ok(Self::Prepared::prepare_from_payload( &self.to_payload_bytes()?, diff --git a/radix-transactions/src/model/v1/blobs.rs b/radix-transactions/src/model/v1/blobs.rs index e011f1b9120..ab7d4c493ec 100644 --- a/radix-transactions/src/model/v1/blobs.rs +++ b/radix-transactions/src/model/v1/blobs.rs @@ -3,11 +3,11 @@ use radix_common::constants::MAX_NUMBER_OF_BLOBS; use super::*; use crate::internal_prelude::*; -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct BlobV1(pub Vec); -#[derive(Default, Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Default, Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct BlobsV1 { pub blobs: Vec, diff --git a/radix-transactions/src/model/v1/dynamic_addresses.rs b/radix-transactions/src/model/v1/dynamic_addresses.rs new file mode 100644 index 00000000000..d201d1fe64a --- /dev/null +++ b/radix-transactions/src/model/v1/dynamic_addresses.rs @@ -0,0 +1,544 @@ +use crate::internal_prelude::*; +use radix_common::scrypto_describe_for_manifest_type; +use sbor::{Decoder, Encoder}; + +/* +================================================================================= +NOTE: For now, we only support "dynamic" addresses for CALL instructions. +================================================================================= +This is to reduce the scope of change and make manifest easier to reason about. + +In theory, we can apply it to all types of global addresses (`GlobalAddress`, +`PackageAddress`, `ResourceAddress` and `ComponentAddress`). + +Then, we can do more advanced stuff in manifest, such as +``` +ALLOCATE_GLOBAL_ADDRESS + Address("{resource_package}") + "FungibleResourceManager" + AddressReservation("address_reservation") + NamedAddress("new_resource") +; +CALL_FUNCTION + Address("{resource_package}") + "FungibleResourceManager" + "create_with_initial_supply_and_address" + Decimal("10") + AddressReservation("address_reservation") +; +TAKE_FROM_WORKTOP + NamedAddress("new_resource") + Decimal("5.0") + Bucket("bucket1") +; +TAKE_FROM_WORKTOP + NamedAddress("new_resource") + Decimal("5.0") + Bucket("bucket2") +; +``` +*/ + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DynamicGlobalAddress { + Static(GlobalAddress), + Named(u32), +} + +scrypto_describe_for_manifest_type!( + DynamicGlobalAddress, + GLOBAL_ADDRESS_TYPE, + global_address_type_data, +); + +impl Categorize for DynamicGlobalAddress { + #[inline] + fn value_kind() -> ValueKind { + ValueKind::Custom(ManifestCustomValueKind::Address) + } +} + +impl> Encode + for DynamicGlobalAddress +{ + #[inline] + fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_value_kind(Self::value_kind()) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + Self::Static(address) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; + encoder.write_slice(address.as_node_id().as_bytes())?; + } + Self::Named(address_id) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; + encoder.write_slice(&address_id.to_le_bytes())?; + } + } + Ok(()) + } +} + +impl> Decode + for DynamicGlobalAddress +{ + fn decode_body_with_value_kind( + decoder: &mut D, + value_kind: ValueKind, + ) -> Result { + decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; + match decoder.read_discriminator()? { + MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { + let slice = decoder.read_slice(NodeId::LENGTH)?; + Ok(Self::Static( + GlobalAddress::try_from(slice).map_err(|_| DecodeError::InvalidCustomValue)?, + )) + } + MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { + let slice = decoder.read_slice(4)?; + let id = u32::from_le_bytes(slice.try_into().unwrap()); + Ok(Self::Named(id)) + } + _ => Err(DecodeError::InvalidCustomValue), + } + } +} + +impl DynamicGlobalAddress { + /// This is to support either `Address("static_address")` or `NamedAddress("abc")` in manifest instruction, + /// instead of `Enum<0u8>(Address("static_address"))`. + pub fn to_instruction_argument(&self) -> ManifestValue { + match self { + Self::Static(address) => ManifestValue::Custom { + value: ManifestCustomValue::Address(ManifestAddress::Static( + address.into_node_id(), + )), + }, + Self::Named(id) => ManifestValue::Custom { + value: ManifestCustomValue::Address(ManifestAddress::Named(*id)), + }, + } + } + + pub fn is_static_global_package(&self) -> bool { + match self { + Self::Static(address) => address.as_node_id().is_global_package(), + Self::Named(_) => false, + } + } + + pub fn is_static_global_fungible_resource_manager(&self) -> bool { + match self { + Self::Static(address) => address.as_node_id().is_global_fungible_resource_manager(), + Self::Named(_) => false, + } + } + pub fn is_static_global_non_fungible_resource_manager(&self) -> bool { + match self { + Self::Static(address) => address + .as_node_id() + .is_global_non_fungible_resource_manager(), + Self::Named(_) => false, + } + } +} + +impl From for DynamicGlobalAddress { + fn from(value: GlobalAddress) -> Self { + Self::Static(value) + } +} + +impl From for DynamicGlobalAddress { + fn from(value: PackageAddress) -> Self { + Self::Static(value.into()) + } +} + +impl From for DynamicGlobalAddress { + fn from(value: DynamicPackageAddress) -> Self { + match value { + DynamicPackageAddress::Static(value) => Self::Static(value.into()), + DynamicPackageAddress::Named(value) => Self::Named(value), + } + } +} + +impl From for DynamicGlobalAddress { + fn from(value: ResourceAddress) -> Self { + Self::Static(value.into()) + } +} + +impl From for DynamicGlobalAddress { + fn from(value: DynamicResourceAddress) -> Self { + match value { + DynamicResourceAddress::Static(value) => Self::Static(value.into()), + DynamicResourceAddress::Named(value) => Self::Named(value), + } + } +} + +impl From for DynamicGlobalAddress { + fn from(value: ComponentAddress) -> Self { + Self::Static(value.into()) + } +} + +impl From for DynamicGlobalAddress { + fn from(value: DynamicComponentAddress) -> Self { + match value { + DynamicComponentAddress::Static(value) => Self::Static(value.into()), + DynamicComponentAddress::Named(value) => Self::Named(value), + } + } +} + +impl From for DynamicGlobalAddress { + fn from(value: u32) -> Self { + Self::Named(value) + } +} + +impl TryFrom for DynamicGlobalAddress { + type Error = ParseGlobalAddressError; + + fn try_from(value: ManifestAddress) -> Result { + Ok(match value { + ManifestAddress::Static(value) => Self::Static(value.try_into()?), + ManifestAddress::Named(value) => Self::Named(value), + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DynamicPackageAddress { + Static(PackageAddress), + Named(u32), +} + +scrypto_describe_for_manifest_type!( + DynamicPackageAddress, + PACKAGE_ADDRESS_TYPE, + package_address_type_data, +); + +impl Categorize for DynamicPackageAddress { + #[inline] + fn value_kind() -> ValueKind { + ValueKind::Custom(ManifestCustomValueKind::Address) + } +} + +impl> Encode + for DynamicPackageAddress +{ + #[inline] + fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_value_kind(Self::value_kind()) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + Self::Static(address) => { + encoder.write_discriminator(0)?; + encoder.write_slice(address.as_node_id().as_bytes())?; + } + Self::Named(address_id) => { + encoder.write_discriminator(1)?; + encoder.write_slice(&address_id.to_le_bytes())?; + } + } + Ok(()) + } +} + +impl> Decode + for DynamicPackageAddress +{ + fn decode_body_with_value_kind( + decoder: &mut D, + value_kind: ValueKind, + ) -> Result { + decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; + match decoder.read_discriminator()? { + MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { + let slice = decoder.read_slice(NodeId::LENGTH)?; + Ok(Self::Static( + PackageAddress::try_from(slice).map_err(|_| DecodeError::InvalidCustomValue)?, + )) + } + MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { + let slice = decoder.read_slice(4)?; + let id = u32::from_le_bytes(slice.try_into().unwrap()); + Ok(Self::Named(id)) + } + _ => Err(DecodeError::InvalidCustomValue), + } + } +} + +impl DynamicPackageAddress { + /// This is to support either `Address("static_address")` or `NamedAddress("abc")` in manifest instruction, + /// instead of `Enum<0u8>(Address("static_address"))`. + pub fn to_instruction_argument(&self) -> ManifestValue { + match self { + Self::Static(address) => ManifestValue::Custom { + value: ManifestCustomValue::Address(ManifestAddress::Static( + address.into_node_id(), + )), + }, + Self::Named(id) => ManifestValue::Custom { + value: ManifestCustomValue::Address(ManifestAddress::Named(*id)), + }, + } + } + + pub fn is_static_global_package_of(&self, package_address: &PackageAddress) -> bool { + match self { + Self::Static(address) => address.as_node_id().eq(package_address.as_node_id()), + Self::Named(_) => false, + } + } +} + +impl From for DynamicPackageAddress { + fn from(value: PackageAddress) -> Self { + Self::Static(value.into()) + } +} + +impl From for DynamicPackageAddress { + fn from(value: u32) -> Self { + Self::Named(value) + } +} + +impl TryFrom for DynamicPackageAddress { + type Error = ParsePackageAddressError; + + fn try_from(value: GlobalAddress) -> Result { + Ok(Self::Static(PackageAddress::try_from( + value.into_node_id(), + )?)) + } +} + +impl TryFrom for DynamicPackageAddress { + type Error = ParsePackageAddressError; + + fn try_from(value: ManifestAddress) -> Result { + Ok(match value { + ManifestAddress::Static(value) => Self::Static(value.try_into()?), + ManifestAddress::Named(value) => Self::Named(value), + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DynamicComponentAddress { + Static(ComponentAddress), + Named(u32), +} + +scrypto_describe_for_manifest_type!( + DynamicComponentAddress, + COMPONENT_ADDRESS_TYPE, + component_address_type_data, +); + +impl Categorize for DynamicComponentAddress { + #[inline] + fn value_kind() -> ValueKind { + ValueKind::Custom(ManifestCustomValueKind::Address) + } +} + +impl> Encode + for DynamicComponentAddress +{ + #[inline] + fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_value_kind(Self::value_kind()) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + Self::Static(address) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; + encoder.write_slice(address.as_node_id().as_bytes())?; + } + Self::Named(address_id) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; + encoder.write_slice(&address_id.to_le_bytes())?; + } + } + Ok(()) + } +} + +impl> Decode + for DynamicComponentAddress +{ + fn decode_body_with_value_kind( + decoder: &mut D, + value_kind: ValueKind, + ) -> Result { + decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; + match decoder.read_discriminator()? { + MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { + let slice = decoder.read_slice(NodeId::LENGTH)?; + Ok(Self::Static( + ComponentAddress::try_from(slice) + .map_err(|_| DecodeError::InvalidCustomValue)?, + )) + } + MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { + let slice = decoder.read_slice(4)?; + let id = u32::from_le_bytes(slice.try_into().unwrap()); + Ok(Self::Named(id)) + } + _ => Err(DecodeError::InvalidCustomValue), + } + } +} + +impl From for DynamicComponentAddress { + fn from(value: ComponentAddress) -> Self { + Self::Static(value) + } +} + +impl From for DynamicComponentAddress { + fn from(value: u32) -> Self { + Self::Named(value) + } +} + +impl TryFrom for DynamicComponentAddress { + type Error = ParseComponentAddressError; + + fn try_from(value: GlobalAddress) -> Result { + Ok(Self::Static(ComponentAddress::try_from( + value.into_node_id(), + )?)) + } +} + +impl TryFrom for DynamicComponentAddress { + type Error = ParseComponentAddressError; + + fn try_from(value: ManifestAddress) -> Result { + Ok(match value { + ManifestAddress::Static(value) => Self::Static(value.try_into()?), + ManifestAddress::Named(value) => Self::Named(value), + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DynamicResourceAddress { + Static(ResourceAddress), + Named(u32), +} + +scrypto_describe_for_manifest_type!( + DynamicResourceAddress, + RESOURCE_ADDRESS_TYPE, + resource_address_type_data, +); + +impl Categorize for DynamicResourceAddress { + #[inline] + fn value_kind() -> ValueKind { + ValueKind::Custom(ManifestCustomValueKind::Address) + } +} + +impl> Encode + for DynamicResourceAddress +{ + #[inline] + fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { + encoder.write_value_kind(Self::value_kind()) + } + + #[inline] + fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { + match self { + Self::Static(address) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; + encoder.write_slice(address.as_node_id().as_bytes())?; + } + Self::Named(address_id) => { + encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; + encoder.write_slice(&address_id.to_le_bytes())?; + } + } + Ok(()) + } +} + +impl> Decode + for DynamicResourceAddress +{ + fn decode_body_with_value_kind( + decoder: &mut D, + value_kind: ValueKind, + ) -> Result { + decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; + match decoder.read_discriminator()? { + MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { + let slice = decoder.read_slice(NodeId::LENGTH)?; + Ok(Self::Static( + ResourceAddress::try_from(slice) + .map_err(|_| DecodeError::InvalidCustomValue)?, + )) + } + MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { + let slice = decoder.read_slice(4)?; + let id = u32::from_le_bytes(slice.try_into().unwrap()); + Ok(Self::Named(id)) + } + _ => Err(DecodeError::InvalidCustomValue), + } + } +} + +impl From for DynamicResourceAddress { + fn from(value: ResourceAddress) -> Self { + Self::Static(value) + } +} + +impl From for DynamicResourceAddress { + fn from(value: u32) -> Self { + Self::Named(value) + } +} + +impl TryFrom for DynamicResourceAddress { + type Error = ParseResourceAddressError; + + fn try_from(value: GlobalAddress) -> Result { + Ok(Self::Static(ResourceAddress::try_from( + value.into_node_id(), + )?)) + } +} + +impl TryFrom for DynamicResourceAddress { + type Error = ParseResourceAddressError; + + fn try_from(value: ManifestAddress) -> Result { + Ok(match value { + ManifestAddress::Static(value) => Self::Static(value.try_into()?), + ManifestAddress::Named(value) => Self::Named(value), + }) + } +} diff --git a/radix-transactions/src/model/v1/flash_transaction.rs b/radix-transactions/src/model/v1/flash_transaction.rs new file mode 100644 index 00000000000..ab0bb0f507e --- /dev/null +++ b/radix-transactions/src/model/v1/flash_transaction.rs @@ -0,0 +1,65 @@ +use super::*; +use crate::internal_prelude::*; + +#[derive(Debug, Clone, PartialEq, Eq, Sbor)] +pub struct FlashTransactionV1 { + pub name: String, + pub state_updates: StateUpdates, +} + +pub struct PreparedFlashTransactionV1 { + pub name: String, + pub state_updates: StateUpdates, + pub summary: Summary, +} + +impl TransactionPayload for FlashTransactionV1 { + type Prepared = PreparedFlashTransactionV1; + type Raw = RawFlashTransactionV1; +} + +define_raw_transaction_payload!(RawFlashTransactionV1); + +impl HasSummary for PreparedFlashTransactionV1 { + fn get_summary(&self) -> &Summary { + &self.summary + } +} + +impl HasFlashTransactionHash for PreparedFlashTransactionV1 { + fn flash_transaction_hash(&self) -> FlashTransactionHash { + FlashTransactionHash(self.summary.hash) + } +} + +impl TransactionFullChildPreparable for PreparedFlashTransactionV1 { + fn prepare_as_full_body_child(decoder: &mut TransactionDecoder) -> Result { + let ((name, state_updates), summary) = + ConcatenatedDigest::prepare_from_transaction_child_struct::<( + SummarizedRawFullBody, + SummarizedRawFullBody, + )>(decoder, TransactionDiscriminator::V1Flash)?; + Ok(Self { + name: name.inner, + state_updates: state_updates.inner, + summary, + }) + } +} + +impl TransactionPayloadPreparable for PreparedFlashTransactionV1 { + type Raw = RawFlashTransactionV1; + + fn prepare_for_payload(decoder: &mut TransactionDecoder) -> Result { + let ((name, state_updates), summary) = + ConcatenatedDigest::prepare_from_transaction_payload_enum::<( + SummarizedRawFullBody, + SummarizedRawFullBody, + )>(decoder, TransactionDiscriminator::V1Flash)?; + Ok(Self { + name: name.inner, + state_updates: state_updates.inner, + summary, + }) + } +} diff --git a/radix-transactions/src/model/v1/header.rs b/radix-transactions/src/model/v1/header.rs index 42aaa0efe67..7f188924780 100644 --- a/radix-transactions/src/model/v1/header.rs +++ b/radix-transactions/src/model/v1/header.rs @@ -1,9 +1,10 @@ +use crate::internal_prelude::*; use radix_common::types::Epoch; use radix_common::{crypto::PublicKey, ManifestSbor}; use crate::model::SummarizedRawFullBody; -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub struct TransactionHeaderV1 { pub network_id: u8, pub start_epoch_inclusive: Epoch, diff --git a/radix-transactions/src/model/v1/instruction.rs b/radix-transactions/src/model/v1/instruction.rs index 9c1a4b564e9..491404f2d14 100644 --- a/radix-transactions/src/model/v1/instruction.rs +++ b/radix-transactions/src/model/v1/instruction.rs @@ -1,528 +1,11 @@ +use super::*; use crate::internal_prelude::*; use radix_common::data::manifest::{model::*, ManifestValue}; use radix_common::data::scrypto::model::*; use radix_common::math::Decimal; use radix_engine_interface::types::*; -use sbor::{Decoder, Encoder}; - -/* -================================================================================= -NOTE: For now, we only support "dynamic" addresses for CALL instructions. -================================================================================= -This is to reduce the scope of change and make manifest easier to reason about. - -In theory, we can apply it to all types of global addresses (`GlobalAddress`, -`PackageAddress`, `ResourceAddress` and `ComponentAddress`). - -Then, we can do more advanced stuff in manifest, such as -``` -ALLOCATE_GLOBAL_ADDRESS - Address("{resource_package}") - "FungibleResourceManager" - AddressReservation("address_reservation") - NamedAddress("new_resource") -; -CALL_FUNCTION - Address("{resource_package}") - "FungibleResourceManager" - "create_with_initial_supply_and_address" - Decimal("10") - AddressReservation("address_reservation") -; -TAKE_FROM_WORKTOP - NamedAddress("new_resource") - Decimal("5.0") - Bucket("bucket1") -; -TAKE_FROM_WORKTOP - NamedAddress("new_resource") - Decimal("5.0") - Bucket("bucket2") -; -``` -*/ - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DynamicGlobalAddress { - Static(GlobalAddress), - Named(u32), -} - -impl Categorize for DynamicGlobalAddress { - #[inline] - fn value_kind() -> ValueKind { - ValueKind::Custom(ManifestCustomValueKind::Address) - } -} - -impl> Encode - for DynamicGlobalAddress -{ - #[inline] - fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_value_kind(Self::value_kind()) - } - - #[inline] - fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - match self { - Self::Static(address) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; - encoder.write_slice(address.as_node_id().as_bytes())?; - } - Self::Named(address_id) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; - encoder.write_slice(&address_id.to_le_bytes())?; - } - } - Ok(()) - } -} - -impl> Decode - for DynamicGlobalAddress -{ - fn decode_body_with_value_kind( - decoder: &mut D, - value_kind: ValueKind, - ) -> Result { - decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; - match decoder.read_discriminator()? { - MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { - let slice = decoder.read_slice(NodeId::LENGTH)?; - Ok(Self::Static( - GlobalAddress::try_from(slice).map_err(|_| DecodeError::InvalidCustomValue)?, - )) - } - MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { - let slice = decoder.read_slice(4)?; - let id = u32::from_le_bytes(slice.try_into().unwrap()); - Ok(Self::Named(id)) - } - _ => Err(DecodeError::InvalidCustomValue), - } - } -} - -impl DynamicGlobalAddress { - /// This is to support either `Address("static_address")` or `NamedAddress("abc")` in manifest instruction, - /// instead of `Enum<0u8>(Address("static_address"))`. - pub fn to_instruction_argument(&self) -> ManifestValue { - match self { - Self::Static(address) => ManifestValue::Custom { - value: ManifestCustomValue::Address(ManifestAddress::Static( - address.into_node_id(), - )), - }, - Self::Named(id) => ManifestValue::Custom { - value: ManifestCustomValue::Address(ManifestAddress::Named(*id)), - }, - } - } - - pub fn is_static_global_package(&self) -> bool { - match self { - Self::Static(address) => address.as_node_id().is_global_package(), - Self::Named(_) => false, - } - } - - pub fn is_static_global_fungible_resource_manager(&self) -> bool { - match self { - Self::Static(address) => address.as_node_id().is_global_fungible_resource_manager(), - Self::Named(_) => false, - } - } - pub fn is_static_global_non_fungible_resource_manager(&self) -> bool { - match self { - Self::Static(address) => address - .as_node_id() - .is_global_non_fungible_resource_manager(), - Self::Named(_) => false, - } - } -} - -impl From for DynamicGlobalAddress { - fn from(value: GlobalAddress) -> Self { - Self::Static(value) - } -} - -impl From for DynamicGlobalAddress { - fn from(value: PackageAddress) -> Self { - Self::Static(value.into()) - } -} - -impl From for DynamicGlobalAddress { - fn from(value: DynamicPackageAddress) -> Self { - match value { - DynamicPackageAddress::Static(value) => Self::Static(value.into()), - DynamicPackageAddress::Named(value) => Self::Named(value), - } - } -} - -impl From for DynamicGlobalAddress { - fn from(value: ResourceAddress) -> Self { - Self::Static(value.into()) - } -} - -impl From for DynamicGlobalAddress { - fn from(value: DynamicResourceAddress) -> Self { - match value { - DynamicResourceAddress::Static(value) => Self::Static(value.into()), - DynamicResourceAddress::Named(value) => Self::Named(value), - } - } -} - -impl From for DynamicGlobalAddress { - fn from(value: ComponentAddress) -> Self { - Self::Static(value.into()) - } -} - -impl From for DynamicGlobalAddress { - fn from(value: DynamicComponentAddress) -> Self { - match value { - DynamicComponentAddress::Static(value) => Self::Static(value.into()), - DynamicComponentAddress::Named(value) => Self::Named(value), - } - } -} - -impl From for DynamicGlobalAddress { - fn from(value: u32) -> Self { - Self::Named(value) - } -} - -impl TryFrom for DynamicGlobalAddress { - type Error = ParseGlobalAddressError; - - fn try_from(value: ManifestAddress) -> Result { - Ok(match value { - ManifestAddress::Static(value) => Self::Static(value.try_into()?), - ManifestAddress::Named(value) => Self::Named(value), - }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DynamicPackageAddress { - Static(PackageAddress), - Named(u32), -} - -impl Categorize for DynamicPackageAddress { - #[inline] - fn value_kind() -> ValueKind { - ValueKind::Custom(ManifestCustomValueKind::Address) - } -} - -impl> Encode - for DynamicPackageAddress -{ - #[inline] - fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_value_kind(Self::value_kind()) - } - - #[inline] - fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - match self { - Self::Static(address) => { - encoder.write_discriminator(0)?; - encoder.write_slice(address.as_node_id().as_bytes())?; - } - Self::Named(address_id) => { - encoder.write_discriminator(1)?; - encoder.write_slice(&address_id.to_le_bytes())?; - } - } - Ok(()) - } -} - -impl> Decode - for DynamicPackageAddress -{ - fn decode_body_with_value_kind( - decoder: &mut D, - value_kind: ValueKind, - ) -> Result { - decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; - match decoder.read_discriminator()? { - MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { - let slice = decoder.read_slice(NodeId::LENGTH)?; - Ok(Self::Static( - PackageAddress::try_from(slice).map_err(|_| DecodeError::InvalidCustomValue)?, - )) - } - MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { - let slice = decoder.read_slice(4)?; - let id = u32::from_le_bytes(slice.try_into().unwrap()); - Ok(Self::Named(id)) - } - _ => Err(DecodeError::InvalidCustomValue), - } - } -} - -impl DynamicPackageAddress { - /// This is to support either `Address("static_address")` or `NamedAddress("abc")` in manifest instruction, - /// instead of `Enum<0u8>(Address("static_address"))`. - pub fn to_instruction_argument(&self) -> ManifestValue { - match self { - Self::Static(address) => ManifestValue::Custom { - value: ManifestCustomValue::Address(ManifestAddress::Static( - address.into_node_id(), - )), - }, - Self::Named(id) => ManifestValue::Custom { - value: ManifestCustomValue::Address(ManifestAddress::Named(*id)), - }, - } - } - - pub fn is_static_global_package_of(&self, package_address: &PackageAddress) -> bool { - match self { - Self::Static(address) => address.as_node_id().eq(package_address.as_node_id()), - Self::Named(_) => false, - } - } -} - -impl From for DynamicPackageAddress { - fn from(value: PackageAddress) -> Self { - Self::Static(value.into()) - } -} - -impl From for DynamicPackageAddress { - fn from(value: u32) -> Self { - Self::Named(value) - } -} - -impl TryFrom for DynamicPackageAddress { - type Error = ParsePackageAddressError; - - fn try_from(value: GlobalAddress) -> Result { - Ok(Self::Static(PackageAddress::try_from( - value.into_node_id(), - )?)) - } -} - -impl TryFrom for DynamicPackageAddress { - type Error = ParsePackageAddressError; - - fn try_from(value: ManifestAddress) -> Result { - Ok(match value { - ManifestAddress::Static(value) => Self::Static(value.try_into()?), - ManifestAddress::Named(value) => Self::Named(value), - }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DynamicComponentAddress { - Static(ComponentAddress), - Named(u32), -} - -impl Categorize for DynamicComponentAddress { - #[inline] - fn value_kind() -> ValueKind { - ValueKind::Custom(ManifestCustomValueKind::Address) - } -} - -impl> Encode - for DynamicComponentAddress -{ - #[inline] - fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_value_kind(Self::value_kind()) - } - - #[inline] - fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - match self { - Self::Static(address) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; - encoder.write_slice(address.as_node_id().as_bytes())?; - } - Self::Named(address_id) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; - encoder.write_slice(&address_id.to_le_bytes())?; - } - } - Ok(()) - } -} - -impl> Decode - for DynamicComponentAddress -{ - fn decode_body_with_value_kind( - decoder: &mut D, - value_kind: ValueKind, - ) -> Result { - decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; - match decoder.read_discriminator()? { - MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { - let slice = decoder.read_slice(NodeId::LENGTH)?; - Ok(Self::Static( - ComponentAddress::try_from(slice) - .map_err(|_| DecodeError::InvalidCustomValue)?, - )) - } - MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { - let slice = decoder.read_slice(4)?; - let id = u32::from_le_bytes(slice.try_into().unwrap()); - Ok(Self::Named(id)) - } - _ => Err(DecodeError::InvalidCustomValue), - } - } -} - -impl From for DynamicComponentAddress { - fn from(value: ComponentAddress) -> Self { - Self::Static(value) - } -} - -impl From for DynamicComponentAddress { - fn from(value: u32) -> Self { - Self::Named(value) - } -} - -impl TryFrom for DynamicComponentAddress { - type Error = ParseComponentAddressError; - - fn try_from(value: GlobalAddress) -> Result { - Ok(Self::Static(ComponentAddress::try_from( - value.into_node_id(), - )?)) - } -} - -impl TryFrom for DynamicComponentAddress { - type Error = ParseComponentAddressError; - - fn try_from(value: ManifestAddress) -> Result { - Ok(match value { - ManifestAddress::Static(value) => Self::Static(value.try_into()?), - ManifestAddress::Named(value) => Self::Named(value), - }) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DynamicResourceAddress { - Static(ResourceAddress), - Named(u32), -} - -impl Categorize for DynamicResourceAddress { - #[inline] - fn value_kind() -> ValueKind { - ValueKind::Custom(ManifestCustomValueKind::Address) - } -} - -impl> Encode - for DynamicResourceAddress -{ - #[inline] - fn encode_value_kind(&self, encoder: &mut E) -> Result<(), EncodeError> { - encoder.write_value_kind(Self::value_kind()) - } - - #[inline] - fn encode_body(&self, encoder: &mut E) -> Result<(), EncodeError> { - match self { - Self::Static(address) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_STATIC)?; - encoder.write_slice(address.as_node_id().as_bytes())?; - } - Self::Named(address_id) => { - encoder.write_discriminator(MANIFEST_ADDRESS_DISCRIMINATOR_NAMED)?; - encoder.write_slice(&address_id.to_le_bytes())?; - } - } - Ok(()) - } -} - -impl> Decode - for DynamicResourceAddress -{ - fn decode_body_with_value_kind( - decoder: &mut D, - value_kind: ValueKind, - ) -> Result { - decoder.check_preloaded_value_kind(value_kind, Self::value_kind())?; - match decoder.read_discriminator()? { - MANIFEST_ADDRESS_DISCRIMINATOR_STATIC => { - let slice = decoder.read_slice(NodeId::LENGTH)?; - Ok(Self::Static( - ResourceAddress::try_from(slice) - .map_err(|_| DecodeError::InvalidCustomValue)?, - )) - } - MANIFEST_ADDRESS_DISCRIMINATOR_NAMED => { - let slice = decoder.read_slice(4)?; - let id = u32::from_le_bytes(slice.try_into().unwrap()); - Ok(Self::Named(id)) - } - _ => Err(DecodeError::InvalidCustomValue), - } - } -} - -impl From for DynamicResourceAddress { - fn from(value: ResourceAddress) -> Self { - Self::Static(value) - } -} - -impl From for DynamicResourceAddress { - fn from(value: u32) -> Self { - Self::Named(value) - } -} - -impl TryFrom for DynamicResourceAddress { - type Error = ParseResourceAddressError; - - fn try_from(value: GlobalAddress) -> Result { - Ok(Self::Static(ResourceAddress::try_from( - value.into_node_id(), - )?)) - } -} - -impl TryFrom for DynamicResourceAddress { - type Error = ParseResourceAddressError; - - fn try_from(value: ManifestAddress) -> Result { - Ok(match value { - ManifestAddress::Static(value) => Self::Static(value.try_into()?), - ManifestAddress::Named(value) => Self::Named(value), - }) - } -} -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub enum InstructionV1 { //============== // Worktop diff --git a/radix-transactions/src/model/v1/instructions.rs b/radix-transactions/src/model/v1/instructions.rs index a0fb5329050..a9069b87ad3 100644 --- a/radix-transactions/src/model/v1/instructions.rs +++ b/radix-transactions/src/model/v1/instructions.rs @@ -1,7 +1,7 @@ use super::*; use crate::internal_prelude::*; -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct InstructionsV1(pub Vec); diff --git a/radix-transactions/src/model/v1/intent.rs b/radix-transactions/src/model/v1/intent.rs index c21caad6505..209d631a363 100644 --- a/radix-transactions/src/model/v1/intent.rs +++ b/radix-transactions/src/model/v1/intent.rs @@ -6,7 +6,7 @@ use crate::internal_prelude::*; // See versioned.rs for tests and a demonstration for the calculation of hashes etc //================================================================================= -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub struct IntentV1 { pub header: TransactionHeaderV1, pub instructions: InstructionsV1, diff --git a/radix-transactions/src/model/v1/intent_signatures.rs b/radix-transactions/src/model/v1/intent_signatures.rs index 1d7fdb3b3b5..812c6e9776b 100644 --- a/radix-transactions/src/model/v1/intent_signatures.rs +++ b/radix-transactions/src/model/v1/intent_signatures.rs @@ -42,11 +42,11 @@ impl From<(Ed25519PublicKey, Ed25519Signature)> for SignatureWithPublicKeyV1 { } } -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct IntentSignatureV1(pub SignatureWithPublicKeyV1); -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct IntentSignaturesV1 { pub signatures: Vec, diff --git a/radix-transactions/src/model/v1/manifest.rs b/radix-transactions/src/model/v1/manifest.rs index b1157995791..e48a8d4d504 100644 --- a/radix-transactions/src/model/v1/manifest.rs +++ b/radix-transactions/src/model/v1/manifest.rs @@ -7,7 +7,7 @@ use crate::internal_prelude::*; // in eg the manifest builder //================================================================================= -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub struct TransactionManifestV1 { pub instructions: Vec, pub blobs: IndexMap>, diff --git a/radix-transactions/src/model/v1/message.rs b/radix-transactions/src/model/v1/message.rs index 601aecdae98..a2eacac275f 100644 --- a/radix-transactions/src/model/v1/message.rs +++ b/radix-transactions/src/model/v1/message.rs @@ -2,7 +2,7 @@ use super::*; use crate::internal_prelude::*; /// Transaction messages as per REP-70 -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub enum MessageV1 { None, Plaintext(PlaintextMessageV1), @@ -19,7 +19,7 @@ impl Default for MessageV1 { // PLAINTEXT MESSAGE //============================================================================ -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub struct PlaintextMessageV1 { pub mime_type: String, pub message: MessageContentsV1, @@ -29,7 +29,7 @@ pub struct PlaintextMessageV1 { /// whether the message is intended to be displayable as text, or not. /// /// This data model ensures that messages intended to be displayable as text are valid unicode strings. -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub enum MessageContentsV1 { String(String), Bytes(Vec), @@ -68,7 +68,7 @@ impl MessageContentsV1 { /// - We persist 128-bit symmetric keys because we wish to save on payload size, and: /// * 128-bit AES is considered secure enough for most use cases (EG bitcoin hash rate is only 2^93 / year) /// * It's being used with a transient key - so a hypothetical successful attack would only decrypt one message -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub struct EncryptedMessageV1 { pub encrypted: AesGcmPayload, // Note we use a collection here rather than a struct to be forward-compatible to adding more curve types. @@ -76,13 +76,15 @@ pub struct EncryptedMessageV1 { pub decryptors_by_curve: IndexMap, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ManifestSbor)] +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ManifestSbor, ScryptoDescribe, +)] pub enum CurveType { Ed25519, Secp256k1, } -#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, ManifestSbor, ScryptoDescribe)] pub enum DecryptorsByCurve { Ed25519 { dh_ephemeral_public_key: Ed25519PublicKey, @@ -112,7 +114,7 @@ impl DecryptorsByCurve { /// The last 8 bytes of the Blake2b-256 hash of the public key bytes, /// in their standard Radix byte-serialization. -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, ManifestSbor)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct PublicKeyFingerprint(pub [u8; Self::LENGTH]); @@ -140,7 +142,7 @@ impl From for PublicKeyFingerprint { /// * Nonce/IV: 12 bytes /// * Cipher(text): Variable length /// * Tag/MAC: 16 bytes -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct AesGcmPayload(pub Vec); @@ -152,7 +154,7 @@ pub struct AesGcmPayload(pub Vec); /// This must be serialized as per https://www.ietf.org/rfc/rfc3394.txt as `IV || Cipher` where: /// * IV: First 8 bytes /// * Cipher: The wrapped 128 bit key, encoded as two 64 bit blocks -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct AesWrapped128BitKey(pub [u8; Self::LENGTH]); diff --git a/radix-transactions/src/model/v1/mod.rs b/radix-transactions/src/model/v1/mod.rs index 1e8997f53b1..9dd6379a1d0 100644 --- a/radix-transactions/src/model/v1/mod.rs +++ b/radix-transactions/src/model/v1/mod.rs @@ -1,6 +1,8 @@ use super::*; mod blobs; +mod dynamic_addresses; +mod flash_transaction; mod header; mod instruction; mod instructions; @@ -11,12 +13,15 @@ mod message; mod notarized_transaction; mod notary_signature; mod preview_transaction; +mod round_update_transaction; mod signed_intent; mod system_transaction; mod test_transaction; mod validated_notarized_transaction; pub use blobs::*; +pub use dynamic_addresses::*; +pub use flash_transaction::*; pub use header::*; pub use instruction::*; pub use instructions::*; @@ -27,6 +32,7 @@ pub use message::*; pub use notarized_transaction::*; pub use notary_signature::*; pub use preview_transaction::*; +pub use round_update_transaction::*; pub use signed_intent::*; pub use system_transaction::*; pub use test_transaction::*; diff --git a/radix-transactions/src/model/v1/notarized_transaction.rs b/radix-transactions/src/model/v1/notarized_transaction.rs index d5f30cdadeb..8b00a7373c2 100644 --- a/radix-transactions/src/model/v1/notarized_transaction.rs +++ b/radix-transactions/src/model/v1/notarized_transaction.rs @@ -6,7 +6,11 @@ use crate::internal_prelude::*; // See versioned.rs for tests and a demonstration for the calculation of hashes etc //================================================================================= -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe, ScryptoSborAssertion)] +#[sbor_assert( + fixed("FILE:notarized_transaction_v1_schema.txt"), + settings(allow_name_changes) +)] pub struct NotarizedTransactionV1 { pub signed_intent: SignedIntentV1, pub notary_signature: NotarySignatureV1, diff --git a/radix-transactions/src/model/v1/notarized_transaction_v1_schema.txt b/radix-transactions/src/model/v1/notarized_transaction_v1_schema.txt new file mode 100644 index 00000000000..67bc7304d3e --- /dev/null +++ b/radix-transactions/src/model/v1/notarized_transaction_v1_schema.txt @@ -0,0 +1 @@ +5c2102220001210320221c0e0120220201010a010000000000000001010a1b000000000000000e0120220201010a020000000000000001010a15000000000000000e0120220401010a030000000000000001010a050000000000000001010a080000000000000001010a0a000000000000000e012022070001070701010a040000000000000001010a040000000000000000010709000107d000010701000107080a000d012201010a06000000000000000f012307201e0222010001078500220200010785000107c00122020001078501010a0700000000000000032201000107a10622010001078504220200010785000107c00522020001078501010a0700000000000000102200112201000107a414220200010785000107c01522020001078501010a070000000000000016220100010785122200132200172200212202000107a1000107c0222202000107a101010a0700000000000000232201000107a1242201000107a1302201000107a4312201000107a4402204000107830001070c0001070c00010740412203000107810001070c00010740422203000107810001070c00010740432203000107810001070c00010740442203000107810001070c00010740452203000107820001070c00010740522200502200512202000107830001070c0d0122000107c20d012201010a09000000000000000d0122000107070f012307200300220001220101010a0b0000000000000002220101010a0d000000000000000e012022020001070c01010a0c000000000000000f01230720020022010001070c012201000107410e0120220201010a0e0000000000000001010a0f000000000000000d01220001070710022201010a10000000000000002201010a11000000000000000f01230720020022000122000f0123072002002202000107d201010a1200000000000000012202000107d101010a120000000000000010022201010a13000000000000002201010a14000000000000000d0122000107070d0122000107070d012201010a16000000000000000f012307200200220101010a1700000000000000012202000107d201010a19000000000000000e0120220101010a18000000000000000d0122000107070e0120220101010a1a000000000000000d0122000107070f012307200200220101010a170000000000000001220101010a190000000000000020211c022201010c164e6f746172697a65645472616e73616374696f6e5631220101220001200c020d7369676e65645f696e74656e74106e6f746172795f7369676e6174757265022201010c0e5369676e6564496e74656e745631220101220001200c0206696e74656e7411696e74656e745f7369676e617475726573022201010c08496e74656e745631220101220001200c04066865616465720c696e737472756374696f6e7305626c6f6273076d657373616765022201010c135472616e73616374696f6e4865616465725631220101220001200c070a6e6574776f726b5f69641573746172745f65706f63685f696e636c757369766513656e645f65706f63685f6578636c7573697665056e6f6e6365116e6f746172795f7075626c69635f6b6579136e6f746172795f69735f7369676e61746f72790e7469705f70657263656e74616765022201010c0545706f6368220000022201010c0e496e737472756374696f6e735631220000022201010c0d496e737472756374696f6e56312201012201012307211e02022201010c1254616b65416c6c46726f6d576f726b746f70220101220001200c01107265736f757263655f6164647265737300022201010c0f54616b6546726f6d576f726b746f70220101220001200c02107265736f757263655f6164647265737306616d6f756e7401022201010c1b54616b654e6f6e46756e6769626c657346726f6d576f726b746f70220101220001200c02107265736f757263655f616464726573730369647303022201010c0f52657475726e546f576f726b746f70220101220001200c01096275636b65745f696406022201010c18417373657274576f726b746f70436f6e7461696e73416e79220101220001200c01107265736f757263655f6164647265737304022201010c15417373657274576f726b746f70436f6e7461696e73220101220001200c02107265736f757263655f6164647265737306616d6f756e7405022201010c21417373657274576f726b746f70436f6e7461696e734e6f6e46756e6769626c6573220101220001200c02107265736f757263655f616464726573730369647310022201010c0f506f7046726f6d417574685a6f6e6522000011022201010c0e50757368546f417574685a6f6e65220101220001200c010870726f6f665f696414022201010c1f43726561746550726f6f6646726f6d417574685a6f6e654f66416d6f756e74220101220001200c02107265736f757263655f6164647265737306616d6f756e7415022201010c2543726561746550726f6f6646726f6d417574685a6f6e654f664e6f6e46756e6769626c6573220101220001200c02107265736f757263655f616464726573730369647316022201010c1c43726561746550726f6f6646726f6d417574685a6f6e654f66416c6c220101220001200c01107265736f757263655f6164647265737312022201010c1244726f70417574685a6f6e6550726f6f667322000013022201010c1944726f70417574685a6f6e65526567756c617250726f6f667322000017022201010c1b44726f70417574685a6f6e655369676e617475726550726f6f667322000021022201010c1d43726561746550726f6f6646726f6d4275636b65744f66416d6f756e74220101220001200c02096275636b65745f696406616d6f756e7422022201010c2343726561746550726f6f6646726f6d4275636b65744f664e6f6e46756e6769626c6573220101220001200c02096275636b65745f69640369647323022201010c1a43726561746550726f6f6646726f6d4275636b65744f66416c6c220101220001200c01096275636b65745f696424022201010c0c4275726e5265736f75726365220101220001200c01096275636b65745f696430022201010c0a436c6f6e6550726f6f66220101220001200c010870726f6f665f696431022201010c0944726f7050726f6f66220101220001200c010870726f6f665f696440022201010c0c43616c6c46756e6374696f6e220101220001200c040f7061636b6167655f616464726573730e626c75657072696e745f6e616d650d66756e6374696f6e5f6e616d65046172677341022201010c0a43616c6c4d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677342022201010c1143616c6c526f79616c74794d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677343022201010c1243616c6c4d657461646174614d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677344022201010c1843616c6c526f6c6541737369676e6d656e744d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677345022201010c1543616c6c4469726563745661756c744d6574686f64220101220001200c0307616464726573730b6d6574686f645f6e616d65046172677352022201010c0f44726f704e616d656450726f6f667322000050022201010c0d44726f70416c6c50726f6f667322000051022201010c15416c6c6f63617465476c6f62616c41646472657373220101220001200c020f7061636b6167655f616464726573730e626c75657072696e745f6e616d6502220000220000022201010c07426c6f62735631220000022201010c06426c6f625631220000022201010c094d65737361676556312201012201012307210300022201010c044e6f6e6522000001022201010c09506c61696e7465787422000002022201010c09456e63727970746564220000022201010c12506c61696e746578744d6573736167655631220101220001200c02096d696d655f74797065076d657373616765022201010c114d657373616765436f6e74656e747356312201012201012307210200022201010c06537472696e6722000001022201010c054279746573220000022201010c12456e637279707465644d6573736167655631220101220001200c0209656e6372797074656413646563727970746f72735f62795f6375727665022201010c0d41657347636d5061796c6f616422000002220000220000022201010c094375727665547970652201012201012307210200022201010c074564323535313922000001022201010c09536563703235366b31220000022201010c11446563727970746f7273427943757276652201012201012307210200022201010c0745643235353139220101220001200c021764685f657068656d6572616c5f7075626c69635f6b65790a646563727970746f727301022201010c09536563703235366b31220101220001200c021764685f657068656d6572616c5f7075626c69635f6b65790a646563727970746f727302220000220000022201010c145075626c69634b657946696e6765727072696e74220000022201010c13416573577261707065643132384269744b6579220000022201010c12496e74656e745369676e6174757265735631220000022201010c11496e74656e745369676e617475726556312201012201012307210200022201010c09536563703235366b31220101220001200c01097369676e617475726501022201010c0745643235353139220101220001200c020a7075626c69635f6b6579097369676e6174757265022201010c12536563703235366b315369676e617475726522000002220000220000022201010c10456432353531395369676e617475726522000002220000220000022201010c114e6f746172795369676e617475726556312201012201012307210200022201010c09536563703235366b3122000001022201010c074564323535313922000020221c00000000000000000000000000000000000000000000000000000000000000000000000000000c012102220101090800000022010109080000000c012102220101091800000022010109180000000000000000000c0121022201010941000000220101094100000000000c0121022201010940000000220101094000000000002201010a0000000000000000 \ No newline at end of file diff --git a/radix-transactions/src/model/v1/notary_signature.rs b/radix-transactions/src/model/v1/notary_signature.rs index 20136055c5f..ad3f4f1c0b0 100644 --- a/radix-transactions/src/model/v1/notary_signature.rs +++ b/radix-transactions/src/model/v1/notary_signature.rs @@ -25,7 +25,7 @@ impl From for SignatureV1 { } } -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] #[sbor(transparent)] pub struct NotarySignatureV1(pub SignatureV1); diff --git a/radix-transactions/src/model/v1/preview_transaction.rs b/radix-transactions/src/model/v1/preview_transaction.rs index 590aedf7c35..25fa1662bcf 100644 --- a/radix-transactions/src/model/v1/preview_transaction.rs +++ b/radix-transactions/src/model/v1/preview_transaction.rs @@ -9,7 +9,7 @@ pub struct PreviewFlags { pub disable_auth: bool, } -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub struct PreviewIntentV1 { pub intent: IntentV1, pub signer_public_keys: Vec, diff --git a/radix-transactions/src/model/v1/round_update_transaction.rs b/radix-transactions/src/model/v1/round_update_transaction.rs new file mode 100644 index 00000000000..71ea78dbd7b --- /dev/null +++ b/radix-transactions/src/model/v1/round_update_transaction.rs @@ -0,0 +1,134 @@ +use super::*; +use crate::internal_prelude::*; + +/// This is used in the node to increment rounds. +#[derive(Debug, Clone, Categorize, Encode, Decode, PartialEq, Eq, ScryptoDescribe)] +pub struct RoundUpdateTransactionV1 { + pub proposer_timestamp_ms: i64, + pub epoch: Epoch, + pub round: Round, + pub leader_proposal_history: LeaderProposalHistory, +} + +impl RoundUpdateTransactionV1 { + /// Note - we purposefully restrict what the content of a Round Update transaction can do + /// so we convert it to instructions at run-time. + pub fn create_instructions(&self) -> Vec { + vec![InstructionV1::CallMethod { + address: CONSENSUS_MANAGER.into(), + method_name: CONSENSUS_MANAGER_NEXT_ROUND_IDENT.to_string(), + args: to_manifest_value(&ConsensusManagerNextRoundInput { + round: self.round, + proposer_timestamp_ms: self.proposer_timestamp_ms, + leader_proposal_history: self.leader_proposal_history.clone(), + }) + .expect("round update input encoding should succeed"), + }] + } + + pub fn prepare(&self) -> Result { + let prepared_instructions = InstructionsV1(self.create_instructions()).prepare_partial()?; + let encoded_source = manifest_encode(&self)?; + // Minor TODO - for a slight performance improvement, change this to be read from the decoder + // As per the other hashes, don't include the prefix byte + let source_hash = hash(&encoded_source[1..]); + let instructions_hash = prepared_instructions.summary.hash; + let round_update_hash = HashAccumulator::new() + .update([ + TRANSACTION_HASHABLE_PAYLOAD_PREFIX, + TransactionDiscriminator::V1RoundUpdate as u8, + ]) + // We include the full source transaction contents + .update(source_hash) + // We also include the instructions hash, so the exact instructions can be proven + .update(instructions_hash) + .finalize(); + Ok(PreparedRoundUpdateTransactionV1 { + encoded_instructions: manifest_encode(&prepared_instructions.inner.0)?, + references: prepared_instructions.references, + blobs: index_map_new(), + summary: Summary { + effective_length: prepared_instructions.summary.effective_length, + total_bytes_hashed: prepared_instructions.summary.total_bytes_hashed, + hash: round_update_hash, + }, + }) + } +} + +impl TransactionPayload for RoundUpdateTransactionV1 { + type Prepared = PreparedRoundUpdateTransactionV1; + type Raw = RawRoundUpdateTransactionV1; +} + +pub struct PreparedRoundUpdateTransactionV1 { + pub encoded_instructions: Vec, + pub references: IndexSet, + pub blobs: IndexMap>, + pub summary: Summary, +} + +impl HasSummary for PreparedRoundUpdateTransactionV1 { + fn get_summary(&self) -> &Summary { + &self.summary + } +} + +define_raw_transaction_payload!(RawRoundUpdateTransactionV1); + +impl TransactionPayloadPreparable for PreparedRoundUpdateTransactionV1 { + type Raw = RawRoundUpdateTransactionV1; + + fn prepare_for_payload(decoder: &mut TransactionDecoder) -> Result { + let decoded = RoundUpdateTransactionV1::from_payload_variant(decoder.decode()?); + decoded.prepare() + } +} + +impl TransactionFullChildPreparable for PreparedRoundUpdateTransactionV1 { + fn prepare_as_full_body_child(decoder: &mut TransactionDecoder) -> Result { + let decoded = decoder.decode::()?; + decoded.prepare() + } +} + +impl PreparedRoundUpdateTransactionV1 { + pub fn get_executable(&self) -> Executable<'_> { + Executable::new( + &self.encoded_instructions, + &self.references, + &self.blobs, + ExecutionContext { + intent_hash: TransactionIntentHash::NotToCheck { + intent_hash: self.summary.hash, + }, + epoch_range: None, + payload_size: 0, + num_of_signature_validations: 0, + auth_zone_params: AuthZoneParams { + initial_proofs: btreeset!(system_execution(SystemExecution::Validator)), + virtual_resources: BTreeSet::new(), + }, + costing_parameters: TransactionCostingParameters { + tip_percentage: 0, + free_credit_in_xrd: Decimal::ZERO, + abort_when_loan_repaid: false, + }, + pre_allocated_addresses: vec![], + }, + true, + ) + } +} + +define_wrapped_hash!(RoundUpdateTransactionHash); + +impl HasRoundUpdateTransactionHash for PreparedRoundUpdateTransactionV1 { + fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash { + RoundUpdateTransactionHash::from_hash(self.summary.hash) + } +} + +pub trait HasRoundUpdateTransactionHash { + fn round_update_transaction_hash(&self) -> RoundUpdateTransactionHash; +} diff --git a/radix-transactions/src/model/v1/signed_intent.rs b/radix-transactions/src/model/v1/signed_intent.rs index 24cd0e36339..70e8441d01f 100644 --- a/radix-transactions/src/model/v1/signed_intent.rs +++ b/radix-transactions/src/model/v1/signed_intent.rs @@ -6,7 +6,7 @@ use crate::internal_prelude::*; // See versioned.rs for tests and a demonstration for the calculation of hashes etc //================================================================================= -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub struct SignedIntentV1 { pub intent: IntentV1, pub intent_signatures: IntentSignaturesV1, diff --git a/radix-transactions/src/model/v1/system_transaction.rs b/radix-transactions/src/model/v1/system_transaction.rs index d0ffe083b3a..1305cc4b9b8 100644 --- a/radix-transactions/src/model/v1/system_transaction.rs +++ b/radix-transactions/src/model/v1/system_transaction.rs @@ -2,7 +2,7 @@ use super::{ExecutionContext, TransactionCostingParameters}; use crate::internal_prelude::*; use crate::model::{AuthZoneParams, Executable}; -#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor)] +#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)] pub struct SystemTransactionV1 { pub instructions: InstructionsV1, pub blobs: BlobsV1, diff --git a/radix-transactions/src/model/versioned.rs b/radix-transactions/src/model/versioned.rs index 3e45737c12e..383107a1a11 100644 --- a/radix-transactions/src/model/versioned.rs +++ b/radix-transactions/src/model/versioned.rs @@ -16,7 +16,6 @@ pub enum TransactionDiscriminator { V1Notarized = V1_NOTARIZED_TRANSACTION, V1System = V1_SYSTEM_TRANSACTION, V1RoundUpdate = V1_ROUND_UPDATE_TRANSACTION, - V1Preview = V1_PREVIEW_TRANSACTION, V1Ledger = V1_LEDGER_TRANSACTION, V1Flash = V1_FLASH_TRANSACTION, } @@ -26,15 +25,33 @@ const V1_SIGNED_INTENT: u8 = 2; const V1_NOTARIZED_TRANSACTION: u8 = 3; const V1_SYSTEM_TRANSACTION: u8 = 4; const V1_ROUND_UPDATE_TRANSACTION: u8 = 5; -const V1_PREVIEW_TRANSACTION: u8 = 6; +// NOTE: 6 used to be reserved for serialized preview transactions, +// but they have never been serialized, so 6 is free for re-use const V1_LEDGER_TRANSACTION: u8 = 7; const V1_FLASH_TRANSACTION: u8 = 8; /// An enum of a variety of different transaction payload types. -/// This might see use in (eg) the Node's transaction parse API. -/// These represent the different transaction types. -#[derive(Clone, Debug, Eq, PartialEq, ManifestSbor)] +/// +/// Running `to_payload_bytes()` on each transaction type gives the same +/// as Manifest SBOR encoding the variant of this enum. +/// +/// For this reason, this type might see use in (e.g.) the Node's +/// transaction parse API. +/// +/// All the transaction types also implement `ScryptoDescribe`, primarily +/// so that they can derive `ScryptoSborAssertion` to ensure we don't change +/// the types accidentally. +#[derive(Clone, Debug, Eq, PartialEq, ManifestSbor, ScryptoDescribe, ScryptoSborAssertion)] #[sbor(impl_variant_traits)] +#[sbor_assert( + // This sum type of all payload-convertible transactions is extensible, so + // we use `backwards_compatible` here. But most individual transaction models + // should themselves be `fixed`, e.g. NotarizedTransactionV1 + backwards_compatible( + bottlenose = "FILE:any_transaction_payload_schema.txt" + ), + settings(allow_name_changes) +)] pub enum VersionedTransactionPayload { #[sbor(flatten, discriminator(V1_INTENT))] IntentV1(IntentV1), @@ -44,6 +61,12 @@ pub enum VersionedTransactionPayload { NotarizedTransactionV1(NotarizedTransactionV1), #[sbor(flatten, discriminator(V1_SYSTEM_TRANSACTION))] SystemTransactionV1(SystemTransactionV1), + #[sbor(flatten, discriminator(V1_ROUND_UPDATE_TRANSACTION))] + RoundUpdateTransactionV1(RoundUpdateTransactionV1), + #[sbor(discriminator(V1_LEDGER_TRANSACTION))] // Not flattened because it's an enum + LedgerTransaction(LedgerTransaction), + #[sbor(flatten, discriminator(V1_FLASH_TRANSACTION))] + FlashTransactionV1(FlashTransactionV1), } #[cfg(test)] diff --git a/sbor-derive-common/src/sbor_assert.rs b/sbor-derive-common/src/sbor_assert.rs index c2245df1857..90b7d125119 100644 --- a/sbor-derive-common/src/sbor_assert.rs +++ b/sbor-derive-common/src/sbor_assert.rs @@ -390,7 +390,7 @@ fn handle_generate( )); // We panic because the generate test is always expected to fail - so that someone doesn't leave it in generate mode accidentally. - panic!("Schema written successfully to {}", full_file_path.display()); + panic!("\n\nSchema written successfully to:\n {}\n\nNow panicking so that you can't accidentally leave this in generate mode and have your tests pass!\n\n", full_file_path.display()); }, }; diff --git a/scrypto-derive/src/ast.rs b/scrypto-derive/src/ast.rs index a100eeeb1ae..775bb082856 100644 --- a/scrypto-derive/src/ast.rs +++ b/scrypto-derive/src/ast.rs @@ -22,6 +22,7 @@ impl Parse for Blueprint { } /// Represents a Blueprint module which consists of a struct and an implementation of said struct +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct BlueprintMod { pub vis: Visibility, pub mod_token: Token![mod], @@ -89,6 +90,7 @@ impl Parse for BlueprintMod { } } +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct EventsInner { pub paren_token: Paren, pub paths: Punctuated, @@ -104,6 +106,7 @@ impl Parse for EventsInner { } } +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct TypesInner { pub paren_token: Paren, pub aliasable_types: Punctuated, diff --git a/scrypto-derive/src/blueprint.rs b/scrypto-derive/src/blueprint.rs index 411c0278f25..9363488cc42 100644 --- a/scrypto-derive/src/blueprint.rs +++ b/scrypto-derive/src/blueprint.rs @@ -17,6 +17,7 @@ macro_rules! trace { }}; } +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct GlobalComponent { pub ident: Ident, pub comma: Comma, @@ -36,6 +37,7 @@ impl Parse for GlobalComponent { } } +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct ImportBlueprintFn { pub sig: Signature, pub semi_token: Token![;], @@ -49,6 +51,7 @@ impl Parse for ImportBlueprintFn { } } +#[allow(dead_code)] // Fields for tokens from parse for completeness pub struct ImportBlueprint { pub package: Expr, pub comma0: Comma, diff --git a/scrypto-test/src/ledger_simulator/ledger_simulator.rs b/scrypto-test/src/ledger_simulator/ledger_simulator.rs index fca8bd49b64..f3f4ddc2005 100644 --- a/scrypto-test/src/ledger_simulator/ledger_simulator.rs +++ b/scrypto-test/src/ledger_simulator/ledger_simulator.rs @@ -34,9 +34,7 @@ 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::{ - CommittableSubstateDatabase, DatabaseUpdate, ListableSubstateDatabase, SubstateDatabase, -}; +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; use radix_substate_store_queries::typed_substate_layout::*;