From 769c59648e4ba8166560eeb45622f7e8aebc0d42 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sun, 15 Sep 2024 20:51:23 +0100 Subject: [PATCH] feature: Introduce Test Transaction builder --- radix-common/src/crypto/public_key_hash.rs | 4 + .../src/types/non_fungible_global_id.rs | 2 + .../tests/protocol/transaction.rs | 34 ++- .../tests/system/subintent_auth.rs | 200 +++++++----------- .../tests/system/subintent_leaks.rs | 101 +++------ .../tests/system/subintent_lock_fee.rs | 58 ++--- .../tests/system/subintent_txn_shape.rs | 138 ++++++++---- .../src/builder/manifest_namer.rs | 86 -------- .../src/model/v1/test_transaction.rs | 196 ++++++++++------- scrypto-test/src/prelude.rs | 1 + 10 files changed, 374 insertions(+), 446 deletions(-) diff --git a/radix-common/src/crypto/public_key_hash.rs b/radix-common/src/crypto/public_key_hash.rs index f9867d87d08..84ea1cb9973 100644 --- a/radix-common/src/crypto/public_key_hash.rs +++ b/radix-common/src/crypto/public_key_hash.rs @@ -10,6 +10,10 @@ pub trait HasPublicKeyHash { type TypedPublicKeyHash: IsPublicKeyHash; fn get_hash(&self) -> Self::TypedPublicKeyHash; + + fn signature_proof(&self) -> NonFungibleGlobalId { + NonFungibleGlobalId::from_public_key_hash(self.get_hash()) + } } pub trait IsPublicKeyHash: Copy { diff --git a/radix-common/src/types/non_fungible_global_id.rs b/radix-common/src/types/non_fungible_global_id.rs index f444b6ac889..1d832182cae 100644 --- a/radix-common/src/types/non_fungible_global_id.rs +++ b/radix-common/src/types/non_fungible_global_id.rs @@ -181,10 +181,12 @@ pub trait FromPublicKey: Sized { } impl FromPublicKey for NonFungibleGlobalId { + /// Prefer using the `signature` function or the `signature_proof()` method. fn from_public_key(public_key: &P) -> Self { Self::from_public_key_hash(public_key.get_hash()) } + /// Prefer using the `signature` function or the `signature_proof()` method. fn from_public_key_hash(public_key_hash: P) -> Self { match public_key_hash.into_enum() { PublicKeyHash::Secp256k1(public_key_hash) => NonFungibleGlobalId::new( diff --git a/radix-engine-tests/tests/protocol/transaction.rs b/radix-engine-tests/tests/protocol/transaction.rs index bcfa9f35d51..fb53dd368b2 100644 --- a/radix-engine-tests/tests/protocol/transaction.rs +++ b/radix-engine-tests/tests/protocol/transaction.rs @@ -1,6 +1,3 @@ -use radix_common::prelude::*; -use radix_engine::errors::*; -use radix_engine::updates::ProtocolVersion; use scrypto_test::prelude::*; #[test] @@ -12,21 +9,22 @@ fn bottlenose_protocol_should_not_support_v2_transactions() { let (public_key, _, account) = ledger.new_allocated_account(); // Act - let intents = (0..2) - .into_iter() - .map(|_| { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .build(); - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }) - .collect(); - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + let child_one = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .yield_to_parent(()) + .build(), + [], + ); + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child_one) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_specific_rejection(|e| matches!(e, RejectionReason::TransactionNotYetSupported)); diff --git a/radix-engine-tests/tests/system/subintent_auth.rs b/radix-engine-tests/tests/system/subintent_auth.rs index 0213854ce22..ea9c9cb6044 100644 --- a/radix-engine-tests/tests/system/subintent_auth.rs +++ b/radix-engine-tests/tests/system/subintent_auth.rs @@ -1,15 +1,4 @@ -use radix_common::constants::TRANSACTION_PROCESSOR_PACKAGE; -use radix_common::prelude::*; -use radix_engine::errors::{RuntimeError, SystemModuleError}; -use radix_engine::system::system_modules::auth::AuthError; -use radix_engine_interface::blueprints::transaction_processor::{ - TRANSACTION_PROCESSOR_BLUEPRINT, TRANSACTION_PROCESSOR_RUN_IDENT, -}; -use radix_engine_interface::macros::dec; -use radix_transactions::builder::{ManifestBuilder, ResolvableArguments}; -use radix_transactions::manifest::YieldToChild; -use radix_transactions::model::{InstructionV1, ManifestNamedIntentIndex, TestTransaction}; -use scrypto_test::ledger_simulator::LedgerSimulatorBuilder; +use scrypto_test::prelude::*; #[test] fn should_not_be_able_to_use_root_auth_in_subintent() { @@ -18,40 +7,27 @@ fn should_not_be_able_to_use_root_auth_in_subintent() { let (public_key, _, account) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - { - let manifest = ManifestBuilder::new_v2() - .withdraw_from_account(account, XRD, dec!(10)) - .deposit_entire_worktop(account) - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset!(), - ) - }, - ]; - - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .withdraw_from_account(account, XRD, dec!(10)) + .deposit_entire_worktop(account) + .yield_to_parent(()) + .build(), + [], + ); + + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_specific_failure(|e| { @@ -70,40 +46,28 @@ fn should_be_able_to_use_separate_auth_in_subintent() { let (public_key2, _, account2) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - { - let manifest = ManifestBuilder::new_v2() - .withdraw_from_account(account2, XRD, dec!(10)) - .deposit_entire_worktop(account2) - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![NonFungibleGlobalId::from_public_key(&public_key2)], - ) - }, - ]; - - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .withdraw_from_account(account2, XRD, dec!(10)) + .deposit_entire_worktop(account2) + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [public_key2.signature_proof()], + ); + + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_commit_success(); @@ -124,51 +88,39 @@ fn should_not_be_able_to_call_tx_processor_in_subintent() { let (public_key, _, account) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + let instructions: Vec = Vec::new(); + let manifest_encoded_instructions = manifest_encode(&instructions).unwrap(); + + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .call_function( + TRANSACTION_PROCESSOR_PACKAGE, + TRANSACTION_PROCESSOR_BLUEPRINT, + TRANSACTION_PROCESSOR_RUN_IDENT, + ManifestTransactionProcessorRunInput { + manifest_encoded_instructions, + global_address_reservations: vec![], + references: vec![], + blobs: index_map_new(), + }, ) - }, - { - let instructions: Vec = Vec::new(); - let manifest_encoded_instructions = manifest_encode(&instructions).unwrap(); - let manifest = ManifestBuilder::new_v2() - .call_function( - TRANSACTION_PROCESSOR_PACKAGE, - TRANSACTION_PROCESSOR_BLUEPRINT, - TRANSACTION_PROCESSOR_RUN_IDENT, - ManifestTransactionProcessorRunInput { - manifest_encoded_instructions, - global_address_reservations: vec![], - references: vec![], - blobs: index_map_new(), - }, - ) - .build(); - - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![], - ) - }, - ]; - - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + .yield_to_parent(()) + .build(), + [], + ); + + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_specific_failure(|e| { diff --git a/radix-engine-tests/tests/system/subintent_leaks.rs b/radix-engine-tests/tests/system/subintent_leaks.rs index 71d04f7fbca..07ef5928a31 100644 --- a/radix-engine-tests/tests/system/subintent_leaks.rs +++ b/radix-engine-tests/tests/system/subintent_leaks.rs @@ -1,9 +1,3 @@ -use radix_engine::blueprints::resource::FungibleResourceManagerError; -use radix_engine::errors::{ApplicationError, RuntimeError}; -use radix_transactions::builder::ResolvableArguments; -use radix_transactions::manifest::YieldToChild; -use radix_transactions::model::{ManifestNamedIntentIndex, TestTransaction}; -use radix_transactions::prelude::ManifestBuilder; use scrypto_test::prelude::*; #[test] @@ -14,39 +8,26 @@ fn bucket_leak_in_subintent_should_fail() { let (public_key2, _, account2) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - { - let manifest = ManifestBuilder::new_v2() - .withdraw_from_account(account2, XRD, dec!(10)) - .build(); + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .withdraw_from_account(account2, XRD, 10) + .yield_to_parent(()) + .build(), + [public_key2.signature_proof()], + ); - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![NonFungibleGlobalId::from_public_key(&public_key2)], - ) - }, - ]; + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_specific_failure(|e| { @@ -67,39 +48,27 @@ fn proofs_in_subintent_should_autodrop() { let (public_key2, _, account2) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - { - let manifest = ManifestBuilder::new_v2() - .create_proof_from_account_of_amount(account2, XRD, dec!(10)) - .build(); + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .create_proof_from_account_of_amount(account2, XRD, 10) + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [public_key2.signature_proof()], + ); - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![NonFungibleGlobalId::from_public_key(&public_key2)], - ) - }, - ]; + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_commit_success(); diff --git a/radix-engine-tests/tests/system/subintent_lock_fee.rs b/radix-engine-tests/tests/system/subintent_lock_fee.rs index 302b4b005f6..257273bf375 100644 --- a/radix-engine-tests/tests/system/subintent_lock_fee.rs +++ b/radix-engine-tests/tests/system/subintent_lock_fee.rs @@ -1,53 +1,33 @@ -use radix_common::prelude::{FromPublicKey, NonFungibleGlobalId}; -use radix_engine::errors::{RuntimeError, SystemError}; -use radix_engine::transaction::ExecutionConfig; -use radix_rust::btreeset; -use radix_transactions::builder::ResolvableArguments; -use radix_transactions::manifest::YieldToChild; -use radix_transactions::model::{ManifestNamedIntentIndex, TestTransaction}; -use radix_transactions::prelude::ManifestBuilder; -use scrypto_test::ledger_simulator::LedgerSimulatorBuilder; +use scrypto_test::prelude::*; #[test] fn should_not_be_able_to_lock_fee_in_a_child_subintent() { // Arrange let mut ledger = LedgerSimulatorBuilder::new().build(); let (public_key, _, account) = ledger.new_allocated_account(); + let (public_key2, _, account2) = ledger.new_allocated_account(); // Act - let intents = vec![ - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(0), - args: ().resolve(), - }) - .0 - .build(); + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); - ( - manifest, - ledger.next_transaction_nonce(), - vec![1], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - { - let manifest = ManifestBuilder::new_v2() - .lock_standard_test_fee(account) - .build(); + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .lock_standard_test_fee(account2) + .yield_to_parent(()) + .build(), + [public_key2.signature_proof()], + ); - ( - manifest, - ledger.next_transaction_nonce(), - vec![], - btreeset![NonFungibleGlobalId::from_public_key(&public_key)], - ) - }, - ]; + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_specific_failure(|e| { diff --git a/radix-engine-tests/tests/system/subintent_txn_shape.rs b/radix-engine-tests/tests/system/subintent_txn_shape.rs index 7f6f9161c6d..5340a37b36e 100644 --- a/radix-engine-tests/tests/system/subintent_txn_shape.rs +++ b/radix-engine-tests/tests/system/subintent_txn_shape.rs @@ -1,59 +1,121 @@ -use radix_common::prelude::*; -use radix_transactions::builder::ResolvableArguments; -use radix_transactions::manifest::YieldToChild; -use radix_transactions::model::{ManifestNamedIntentIndex, TestTransaction}; -use radix_transactions::prelude::*; -use scrypto_test::ledger_simulator::LedgerSimulatorBuilder; +use scrypto_test::prelude::*; #[test] fn simple_subintent_should_work() { - test_subintent_txn_shape(vec![vec![1], vec![]]); + // Arrange + let mut ledger = LedgerSimulatorBuilder::new().build(); + let (public_key, _, account) = ledger.new_allocated_account(); + + // Act + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + let child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [], + ); + + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .use_child("child", child) + .lock_standard_test_fee(account) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); + + // Assert + receipt.expect_commit_success(); } #[test] fn multiple_flat_subintents_should_work() { - test_subintent_txn_shape(vec![vec![1, 2, 3, 4], vec![], vec![], vec![], vec![]]); + // Arrange + let mut ledger = LedgerSimulatorBuilder::new().build(); + let (public_key, _, account) = ledger.new_allocated_account(); + + // Act + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + let children = (0..4) + .into_iter() + .map(|_| { + builder.add_subintent( + ManifestBuilder::new_subintent_v2() + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [], + ) + }) + .collect::>(); + + let mut root_manifest_builder = ManifestBuilder::new_v2().lock_standard_test_fee(account); + + for (index, child_hash) in children.into_iter().enumerate() { + let child_name = format!("child{index}"); + root_manifest_builder = root_manifest_builder + .use_child(&child_name, child_hash) + .yield_to_child(&child_name, ()); + } + + let transaction = builder.finish_with_root_intent( + root_manifest_builder.build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); + + // Assert + receipt.expect_commit_success(); } #[test] fn multiple_deep_subintents_should_work() { - test_subintent_txn_shape(vec![vec![1], vec![2], vec![3], vec![4], vec![]]); -} - -fn test_subintent_txn_shape(children: Vec>) { // Arrange let mut ledger = LedgerSimulatorBuilder::new().build(); let (public_key, _, account) = ledger.new_allocated_account(); // Act - let mut intents = vec![]; - - for (index, intent_children) in children.into_iter().enumerate() { - let mut builder = ManifestBuilder::new_v2(); - if index == 0 { - builder = builder.lock_standard_test_fee(account); - } - for (index, _) in intent_children.iter().enumerate() { - builder = builder - .add_instruction_advanced(YieldToChild { - child_index: ManifestNamedIntentIndex(index as u32), - args: ().resolve(), - }) - .0 - } - - let manifest = builder.build(); - - let signatures = btreeset![NonFungibleGlobalId::from_public_key(&public_key)]; - intents.push(( - manifest, - ledger.next_transaction_nonce(), - intent_children, - signatures, - )) + let mut builder = TestTransaction::new_v2_builder(ledger.next_transaction_nonce()); + + // Create deepest child + let mut child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [], + ); + + // Create middle-layer children + for _ in 0..3 { + child = builder.add_subintent( + ManifestBuilder::new_subintent_v2() + .use_child("child", child) + .yield_to_child("child", ()) + // TODO-CUTTLEFISH: Fix the test / behaviour so this line can be uncommented + //.yield_to_parent(()) + .build(), + [], + ); } - let receipt = ledger.execute_test_transaction(TestTransaction::new_v2_from_nonce(intents)); + // Create top-level root manifest + let transaction = builder.finish_with_root_intent( + ManifestBuilder::new_v2() + .lock_standard_test_fee(account) + .use_child("child", child) + .yield_to_child("child", ()) + .build(), + [public_key.signature_proof()], + ); + + let receipt = ledger.execute_test_transaction(transaction); // Assert receipt.expect_commit_success(); diff --git a/radix-transactions/src/builder/manifest_namer.rs b/radix-transactions/src/builder/manifest_namer.rs index 68d8b1ff3cb..958dc60b8f0 100644 --- a/radix-transactions/src/builder/manifest_namer.rs +++ b/radix-transactions/src/builder/manifest_namer.rs @@ -1052,92 +1052,6 @@ impl, E: Debug> ResolvableGlobalAddr } } -//===================== -// TRANSACTION SIGNATURES -//===================== - -/// This is created so that you can put TransactionSignatures::None in your LedgerSimulator -/// Because [] can't resolve the correct generic when used as a trait impl -pub enum TransactionSignatures { - None, - Some(Vec), -} - -pub trait ResolvableTransactionSignatures { - fn resolve(self) -> Vec; -} - -impl ResolvableTransactionSignatures for TransactionSignatures { - fn resolve(self) -> Vec { - match self { - TransactionSignatures::None => vec![], - TransactionSignatures::Some(signatures) => signatures, - } - } -} - -impl ResolvableTransactionSignatures for Vec { - fn resolve(self) -> Vec { - self - } -} - -impl ResolvableTransactionSignatures for [NonFungibleGlobalId; N] { - fn resolve(self) -> Vec { - self.into() - } -} - -impl ResolvableTransactionSignatures for NonFungibleGlobalId { - fn resolve(self) -> Vec { - vec![self] - } -} - -impl ResolvableTransactionSignatures for Vec { - fn resolve(self) -> Vec { - self.into_iter() - .map(|key| NonFungibleGlobalId::from_public_key(&key)) - .collect() - } -} - -impl ResolvableTransactionSignatures for [PublicKey; N] { - fn resolve(self) -> Vec { - self.into_iter() - .map(|key| NonFungibleGlobalId::from_public_key(&key)) - .collect() - } -} - -impl ResolvableTransactionSignatures for PublicKey { - fn resolve(self) -> Vec { - vec![NonFungibleGlobalId::from_public_key(&self)] - } -} - -impl ResolvableTransactionSignatures for Vec { - fn resolve(self) -> Vec { - self.into_iter() - .map(|key_hash| NonFungibleGlobalId::from_public_key_hash(key_hash)) - .collect() - } -} - -impl ResolvableTransactionSignatures for [PublicKeyHash; N] { - fn resolve(self) -> Vec { - self.into_iter() - .map(|key_hash| NonFungibleGlobalId::from_public_key_hash(key_hash)) - .collect() - } -} - -impl ResolvableTransactionSignatures for PublicKeyHash { - fn resolve(self) -> Vec { - vec![NonFungibleGlobalId::from_public_key_hash(self)] - } -} - //===================== // DECIMAL //===================== diff --git a/radix-transactions/src/model/v1/test_transaction.rs b/radix-transactions/src/model/v1/test_transaction.rs index 9531385374a..7e4ebf40324 100644 --- a/radix-transactions/src/model/v1/test_transaction.rs +++ b/radix-transactions/src/model/v1/test_transaction.rs @@ -9,7 +9,82 @@ use std::ops::Deref; #[derive(ManifestSbor)] pub enum TestTransaction { V1(TestIntentV1), - V2(Vec), + V2 { + root_intent: TestIntentV2, + subintents: Vec, + }, +} + +pub struct TestTransactionV2Builder { + nonce: u32, + subintents: IndexMap, +} + +impl TestTransactionV2Builder { + pub fn new(nonce: u32) -> Self { + Self { + nonce, + subintents: Default::default(), + } + } + + pub fn add_subintent( + &mut self, + manifest: SubintentManifestV2, + proofs: impl IntoIterator, + ) -> SubintentHash { + let (instructions, blobs, child_intents) = manifest.for_intent(); + let intent = self.create_intent(instructions, blobs, child_intents, proofs); + let hash = intent.hash; + self.subintents.insert(SubintentHash(hash), intent); + SubintentHash(hash) + } + + pub fn finish_with_root_intent( + self, + manifest: TransactionManifestV2, + proofs: impl IntoIterator, + ) -> TestTransaction { + let (instructions, blobs, child_intents) = manifest.for_intent(); + let root_intent = self.create_intent(instructions, blobs, child_intents, proofs); + TestTransaction::V2 { + root_intent, + subintents: self.subintents.into_values().collect(), + } + } + + fn create_intent( + &self, + instructions: InstructionsV2, + blobs: BlobsV1, + child_intents: ChildIntentsV2, + proofs: impl IntoIterator, + ) -> TestIntentV2 { + let children_intent_indices = child_intents + .children + .into_iter() + .map(|child| { + let subintent_index = self + .subintents + .get_index_of(&child.hash) + .expect("Child subintents should exist already in the Test Transaction"); + let thread_index = subintent_index + 1; + thread_index + }) + .collect(); + let nonce = self.nonce; + let subintent_count = self.subintents.len(); + let hash = hash(format!( + "Test transaction intent: {nonce} - {subintent_count}" + )); + TestIntentV2 { + instructions, + blobs, + hash, + initial_proofs: proofs.into_iter().collect(), + children_intent_indices, + } + } } #[derive(ManifestSbor)] @@ -45,6 +120,39 @@ pub struct PreparedTestIntent { pub initial_proofs: BTreeSet, } +impl PreparedTestIntent { + #[allow(deprecated)] + pub fn from_v1( + intent: TestIntentV1, + settings: &PreparationSettings, + ) -> Result { + let prepared_instructions = intent.instructions.prepare_partial(settings)?; + Ok(PreparedTestIntent { + encoded_instructions: Rc::new(manifest_encode(&prepared_instructions.inner.0)?), + references: prepared_instructions.references, + blobs: intent.blobs.prepare_partial(settings)?.blobs_by_hash, + hash: intent.hash, + children_intent_indices: vec![], + initial_proofs: intent.initial_proofs, + }) + } + + pub fn from_v2( + intent: TestIntentV2, + settings: &PreparationSettings, + ) -> Result { + let prepared_instructions = intent.instructions.prepare_partial(settings)?; + Ok(PreparedTestIntent { + encoded_instructions: Rc::new(manifest_encode(&prepared_instructions.inner.0)?), + references: prepared_instructions.references.deref().clone(), + blobs: intent.blobs.prepare_partial(settings)?.blobs_by_hash, + hash: intent.hash, + children_intent_indices: intent.children_intent_indices, + initial_proofs: intent.initial_proofs, + }) + } +} + impl TestTransaction { /// The nonce needs to be globally unique amongst test transactions on your ledger pub fn new_v1_from_nonce( @@ -73,55 +181,8 @@ impl TestTransaction { }) } - pub fn new_v2_from_nonce( - intents: Vec<( - TransactionManifestV2, - u32, - Vec, - BTreeSet, - )>, - ) -> Self { - let intents = intents - .into_iter() - .map( - |(manifest, nonce, children_intent_indices, initial_proofs)| { - ( - manifest, - hash(format!("Test transaction: {}", nonce)), - children_intent_indices, - initial_proofs, - ) - }, - ) - .collect(); - Self::new_v2(intents) - } - - pub fn new_v2( - intents: Vec<( - TransactionManifestV2, - Hash, - Vec, - BTreeSet, - )>, - ) -> Self { - let intents = intents - .into_iter() - .map( - |(manifest, hash, children_intent_indices, initial_proofs)| { - let (instructions, blobs, ..) = manifest.for_intent(); - TestIntentV2 { - instructions, - blobs, - hash, - children_intent_indices, - initial_proofs, - } - }, - ) - .collect(); - - Self::V2(intents) + pub fn new_v2_builder(nonce: u32) -> TestTransactionV2Builder { + TestTransactionV2Builder::new(nonce) } #[allow(deprecated)] @@ -130,31 +191,16 @@ impl TestTransaction { settings: &PreparationSettings, ) -> Result { match self { - Self::V1(intent) => { - let prepared_instructions = intent.instructions.prepare_partial(settings)?; - Ok(PreparedTestTransaction::V1(PreparedTestIntent { - encoded_instructions: Rc::new(manifest_encode(&prepared_instructions.inner.0)?), - references: prepared_instructions.references, - blobs: intent.blobs.prepare_partial(settings)?.blobs_by_hash, - hash: intent.hash, - children_intent_indices: vec![], - initial_proofs: intent.initial_proofs, - })) - } - Self::V2(intents) => { - let mut prepared = vec![]; - for intent in intents { - let prepared_instructions = intent.instructions.prepare_partial(settings)?; - prepared.push(PreparedTestIntent { - encoded_instructions: Rc::new(manifest_encode( - &prepared_instructions.inner.0, - )?), - references: prepared_instructions.references.deref().clone(), - blobs: intent.blobs.prepare_partial(settings)?.blobs_by_hash, - hash: intent.hash, - children_intent_indices: intent.children_intent_indices, - initial_proofs: intent.initial_proofs, - }); + Self::V1(intent) => Ok(PreparedTestTransaction::V1(PreparedTestIntent::from_v1( + intent, settings, + )?)), + Self::V2 { + root_intent, + subintents, + } => { + let mut prepared = vec![PreparedTestIntent::from_v2(root_intent, settings)?]; + for intent in subintents { + prepared.push(PreparedTestIntent::from_v2(intent, settings)?); } Ok(PreparedTestTransaction::V2(prepared)) diff --git a/scrypto-test/src/prelude.rs b/scrypto-test/src/prelude.rs index fdff703c80e..def638c9703 100644 --- a/scrypto-test/src/prelude.rs +++ b/scrypto-test/src/prelude.rs @@ -34,6 +34,7 @@ pub use radix_engine::system::system_modules::*; pub use radix_engine::system::system_substates::*; pub use radix_engine::track::*; pub use radix_engine::transaction::*; +pub use radix_engine::updates::*; pub use radix_engine::utils::*; pub use radix_engine::vm::wasm::*; pub use radix_engine::vm::*;