From 12a9ce36cc8c36c728f095b450caeb45195eb431 Mon Sep 17 00:00:00 2001 From: Omar Date: Sat, 31 Aug 2024 19:17:30 +0300 Subject: [PATCH] Support the new toolkit receipt --- Cargo.lock | 2 + crates/radix-engine-toolkit-uniffi/Cargo.toml | 2 + .../src/transaction/manifest.rs | 28 +- .../src/functions/manifest.rs | 5 +- .../src/transaction_types/interface.rs | 18 +- .../transaction_types/traverser/traverser.rs | 52 ++- .../src/transaction_types/types.rs | 349 ++++++++---------- .../tests/test_runner_extension.rs | 4 +- 8 files changed, 206 insertions(+), 254 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5604671..eabce0fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1977,6 +1977,7 @@ dependencies = [ "radix-common", "radix-engine", "radix-engine-interface", + "radix-engine-toolkit 1.2.0", "radix-engine-toolkit 2.1.2", "radix-substate-store-impls", "radix-substate-store-queries", @@ -1985,6 +1986,7 @@ dependencies = [ "sbor", "scrypto", "scrypto-test", + "serde_json", "thiserror", "uniffi", ] diff --git a/crates/radix-engine-toolkit-uniffi/Cargo.toml b/crates/radix-engine-toolkit-uniffi/Cargo.toml index 88b3ddfc..1f1997c5 100644 --- a/crates/radix-engine-toolkit-uniffi/Cargo.toml +++ b/crates/radix-engine-toolkit-uniffi/Cargo.toml @@ -13,6 +13,7 @@ radix-engine = { workspace = true } radix-engine-interface = { workspace = true } radix-substate-store-queries = { workspace = true } radix-transactions = { workspace = true } +native-radix-engine-toolkit = { workspace = true } # Core Radix Engine Toolkit radix-engine-toolkit = { path = "../radix-engine-toolkit" } @@ -22,6 +23,7 @@ uniffi = { git = "https://github.com/0xOmarA/uniffi-rs", tag = "v0.25.4", featur hex = "0.4.3" thiserror = "1.0.50" paste = "1.0.12" +serde_json = "1.0.127" [build-dependencies] # The UniFFI crate for generating bindings to other languages diff --git a/crates/radix-engine-toolkit-uniffi/src/transaction/manifest.rs b/crates/radix-engine-toolkit-uniffi/src/transaction/manifest.rs index f8307d8f..da7520eb 100644 --- a/crates/radix-engine-toolkit-uniffi/src/transaction/manifest.rs +++ b/crates/radix-engine-toolkit-uniffi/src/transaction/manifest.rs @@ -15,6 +15,9 @@ // specific language governing permissions and limitations // under the License. +use native_radix_engine_toolkit::receipt::{ + RuntimeToolkitTransactionReceipt, SerializableToolkitTransactionReceipt, +}; use sbor::Versioned; use crate::prelude::*; @@ -98,17 +101,24 @@ impl TransactionManifest { pub fn execution_summary( &self, network_id: u8, - encoded_receipt: Vec, + toolkit_receipt: String, ) -> Result { let native = self.clone().to_native(); - let versioned_transaction_receipt = native_scrypto_decode::< - NativeVersionedTransactionReceipt, - >(&encoded_receipt)?; - let receipt = versioned_transaction_receipt - .as_latest_version() - .ok_or(RadixEngineToolkitError::InvalidReceipt)?; - - core_manifest_execution_summary(&native, receipt) + let network_definition = + core_network_definition_from_network_id(network_id); + let receipt = serde_json::from_str::< + SerializableToolkitTransactionReceipt, + >(&toolkit_receipt) + .ok() + .and_then(|receipt| { + receipt + .into_runtime_receipt(&NativeAddressBech32Decoder::new( + &network_definition, + )) + .ok() + }) + .ok_or(RadixEngineToolkitError::InvalidReceipt)?; + core_manifest_execution_summary(&native, &receipt) .map_err(|_| RadixEngineToolkitError::InvalidReceipt) .map(|summary| ExecutionSummary::from_native(summary, network_id))? } diff --git a/crates/radix-engine-toolkit/src/functions/manifest.rs b/crates/radix-engine-toolkit/src/functions/manifest.rs index a4681ba4..17c1d803 100644 --- a/crates/radix-engine-toolkit/src/functions/manifest.rs +++ b/crates/radix-engine-toolkit/src/functions/manifest.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +use native_radix_engine_toolkit::receipt::RuntimeToolkitTransactionReceipt; use radix_common::prelude::*; use radix_engine_interface::blueprints::access_controller::*; use radix_engine_interface::blueprints::account::*; @@ -22,8 +23,6 @@ use radix_transactions::errors::*; use radix_transactions::prelude::*; use radix_transactions::validation::*; -use radix_engine::transaction::*; - use crate::transaction_types::*; pub fn hash(manifest: &TransactionManifestV1) -> Result { @@ -227,7 +226,7 @@ pub fn summary(manifest: &TransactionManifestV1) -> ManifestSummary { pub fn execution_summary( manifest: &TransactionManifestV1, - receipt: &TransactionReceipt, + receipt: &RuntimeToolkitTransactionReceipt, ) -> Result { crate::transaction_types::execution_summary(manifest, receipt) } diff --git a/crates/radix-engine-toolkit/src/transaction_types/interface.rs b/crates/radix-engine-toolkit/src/transaction_types/interface.rs index 9b7e7a9a..849b38ae 100644 --- a/crates/radix-engine-toolkit/src/transaction_types/interface.rs +++ b/crates/radix-engine-toolkit/src/transaction_types/interface.rs @@ -19,8 +19,8 @@ //! any of the implementation details of how the module finds and determines //! the transaction types. +use native_radix_engine_toolkit::receipt::RuntimeToolkitTransactionReceipt; use radix_common::prelude::*; -use radix_engine::transaction::*; use radix_substate_store_queries::typed_substate_layout::*; use radix_transactions::prelude::*; @@ -131,10 +131,10 @@ pub fn summary(manifest: &TransactionManifestV1) -> ManifestSummary { pub fn execution_summary( manifest: &TransactionManifestV1, - receipt: &TransactionReceipt, + receipt: &RuntimeToolkitTransactionReceipt, ) -> Result { // Attempt to create a tx types receipt from the passed receipt - let receipt = TransactionTypesReceipt::new(receipt) + let receipt = TransactionTypesReceipt::new(&receipt) .ok_or(TransactionTypesError::InvalidReceipt)?; // Settings up the various detectors @@ -308,16 +308,8 @@ pub fn execution_summary( .rev() .collect::>(); - let fee_locks = FeeLocks { - lock: receipt.execution_trace().fee_locks.lock, - contingent_lock: receipt.execution_trace().fee_locks.contingent_lock, - }; - let fee_summary = FeeSummary { - execution_cost: receipt.fee_summary.total_execution_cost_in_xrd, - finalization_cost: receipt.fee_summary.total_finalization_cost_in_xrd, - storage_expansion_cost: receipt.fee_summary.total_storage_cost_in_xrd, - royalty_cost: receipt.fee_summary.total_royalty_cost_in_xrd, - }; + let fee_locks = receipt.fee_locks(); + let fee_summary = receipt.fee_summary(); Ok(ExecutionSummary { account_withdraws, diff --git a/crates/radix-engine-toolkit/src/transaction_types/traverser/traverser.rs b/crates/radix-engine-toolkit/src/transaction_types/traverser/traverser.rs index da99af46..d17351a9 100644 --- a/crates/radix-engine-toolkit/src/transaction_types/traverser/traverser.rs +++ b/crates/radix-engine-toolkit/src/transaction_types/traverser/traverser.rs @@ -42,9 +42,9 @@ pub mod manifest_summary { instruction_index: usize, ) { // At the beginning of an instruction, call the on_instruction callback - callbacks.iter_mut().for_each( - |callback| callback.on_instruction(instruction, instruction_index) - ); + callbacks.iter_mut().for_each(|callback| { + callback.on_instruction(instruction, instruction_index) + }); // Notify the callbacks of the created account proofs handle_on_create_proof(callbacks, instruction); @@ -58,9 +58,9 @@ pub mod manifest_summary { let Ok(global_address) = GlobalAddress::try_from(node_id) else { continue; }; - callbacks.iter_mut().for_each( - |callback| callback.on_global_entity_encounter(global_address) - ); + callbacks.iter_mut().for_each(|callback| { + callback.on_global_entity_encounter(global_address) + }); } } @@ -249,9 +249,9 @@ pub mod execution_summary { bucket_tracker: &IndexMap, ) { let worktop_changes_entry = receipt - .execution_trace() .worktop_changes() - .get(&instruction_index).cloned() + .get(&instruction_index) + .cloned() .unwrap_or_default(); let inputs = { @@ -289,9 +289,9 @@ pub mod execution_summary { if let Some(resource_indicator) = bucket_tracker.get(bucket_id) { - inputs.push( - ResourceSpecifier::from(resource_indicator.clone()) - ) + inputs.push(ResourceSpecifier::from( + resource_indicator.clone(), + )) } } /* Non-sink methods */ @@ -325,17 +325,16 @@ pub mod execution_summary { inputs }; - let outputs = - worktop_changes_entry - .iter() - .filter_map(|item| { - if let WorktopChange::Put(resource_specifier) = item { - Some(resource_specifier.clone()) - } else { - None - } - }) - .collect::>(); + let outputs = worktop_changes_entry + .iter() + .filter_map(|item| { + if let WorktopChange::Put(resource_specifier) = item { + Some(resource_specifier.clone()) + } else { + None + } + }) + .collect::>(); callbacks.iter_mut().for_each(|callback| { ExecutionSummaryCallback::on_instruction( *callback, @@ -531,10 +530,8 @@ pub mod execution_summary { .expressions() .contains(&ManifestExpression::EntireWorktop) { - if let Some(worktop_changes) = receipt - .execution_trace() - .worktop_changes() - .get(&instruction_index) + if let Some(worktop_changes) = + receipt.worktop_changes().get(&instruction_index) { for resource_indicator in worktop_changes .iter() @@ -737,7 +734,6 @@ pub mod execution_summary { resource_address: ResourceAddress, ) -> Option { receipt - .execution_trace() .worktop_changes() .entry(instruction_index) .or_default() @@ -760,7 +756,6 @@ pub mod execution_summary { resource_address: ResourceAddress, ) -> Option> { receipt - .execution_trace() .worktop_changes() .entry(instruction_index) .or_default() @@ -787,7 +782,6 @@ pub mod execution_summary { resource_address: ResourceAddress, ) -> Option> { receipt - .execution_trace() .worktop_changes() .entry(instruction_index) .or_default() diff --git a/crates/radix-engine-toolkit/src/transaction_types/types.rs b/crates/radix-engine-toolkit/src/transaction_types/types.rs index 112f42a4..e06151a7 100644 --- a/crates/radix-engine-toolkit/src/transaction_types/types.rs +++ b/crates/radix-engine-toolkit/src/transaction_types/types.rs @@ -17,15 +17,15 @@ use std::ops::*; -use radix_engine::blueprints::models::KeyValueKeyPayload; -use radix_engine::object_modules::metadata::MetadataEntryV1; -use radix_engine::system::system_substates::*; -use radix_engine::track::*; -use radix_substate_store_interface::interface::*; +use native_radix_engine_toolkit::receipt::{ + MetadataUpdate, RuntimeToolkitTransactionReceipt, ToolkitTransactionReceipt, +}; use radix_substate_store_queries::typed_substate_layout::*; use scrypto::prelude::*; -use radix_engine::system::system_modules::execution_trace::ResourceSpecifier; +use radix_engine::system::system_modules::execution_trace::{ + ResourceSpecifier, WorktopChange, +}; use radix_engine::transaction::*; use radix_engine_interface::blueprints::account::*; @@ -239,126 +239,108 @@ impl From for ManifestClass { /// must belong to a transaction that executed successfully and the execution /// trace must be present. #[derive(Clone, Debug)] -pub struct TransactionTypesReceipt<'r> { - receipt: &'r TransactionReceipt, - commit_result: &'r CommitResult, - execution_trace: &'r TransactionExecutionTrace, -} +pub struct TransactionTypesReceipt<'r>(&'r RuntimeToolkitTransactionReceipt); impl<'r> TransactionTypesReceipt<'r> { - pub fn new(receipt: &'r TransactionReceipt) -> Option { - if let TransactionResult::Commit( - ref commit_result @ CommitResult { - execution_trace: Some(ref execution_trace), - outcome: TransactionOutcome::Success(..), - .. - }, - ) = &receipt.result - { - Some(Self { - receipt, - commit_result, - execution_trace, - }) - } else { - None + pub fn new(receipt: &'r RuntimeToolkitTransactionReceipt) -> Option { + match receipt { + ToolkitTransactionReceipt::CommitSuccess { .. } => { + Some(Self(receipt)) + } + ToolkitTransactionReceipt::CommitFailure { .. } + | ToolkitTransactionReceipt::Reject { .. } + | ToolkitTransactionReceipt::Abort { .. } => None, } } } impl<'r> TransactionTypesReceipt<'r> { - pub fn new_components(&self) -> &'r IndexSet { - self.commit_result.new_component_addresses() - } - - pub fn new_resources(&self) -> &'r IndexSet { - self.commit_result.new_resource_addresses() + pub fn new_components(&self) -> IndexSet { + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .new_entities + .iter() + .filter_map(|entity| { + ComponentAddress::try_from(entity.as_bytes()).ok() + }) + .collect() } - pub fn new_packages(&self) -> &'r IndexSet { - self.commit_result.new_package_addresses() + pub fn new_resources(&self) -> IndexSet { + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .new_entities + .iter() + .filter_map(|entity| { + ResourceAddress::try_from(entity.as_bytes()).ok() + }) + .collect() } - pub fn execution_trace(&self) -> &'r TransactionExecutionTrace { - self.execution_trace + pub fn new_packages(&self) -> IndexSet { + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .new_entities + .iter() + .filter_map(|entity| { + PackageAddress::try_from(entity.as_bytes()).ok() + }) + .collect() } pub fn metadata_of_new_entities( &self, ) -> IndexMap>> { - let mut map = IndexMap::< - GlobalAddress, - IndexMap>, - >::new(); - - for global_address in self.new_entities() { - let entry = map.entry(global_address).or_default(); - if let Some(NodeStateUpdates::Delta { by_partition }) = self - .commit_result - .state_updates - .by_node - .get(global_address.as_node_id()) - { - let entries = match by_partition.get(&METADATA_BASE_PARTITION) { - Some(PartitionStateUpdates::Delta { by_substate }) => { - by_substate - .iter() - .filter_map(|(key, value)| match value { - DatabaseUpdate::Set(value) => { - Some((key.clone(), value.clone())) + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .new_entities + .iter() + .filter_map(|entity| { + GlobalAddress::try_from(entity.as_bytes()).ok() + }) + .fold(IndexMap::new(), |mut acc, address| { + match state_updates_summary + .metadata_updates + .get(address.as_node_id()) + { + Some(entry) => { + acc.entry(address).or_default().extend( + entry.iter().map(|(key, value)| match value { + MetadataUpdate::Set(value) => { + (key.clone(), Some(value.clone())) } - DatabaseUpdate::Delete => None, - }) - .collect::>() - } - Some(PartitionStateUpdates::Batch( - BatchPartitionStateUpdate::Reset { - new_substate_values, - }, - )) => new_substate_values.clone(), - None => continue, - }; - - for (substate_key, data) in entries.into_iter() { - if let Ok(( - TypedSubstateKey::MetadataModule(key), - TypedSubstateValue::MetadataModule(value), - )) = to_typed_substate_key( - global_address.as_node_id().entity_type().unwrap(), - METADATA_BASE_PARTITION, - &substate_key, - ) - .and_then(|typed_substate_key| { - to_typed_substate_value(&typed_substate_key, &data).map( - |typed_substate_value| { - (typed_substate_key, typed_substate_value) - }, - ) - }) { - let TypedMetadataModuleSubstateKey::MetadataEntryKey( - key, - ) = key; - let value = match value { - TypedMetadataModuleSubstateValue::MetadataEntry( - KeyValueEntrySubstate::V1( - KeyValueEntrySubstateV1 { value, .. }, - ), - ) => value, - }; - entry.insert( - key, - value.map(|metadata_entry| { - let metadata: MetadataEntryV1 = - metadata_entry.as_unique_version().clone(); - metadata + MetadataUpdate::Delete => (key.clone(), None), }), ); + acc } + None => acc, } - } - } - - map + }) } fn new_entities(&self) -> IndexSet { @@ -379,47 +361,18 @@ impl<'r> TransactionTypesReceipt<'r> { } pub fn new_non_fungibles(&self) -> HashSet { - let mut minted_id_list = HashSet::new(); - let mut burnt_id_list = HashSet::new(); - for (event_type, event_payload) in - self.commit_result.application_events.iter() - { - if let Emitter::Method(node_id, ..) = event_type.0 { - match ResourceAddress::try_from(node_id.as_bytes()) { - Ok(address) if !address.is_fungible() => { - if event_type.1 - == MintNonFungibleResourceEvent::EVENT_NAME - { - let event: MintNonFungibleResourceEvent = - scrypto_decode(event_payload).unwrap(); - for local_id in event.ids { - minted_id_list.insert( - NonFungibleGlobalId::new( - address, local_id, - ), - ); - } - } else if event_type.1 - == BurnNonFungibleResourceEvent::EVENT_NAME - { - let event: BurnNonFungibleResourceEvent = - scrypto_decode(event_payload).unwrap(); - for local_id in event.ids { - burnt_id_list.insert( - NonFungibleGlobalId::new( - address, local_id, - ), - ); - } - } - } - _ => {} - } - } - } - - minted_id_list.retain(|item| !burnt_id_list.contains(item)); - minted_id_list + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .newly_minted_non_fungibles + .clone() + .into_iter() + .collect() } pub fn non_fungible_data( @@ -427,59 +380,56 @@ impl<'r> TransactionTypesReceipt<'r> { resource_address: &ResourceAddress, non_fungible_local_id: &NonFungibleLocalId, ) -> Option> { - let key = NonFungibleResourceManagerDataKeyPayload::from_content( - non_fungible_local_id.clone(), - ); - - self.commit_result - .state_updates - .by_node - .get(resource_address.as_node_id()) - .and_then(|item| { - let partition_number = MAIN_BASE_PARTITION - .at_offset( - NonFungibleResourceManagerPartitionOffset::DataKeyValue - .as_partition_offset(), - ) - .unwrap(); - - let NodeStateUpdates::Delta { by_partition } = item; - - by_partition.get(&partition_number) - }) - .and_then(|item| match item { - PartitionStateUpdates::Delta { by_substate } => by_substate - .get(&SubstateKey::Map(scrypto_encode(&key).unwrap())) - .and_then(|item| match item { - DatabaseUpdate::Set(value) => Some(value.clone()), - DatabaseUpdate::Delete => None, - }), - PartitionStateUpdates::Batch( - BatchPartitionStateUpdate::Reset { - new_substate_values, - }, - ) => new_substate_values - .get(&SubstateKey::Map(scrypto_encode(&key).unwrap())) - .cloned(), - }) - .and_then(|item| { - scrypto_decode::< - KeyValueEntrySubstate< - NonFungibleResourceManagerDataEntryPayload, - >, - >(&item) - .ok() - .and_then(|item| item.into_value()) - .and_then(|item| scrypto_encode(&item).ok()) - }) + let ToolkitTransactionReceipt::CommitSuccess { + state_updates_summary, + .. + } = self.0 + else { + unreachable!() + }; + state_updates_summary + .non_fungible_data_updates + .get(&NonFungibleGlobalId::new( + *resource_address, + non_fungible_local_id.clone(), + )) + .map(|value| value.clone()) } -} -impl<'r> Deref for TransactionTypesReceipt<'r> { - type Target = TransactionReceipt; + pub fn fee_locks(&self) -> FeeLocks { + let ToolkitTransactionReceipt::CommitSuccess { locked_fees, .. } = + self.0 + else { + unreachable!() + }; + FeeLocks { + lock: locked_fees.non_contingent, + contingent_lock: locked_fees.contingent, + } + } - fn deref(&self) -> &Self::Target { - self.receipt + pub fn fee_summary(&self) -> FeeSummary { + let ToolkitTransactionReceipt::CommitSuccess { fee_summary, .. } = + self.0 + else { + unreachable!() + }; + FeeSummary { + execution_cost: fee_summary.execution_fees_in_xrd, + finalization_cost: fee_summary.finalization_fees_in_xrd, + storage_expansion_cost: fee_summary.storage_fees_in_xrd, + royalty_cost: fee_summary.royalty_fees_in_xrd, + } + } + + pub fn worktop_changes(&self) -> IndexMap> { + let ToolkitTransactionReceipt::CommitSuccess { + worktop_changes, .. + } = self.0 + else { + unreachable!() + }; + worktop_changes.clone() } } @@ -631,9 +581,10 @@ impl From for ResourceSpecifier { ) | ResourceIndicator::Fungible( resource_address, - FungibleResourceIndicator::Predicted( - Predicted { value: amount, .. } - ), + FungibleResourceIndicator::Predicted(Predicted { + value: amount, + .. + }), ) => ResourceSpecifier::Amount(resource_address, amount), ResourceIndicator::NonFungible( resource_address, diff --git a/crates/radix-engine-toolkit/tests/test_runner_extension.rs b/crates/radix-engine-toolkit/tests/test_runner_extension.rs index d79f77c7..78055560 100644 --- a/crates/radix-engine-toolkit/tests/test_runner_extension.rs +++ b/crates/radix-engine-toolkit/tests/test_runner_extension.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +use native_radix_engine_toolkit::receipt::RuntimeToolkitTransactionReceipt; use radix_engine::system::bootstrap::*; use radix_engine::transaction::*; use radix_engine::vm::*; @@ -58,7 +59,8 @@ where radix_engine_toolkit::transaction_types::summary(&manifest); let execution_summary = radix_engine_toolkit::transaction_types::execution_summary( - &manifest, &receipt, + &manifest, + &RuntimeToolkitTransactionReceipt::try_from(receipt).unwrap(), ) .unwrap();