diff --git a/crates/iota-e2e-tests/tests/checkpoint_tests.rs b/crates/iota-e2e-tests/tests/checkpoint_tests.rs index f8ba9f11b33..6c620103577 100644 --- a/crates/iota-e2e-tests/tests/checkpoint_tests.rs +++ b/crates/iota-e2e-tests/tests/checkpoint_tests.rs @@ -65,7 +65,7 @@ async fn checkpoint_split_brain_test() { let tx = make_transfer_iota_transaction(&test_cluster.wallet, None, None).await; test_cluster .wallet - .execute_transaction_may_fail(tx) + .execute_transaction_may_fail(tx, None) .await .ok(); diff --git a/crates/iota-e2e-tests/tests/full_node_tests.rs b/crates/iota-e2e-tests/tests/full_node_tests.rs index c6e5db21b68..b7b54fa7314 100644 --- a/crates/iota-e2e-tests/tests/full_node_tests.rs +++ b/crates/iota-e2e-tests/tests/full_node_tests.rs @@ -1370,7 +1370,10 @@ async fn test_access_old_object_pruned() { } // Check that fullnode would return the same error. - let result = test_cluster.wallet.execute_transaction_may_fail(tx).await; + let result = test_cluster + .wallet + .execute_transaction_may_fail(tx, None) + .await; assert!( result.unwrap_err().to_string().contains( &UserInputError::ObjectVersionUnavailableForConsumption { @@ -1405,7 +1408,7 @@ async fn transfer_coin( .transfer(object_to_send, receiver) .build(), ); - let resp = context.execute_transaction_must_succeed(txn).await; + let resp = context.execute_transaction_must_succeed(txn, None).await; Ok((object_to_send.0, sender, receiver, resp.digest, gas_object)) } diff --git a/crates/iota-e2e-tests/tests/multisig_tests.rs b/crates/iota-e2e-tests/tests/multisig_tests.rs index a184ca30084..e13a7d6d4a0 100644 --- a/crates/iota-e2e-tests/tests/multisig_tests.rs +++ b/crates/iota-e2e-tests/tests/multisig_tests.rs @@ -95,7 +95,7 @@ async fn test_multisig_e2e() { let tx1 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[1]], 0b011); - let res = context.execute_transaction_must_succeed(tx1).await; + let res = context.execute_transaction_must_succeed(tx1, None).await; assert!(res.status_ok().unwrap()); // 2. sign with key 1 and 2 executes successfully. @@ -105,7 +105,7 @@ async fn test_multisig_e2e() { let tx2 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[&keys[1], &keys[2]], 0b110); - let res = context.execute_transaction_must_succeed(tx2).await; + let res = context.execute_transaction_must_succeed(tx2, None).await; assert!(res.status_ok().unwrap()); // 3. signature 2 and 1 swapped fails to execute. @@ -115,7 +115,7 @@ async fn test_multisig_e2e() { let tx3 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[&keys[2], &keys[1]], 0b110); - let res = context.execute_transaction_may_fail(tx3).await; + let res = context.execute_transaction_may_fail(tx3, None).await; assert!( res.unwrap_err() .to_string() @@ -126,7 +126,7 @@ async fn test_multisig_e2e() { let tx4 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0]], 0b001); - let res = context.execute_transaction_may_fail(tx4).await; + let res = context.execute_transaction_may_fail(tx4, None).await; assert!( res.unwrap_err() .to_string() @@ -137,7 +137,7 @@ async fn test_multisig_e2e() { let tx5 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[], 0b001); - let res = context.execute_transaction_may_fail(tx5).await; + let res = context.execute_transaction_may_fail(tx5, None).await; assert!( res.unwrap_err() .to_string() @@ -148,7 +148,7 @@ async fn test_multisig_e2e() { let tx6 = TestTransactionBuilder::new(multisig_addr, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(multisig_pk.clone(), &[&keys[0], &keys[0]], 0b011); - let res = context.execute_transaction_may_fail(tx6).await; + let res = context.execute_transaction_may_fail(tx6, None).await; assert!( res.unwrap_err() .to_string() @@ -171,7 +171,7 @@ async fn test_multisig_e2e() { let tx7 = TestTransactionBuilder::new(wrong_sender, gas, rgp) .transfer_iota(None, IotaAddress::ZERO) .build_and_sign_multisig(wrong_multisig_pk.clone(), &[&keys[0], &keys[2]], 0b101); - let res = context.execute_transaction_may_fail(tx7).await; + let res = context.execute_transaction_may_fail(tx7, None).await; assert!( res.unwrap_err() .to_string() @@ -232,7 +232,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![wrong_sig], multisig_pk.clone()).unwrap(), ); let tx_1 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_1).await; + let res = context.execute_transaction_may_fail(tx_1, None).await; assert!( res.unwrap_err() .to_string() @@ -245,7 +245,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![wrong_sig_2], multisig_pk.clone()).unwrap(), ); let tx_2 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_2).await; + let res = context.execute_transaction_may_fail(tx_2, None).await; assert!( res.unwrap_err() .to_string() @@ -258,7 +258,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![wrong_sig_3], multisig_pk.clone()).unwrap(), ); let tx_3 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_3).await; + let res = context.execute_transaction_may_fail(tx_3, None).await; assert!( res.unwrap_err() .to_string() @@ -276,7 +276,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![wrong_zklogin_sig], multisig_pk.clone()).unwrap(), ); let tx_4 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_4).await; + let res = context.execute_transaction_may_fail(tx_4, None).await; let pk3 = PublicKey::ZkLogin( ZkLoginPublicIdentifier::new(zklogin_inputs.get_iss(), zklogin_inputs.get_address_seed()) .unwrap(), @@ -299,7 +299,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![zklogin_sig_mismatch], multisig_pk.clone()).unwrap(), ); let tx_5 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_5).await; + let res = context.execute_transaction_may_fail(tx_5, None).await; assert!( res.unwrap_err() .to_string() @@ -317,7 +317,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![zklogin_sig_wrong_zklogin_inputs], multisig_pk.clone()).unwrap(), ); let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_7).await; + let res = context.execute_transaction_may_fail(tx_7, None).await; assert!( res.unwrap_err() .to_string() @@ -349,7 +349,7 @@ async fn test_multisig_with_zklogin_scenerios() { let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); let tx_8 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_8).await; + let res = context.execute_transaction_may_fail(tx_8, None).await; assert!( res.unwrap_err() .to_string() @@ -366,7 +366,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk.clone(), )); let tx_7 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_7).await; + let res = context.execute_transaction_may_fail(tx_7, None).await; assert!( res.unwrap_err() .to_string() @@ -386,7 +386,7 @@ async fn test_multisig_with_zklogin_scenerios() { let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig_0], multisig_pk.clone()).unwrap()); let tx_8 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_8).await; + let _ = context.execute_transaction_must_succeed(tx_8, None).await; // 2a. good secp256k1 sig used in multisig executes successfully. let gas = test_cluster @@ -400,7 +400,7 @@ async fn test_multisig_with_zklogin_scenerios() { let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig_1], multisig_pk.clone()).unwrap()); let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_9).await; + let _ = context.execute_transaction_must_succeed(tx_9, None).await; // 3a. good secp256r1 sig used in multisig executes successfully. let gas = test_cluster @@ -414,7 +414,7 @@ async fn test_multisig_with_zklogin_scenerios() { let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig_2], multisig_pk.clone()).unwrap()); let tx_9 = Transaction::from_generic_sig_data(tx_data, vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_9).await; + let _ = context.execute_transaction_must_succeed(tx_9, None).await; // 4b. good zklogin sig used in multisig executes successfully. let gas = test_cluster @@ -433,7 +433,7 @@ async fn test_multisig_with_zklogin_scenerios() { let multisig = GenericSignature::MultiSig(MultiSig::combine(vec![sig_4], multisig_pk.clone()).unwrap()); let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_10).await; + let _ = context.execute_transaction_must_succeed(tx_10, None).await; // 4c. good zklogin sig AND good ed25519 combined used in multisig executes // successfully. @@ -455,7 +455,7 @@ async fn test_multisig_with_zklogin_scenerios() { MultiSig::combine(vec![sig, sig_1], multisig_pk.clone()).unwrap(), ); let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx_11).await; + let _ = context.execute_transaction_must_succeed(tx_11, None).await; // 9. wrong bitmap fails to execute. let gas = test_cluster @@ -472,7 +472,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk.clone(), )); let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_11).await; + let res = context.execute_transaction_may_fail(tx_11, None).await; assert!( res.unwrap_err() .to_string() @@ -487,7 +487,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk.clone(), )); let tx_10 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_10).await; + let res = context.execute_transaction_may_fail(tx_10, None).await; assert!( res.unwrap_err() .to_string() @@ -514,7 +514,7 @@ async fn test_multisig_with_zklogin_scenerios() { bad_multisig_pk.clone(), )); let tx_11 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_11).await; + let res = context.execute_transaction_may_fail(tx_11, None).await; assert!( res.unwrap_err() .to_string() @@ -540,7 +540,7 @@ async fn test_multisig_with_zklogin_scenerios() { bad_multisig_pk, )); let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_14).await; + let res = context.execute_transaction_may_fail(tx_14, None).await; assert!( res.unwrap_err() .to_string() @@ -564,7 +564,7 @@ async fn test_multisig_with_zklogin_scenerios() { small_multisig_pk, )); let tx_13 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_13).await; + let res = context.execute_transaction_may_fail(tx_13, None).await; assert!( res.unwrap_err() .to_string() @@ -589,7 +589,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk_with_dup, )); let tx_14 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_14).await; + let res = context.execute_transaction_may_fail(tx_14, None).await; assert!( res.unwrap_err() .to_string() @@ -613,7 +613,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk_11, )); let tx_15 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_15).await; + let res = context.execute_transaction_may_fail(tx_15, None).await; assert!( res.unwrap_err() .to_string() @@ -638,7 +638,7 @@ async fn test_multisig_with_zklogin_scenerios() { multisig_pk_12, )); let tx_16 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_16).await; + let res = context.execute_transaction_may_fail(tx_16, None).await; assert!( res.unwrap_err() .to_string() @@ -662,7 +662,7 @@ async fn test_multisig_with_zklogin_scenerios() { bad_multisig_empty_pk, )); let tx_17 = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let res = context.execute_transaction_may_fail(tx_17).await; + let res = context.execute_transaction_may_fail(tx_17, None).await; assert!( res.unwrap_err() .to_string() @@ -682,7 +682,10 @@ async fn test_expired_epoch_zklogin_in_multisig() { let tx = construct_simple_zklogin_multisig_tx(&test_cluster) .await .unwrap(); - let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; + let res = test_cluster + .wallet + .execute_transaction_may_fail(tx, None) + .await; assert!( res.unwrap_err() .to_string() @@ -725,7 +728,7 @@ async fn test_random_zklogin_in_multisig() { MultiSig::combine(zklogin_sigs[..9].to_vec(), multisig_pk.clone()).unwrap(), ); let bad_tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![short_multisig]); - let res = context.execute_transaction_may_fail(bad_tx).await; + let res = context.execute_transaction_may_fail(bad_tx, None).await; assert!( res.unwrap_err() .to_string() @@ -736,7 +739,7 @@ async fn test_random_zklogin_in_multisig() { MultiSig::combine(zklogin_sigs.clone(), multisig_pk.clone()).unwrap(), ); let tx = Transaction::from_generic_sig_data(tx_data.clone(), vec![multisig]); - let _ = context.execute_transaction_must_succeed(tx).await; + let _ = context.execute_transaction_must_succeed(tx, None).await; } #[sim_test] @@ -771,7 +774,7 @@ async fn test_multisig_legacy_works() { .build_and_sign_multisig_legacy(multisig_pk_legacy, &[&keys[0], &keys[1]]); context - .execute_transaction_must_succeed(transfer_from_multisig) + .execute_transaction_must_succeed(transfer_from_multisig, None) .await; } @@ -790,7 +793,10 @@ async fn test_zklogin_inside_multisig_feature_deny() { let tx = construct_simple_zklogin_multisig_tx(&test_cluster) .await .unwrap(); - let res = test_cluster.wallet.execute_transaction_may_fail(tx).await; + let res = test_cluster + .wallet + .execute_transaction_may_fail(tx, None) + .await; assert!( res.unwrap_err() .to_string() diff --git a/crates/iota-e2e-tests/tests/shared_objects_tests.rs b/crates/iota-e2e-tests/tests/shared_objects_tests.rs index f216fe8ad7a..a7918044664 100644 --- a/crates/iota-e2e-tests/tests/shared_objects_tests.rs +++ b/crates/iota-e2e-tests/tests/shared_objects_tests.rs @@ -453,7 +453,7 @@ async fn call_shared_object_contract() { .build(); let effects = test_cluster .wallet - .execute_transaction_may_fail(test_cluster.wallet.sign_transaction(&transaction)) + .execute_transaction_may_fail(test_cluster.wallet.sign_transaction(&transaction), None) .await .unwrap() .effects diff --git a/crates/iota-e2e-tests/tests/zklogin_tests.rs b/crates/iota-e2e-tests/tests/zklogin_tests.rs index f9f84aefc38..24d66b7c123 100644 --- a/crates/iota-e2e-tests/tests/zklogin_tests.rs +++ b/crates/iota-e2e-tests/tests/zklogin_tests.rs @@ -123,7 +123,7 @@ async fn zklogin_end_to_end_test() { )); let signed_txn = Transaction::from_generic_sig_data(tx_data.clone(), vec![generic_sig]); let context = &test_cluster.wallet; - let res = context.execute_transaction_may_fail(signed_txn).await; + let res = context.execute_transaction_may_fail(signed_txn, None).await; assert!(res.is_ok()); // a txn with max_epoch mismatch with proof, fails to execute. @@ -136,7 +136,7 @@ async fn zklogin_end_to_end_test() { Transaction::from_generic_sig_data(tx_data, vec![generic_sig]); assert!( context - .execute_transaction_may_fail(signed_txn_with_wrong_max_epoch) + .execute_transaction_may_fail(signed_txn_with_wrong_max_epoch, None) .await .is_err() ); @@ -184,7 +184,7 @@ async fn test_expired_zklogin_sig() { let context = &test_cluster.wallet; let res = context - .execute_transaction_may_fail(signed_txn_expired) + .execute_transaction_may_fail(signed_txn_expired, None) .await; assert!( res.unwrap_err() diff --git a/crates/iota-sdk/src/wallet_context.rs b/crates/iota-sdk/src/wallet_context.rs index 35eb62ed9f9..6344ede6b98 100644 --- a/crates/iota-sdk/src/wallet_context.rs +++ b/crates/iota-sdk/src/wallet_context.rs @@ -299,9 +299,13 @@ impl WalletContext { pub async fn execute_transaction_must_succeed( &self, tx: Transaction, + response_opts: Option, ) -> IotaTransactionBlockResponse { tracing::debug!("Executing transaction: {:?}", tx); - let response = self.execute_transaction_may_fail(tx).await.unwrap(); + let response = self + .execute_transaction_may_fail(tx, response_opts) + .await + .unwrap(); assert!( response.status_ok().unwrap(), "Transaction failed: {:?}", @@ -317,18 +321,28 @@ impl WalletContext { pub async fn execute_transaction_may_fail( &self, tx: Transaction, + mut response_opts: Option, ) -> anyhow::Result { let client = self.get_client().await?; - Ok(client - .quorum_driver_api() - .execute_transaction_block( - tx, + + response_opts = if response_opts.is_none() { + Some( IotaTransactionBlockResponseOptions::new() .with_effects() .with_input() .with_events() .with_object_changes() .with_balance_changes(), + ) + } else { + response_opts + }; + + Ok(client + .quorum_driver_api() + .execute_transaction_block( + tx, + response_opts.unwrap(), Some(iota_types::quorum_driver_types::ExecuteTransactionRequestType::WaitForLocalExecution), ) .await?) diff --git a/crates/iota-source-validation/src/tests.rs b/crates/iota-source-validation/src/tests.rs index fbabc0ac1f9..cc3e396e762 100644 --- a/crates/iota-source-validation/src/tests.rs +++ b/crates/iota-source-validation/src/tests.rs @@ -617,7 +617,7 @@ fn sanitize_id(mut message: String, m: &HashMap) -> String { /// Compile and publish package at absolute path `package` to chain. async fn publish_package(context: &WalletContext, package: PathBuf) -> (ObjectRef, ObjectRef) { let txn = make_publish_transaction(context, package).await; - let response = context.execute_transaction_must_succeed(txn).await; + let response = context.execute_transaction_must_succeed(txn, None).await; let package = get_new_package_obj_from_response(&response).unwrap(); let cap = get_new_package_upgrade_cap_from_response(&response).unwrap(); (package, cap) @@ -651,7 +651,7 @@ async fn upgrade_package( /// its unpublished dependencies. async fn publish_package_and_deps(context: &WalletContext, package: PathBuf) -> ObjectRef { let txn = make_publish_transaction_with_deps(context, package).await; - let response = context.execute_transaction_must_succeed(txn).await; + let response = context.execute_transaction_must_succeed(txn, None).await; get_new_package_obj_from_response(&response).unwrap() } @@ -754,7 +754,9 @@ pub async fn upgrade_package_with_wallet( context.sign_transaction(&data) }; - let resp = context.execute_transaction_must_succeed(transaction).await; + let resp = context + .execute_transaction_must_succeed(transaction, None) + .await; ( get_new_package_obj_from_response(&resp).unwrap(), diff --git a/crates/iota-surfer/src/surfer_state.rs b/crates/iota-surfer/src/surfer_state.rs index f41ebb6aec7..cfeb1170081 100644 --- a/crates/iota-surfer/src/surfer_state.rs +++ b/crates/iota-surfer/src/surfer_state.rs @@ -174,7 +174,7 @@ impl SurferState { match self .cluster .wallet - .execute_transaction_may_fail(tx.clone()) + .execute_transaction_may_fail(tx.clone(), None) .await { Ok(effects) => break effects, @@ -333,7 +333,7 @@ impl SurferState { match self .cluster .wallet - .execute_transaction_may_fail(tx.clone()) + .execute_transaction_may_fail(tx.clone(), None) .await { Ok(response) => { diff --git a/crates/iota-test-transaction-builder/src/lib.rs b/crates/iota-test-transaction-builder/src/lib.rs index 45efb327b8a..731a09a9752 100644 --- a/crates/iota-test-transaction-builder/src/lib.rs +++ b/crates/iota-test-transaction-builder/src/lib.rs @@ -528,7 +528,7 @@ pub async fn publish_package(context: &WalletContext, path: PathBuf) -> ObjectRe .publish(path) .build(), ); - let resp = context.execute_transaction_must_succeed(txn).await; + let resp = context.execute_transaction_must_succeed(txn, None).await; get_new_package_obj_from_response(&resp).unwrap() } @@ -542,7 +542,7 @@ pub async fn publish_basics_package(context: &WalletContext) -> ObjectRef { .publish_examples("basics") .build(), ); - let resp = context.execute_transaction_must_succeed(txn).await; + let resp = context.execute_transaction_must_succeed(txn, None).await; get_new_package_obj_from_response(&resp).unwrap() } @@ -560,7 +560,7 @@ pub async fn publish_basics_package_and_make_counter( .build(), ); let resp = context - .execute_transaction_must_succeed(counter_creation_txn) + .execute_transaction_must_succeed(counter_creation_txn, None) .await; let counter_ref = resp .effects @@ -599,7 +599,7 @@ pub async fn increment_counter( .call_counter_increment(package_id, counter_id, initial_shared_version) .build(), ); - context.execute_transaction_must_succeed(txn).await + context.execute_transaction_must_succeed(txn, None).await } /// Executes a transaction to publish the `nfts` package and returns the package @@ -615,7 +615,7 @@ pub async fn publish_nfts_package( .publish_examples("nfts") .build(), ); - let resp = context.execute_transaction_must_succeed(txn).await; + let resp = context.execute_transaction_must_succeed(txn, None).await; let package_id = get_new_package_obj_from_response(&resp).unwrap().0; (package_id, gas_id, resp.digest) } @@ -635,7 +635,7 @@ pub async fn create_devnet_nft( .call_nft_create(package_id) .build(), ); - let resp = context.execute_transaction_must_succeed(txn).await; + let resp = context.execute_transaction_must_succeed(txn, None).await; let object_id = resp .effects @@ -668,5 +668,5 @@ pub async fn delete_devnet_nft( .call_nft_delete(package_id, nft_to_delete) .build(), ); - context.execute_transaction_must_succeed(txn).await + context.execute_transaction_must_succeed(txn, None).await } diff --git a/crates/iota/src/client_commands.rs b/crates/iota/src/client_commands.rs index 0a461867f68..69061de260e 100644 --- a/crates/iota/src/client_commands.rs +++ b/crates/iota/src/client_commands.rs @@ -22,10 +22,9 @@ use fastcrypto::{ use iota_execution::verifier::VerifierOverrides; use iota_json::IotaJsonValue; use iota_json_rpc_types::{ - Coin, DynamicFieldPage, IotaCoinMetadata, IotaData, IotaExecutionStatus, IotaObjectData, - IotaObjectDataOptions, IotaObjectResponse, IotaObjectResponseQuery, IotaParsedData, - IotaRawData, IotaTransactionBlockEffectsAPI, IotaTransactionBlockResponse, - IotaTransactionBlockResponseOptions, + Coin, DynamicFieldPage, IotaCoinMetadata, IotaData, IotaObjectData, IotaObjectDataOptions, + IotaObjectResponse, IotaObjectResponseQuery, IotaParsedData, IotaRawData, + IotaTransactionBlockResponse, IotaTransactionBlockResponseOptions, }; use iota_keys::keystore::AccountKeystore; use iota_move::build::resolve_lock_file_path; @@ -85,7 +84,7 @@ mod profiler_tests; #[macro_export] macro_rules! serialize_or_execute { - ($tx_data:expr, $serialize_unsigned:expr, $serialize_signed:expr, $context:expr, $result_variant:ident) => {{ + ($tx_data:expr, $serialize_unsigned:expr, $serialize_signed:expr, $context:expr, $result_variant:ident, $opts:expr) => {{ assert!( !$serialize_unsigned || !$serialize_signed, "Cannot specify both --serialize-unsigned-transaction and --serialize-signed-transaction" @@ -107,15 +106,10 @@ macro_rules! serialize_or_execute { IotaClientCommandResult::SerializedSignedTransaction(sender_signed_data) } else { let transaction = Transaction::new(sender_signed_data); - let response = $context.execute_transaction_may_fail(transaction).await?; - let effects = response.effects.as_ref().ok_or_else(|| { - anyhow!("Effects from IotaTransactionBlockResult should not be empty") - })?; - if matches!(effects.status(), IotaExecutionStatus::Failure { .. }) { - return Err(anyhow!( - "Error executing transaction: {:#?}", - effects.status() - )); + let response = $context.execute_transaction_may_fail(transaction, $opts).await?; + let errors: &Vec = response.errors.as_ref(); + if !errors.is_empty() { + return Err(anyhow!("Error executing transaction: {:#?}", errors)); } IotaClientCommandResult::$result_variant(response) } @@ -178,7 +172,6 @@ pub enum IotaClientCommands { #[clap(long, num_args(1..))] args: Vec, /// ID of the gas object for gas payment, in 20 bytes Hex string - #[clap(long)] /// If not provided, a gas object with at least gas_budget value will be /// selected #[clap(long)] @@ -208,6 +201,13 @@ pub enum IotaClientCommands { /// `. #[clap(long, required = false)] serialize_signed_transaction: bool, + + /// Select which fields of the response to display. + /// If not provided, all fields are displayed. + /// The fields are: effects, input, events, object_changes, + /// balance_changes. + #[clap(long, required = false, value_delimiter = ',', num_args = 0.., value_parser = parse_emit_opts)] + emit: Vec, }, /// Query the chain identifier from the rpc endpoint. @@ -863,6 +863,16 @@ pub enum IotaClientCommands { }, } +/// Custom parser for emit options. +fn parse_emit_opts(s: &str) -> Result { + // Validate the input if necessary + // For instance, if you want to restrict to specific fields, add checks here. + match s { + "effects" | "input" | "events" | "object_changes" | "balance_changes" => Ok(s.to_string()), + _ => Err(format!("Invalid option: {}", s)), // Return an error if invalid + } +} + #[derive(serde::Deserialize)] struct FaucetResponse { error: Option, @@ -1099,7 +1109,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - Upgrade + Upgrade, + None ) } IotaClientCommands::Publish { @@ -1155,7 +1166,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - Publish + Publish, + None ) } @@ -1266,6 +1278,7 @@ impl IotaClientCommands { args, serialize_unsigned_transaction, serialize_signed_transaction, + emit, } => { let tx_data = construct_move_call_transaction( package, &module, &function, type_args, gas, gas_budget, gas_price, args, @@ -1277,7 +1290,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - Call + Call, + Some(opts_from_cli(emit)) ) } @@ -1301,7 +1315,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - Transfer + Transfer, + None ) } @@ -1325,7 +1340,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - TransferIota + TransferIota, + None ) } @@ -1370,7 +1386,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - Pay + Pay, + None ) } @@ -1414,7 +1431,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - PayIota + PayIota, + None ) } @@ -1442,7 +1460,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - PayAllIota + PayAllIota, + None ) } @@ -1582,7 +1601,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - SplitCoin + SplitCoin, + None ) } IotaClientCommands::MergeCoin { @@ -1604,7 +1624,8 @@ impl IotaClientCommands { serialize_unsigned_transaction, serialize_signed_transaction, context, - MergeCoin + MergeCoin, + None ) } IotaClientCommands::Switch { address, env } => { @@ -1660,7 +1681,9 @@ impl IotaClientCommands { } let transaction = Transaction::from_generic_sig_data(data, sigs); - let response = context.execute_transaction_may_fail(transaction).await?; + let response = context + .execute_transaction_may_fail(transaction, None) + .await?; IotaClientCommandResult::ExecuteSignedTx(response) } IotaClientCommands::ExecuteCombinedSignedTx { signed_tx_bytes } => { @@ -1671,7 +1694,9 @@ impl IotaClientCommands { .map_err(|_| anyhow!("Invalid Base64 encoding"))? ).map_err(|_| anyhow!("Failed to parse SenderSignedData bytes, check if it matches the output of iota client commands with --serialize-signed-transaction"))?; let transaction = Envelope::::new(data); - let response = context.execute_transaction_may_fail(transaction).await?; + let response = context + .execute_transaction_may_fail(transaction, None) + .await?; IotaClientCommandResult::ExecuteSignedTx(response) } IotaClientCommands::NewEnv { alias, rpc, ws } => { @@ -2676,3 +2701,27 @@ fn format_balance( format!("{whole}.{fractional}{suffix}") } + +fn opts_from_cli(opts: Vec) -> IotaTransactionBlockResponseOptions { + if opts.is_empty() { + return IotaTransactionBlockResponseOptions::new() + .with_effects() + .with_input() + .with_events() + .with_object_changes() + .with_balance_changes(); + } + + let mut options = IotaTransactionBlockResponseOptions::new(); + for opt in opts { + match opt.as_str() { + "input" => options.show_input = true, + "events" => options.show_events = true, + "object_changes" => options.show_object_changes = true, + "balance_changes" => options.show_balance_changes = true, + "effects" => options.show_effects = true, + _ => {} + } + } + options +} diff --git a/crates/iota/src/client_ptb/ptb.rs b/crates/iota/src/client_ptb/ptb.rs index f039a5e6b54..0c9edb7f300 100644 --- a/crates/iota/src/client_ptb/ptb.rs +++ b/crates/iota/src/client_ptb/ptb.rs @@ -168,12 +168,12 @@ impl PTB { ); if program_metadata.serialize_unsigned_set { - serialize_or_execute!(tx_data, true, false, context, PTB).print(true); + serialize_or_execute!(tx_data, true, false, context, PTB, None).print(true); return Ok(()); } if program_metadata.serialize_signed_set { - serialize_or_execute!(tx_data, false, true, context, PTB).print(true); + serialize_or_execute!(tx_data, false, true, context, PTB, None).print(true); return Ok(()); } diff --git a/crates/iota/src/unit_tests/validator_tests.rs b/crates/iota/src/unit_tests/validator_tests.rs index dc0ac36a9dd..08507057323 100644 --- a/crates/iota/src/unit_tests/validator_tests.rs +++ b/crates/iota/src/unit_tests/validator_tests.rs @@ -4,6 +4,7 @@ use anyhow::Ok; use fastcrypto::encoding::{Base64, Encoding}; +use iota_json_rpc_types::IotaTransactionBlockResponseOptions; use iota_types::{ base_types::IotaAddress, crypto::{IotaKeyPair, Signature}, @@ -60,7 +61,7 @@ async fn test_print_raw_rgp_txn() -> Result<(), anyhow::Error> { keypair, ); let txn = Transaction::from_data(data, vec![signature]); - context.execute_transaction_must_succeed(txn).await; + context.execute_transaction_must_succeed(txn, None).await; let (_, summary) = get_validator_summary(&iota_client, validator_address) .await? .unwrap(); diff --git a/crates/iota/tests/cli_tests.rs b/crates/iota/tests/cli_tests.rs index c24ab755557..86b13ec1550 100644 --- a/crates/iota/tests/cli_tests.rs +++ b/crates/iota/tests/cli_tests.rs @@ -31,6 +31,7 @@ use iota_keys::keystore::AccountKeystore; use iota_macros::sim_test; use iota_move_build::{BuildConfig, IotaPackageHooks}; use iota_sdk::{iota_client_config::IotaClientConfig, wallet_context::WalletContext}; +use iota_simulator::tower::balance; use iota_swarm_config::{ genesis_config::{AccountConfig, GenesisConfig, DEFAULT_NUMBER_OF_AUTHORITIES}, network_config::NetworkConfigLight, @@ -313,6 +314,7 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err args: vec![], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -365,6 +367,159 @@ async fn test_ptb_publish_and_complex_arg_resolution() -> Result<(), anyhow::Err Ok(()) } +#[sim_test] +async fn test_call_command_emit_args() -> Result<(), anyhow::Error> { + // Publish the package + move_package::package_hooks::register_package_hooks(Box::new(IotaPackageHooks)); + let mut test_cluster = TestClusterBuilder::new().build().await; + let rgp = test_cluster.get_reference_gas_price().await; + let address = test_cluster.get_address_0(); + let context = &mut test_cluster.wallet; + let client = context.get_client().await?; + let object_refs = client + .read_api() + .get_owned_objects( + address, + Some(IotaObjectResponseQuery::new_with_options( + IotaObjectDataOptions::new() + .with_type() + .with_owner() + .with_previous_transaction(), + )), + None, + None, + ) + .await? + .data; + + let gas_obj_id = object_refs.first().unwrap().object().unwrap().object_id; + + // Provide path to well formed package sources + let mut package_path = PathBuf::from(TEST_DATA_DIR); + package_path.push("simple_mod"); + let build_config = BuildConfig::new_for_testing().config; + let resp = IotaClientCommands::Publish { + package_path: package_path.clone(), + build_config, + gas: Some(gas_obj_id), + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + skip_dependency_verification: false, + with_unpublished_dependencies: false, + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + } + .execute(context) + .await?; + + let IotaClientCommandResult::Publish(response) = resp else { + unreachable!("Invalid response"); + }; + + let IotaTransactionBlockEffects::V1(effects) = response.effects.unwrap(); + + assert!(effects.status.is_ok()); + let package = effects + .created() + .iter() + .find(|refe| matches!(refe.owner, Owner::Immutable)) + .unwrap(); + + let start_call_result = IotaClientCommands::Call { + package: package.reference.object_id, + module: "my_mod".to_string(), + function: "simple_add".to_string(), + type_args: vec![], + gas: None, + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + gas_price: None, + args: vec![IotaJsonValue::new(json!(1))?, IotaJsonValue::new(json!(2))?], + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + emit: vec!["balance_changes".to_string()], + } + .execute(context) + .await?; + + if let Some(tx_block_response) = start_call_result.tx_block_response() { + // Assert Balance Changes are present in the response + assert!(tx_block_response.balance_changes.is_some()); + + // Assert every other field is not present in the response + assert!(tx_block_response.effects.is_none()); + assert!(tx_block_response.object_changes.is_none()); + assert!(tx_block_response.events.is_none()); + assert!(tx_block_response.transaction.is_none()); + } else { + panic!("Transaction block response is None"); + } + + // Make another call, this time with multiple emit args + let start_call_result = IotaClientCommands::Call { + package: package.reference.object_id, + module: "my_mod".to_string(), + function: "simple_add".to_string(), + type_args: vec![], + gas: None, + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + gas_price: None, + args: vec![IotaJsonValue::new(json!(1))?, IotaJsonValue::new(json!(2))?], + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + emit: vec![ + "balance_changes".to_string(), + "effects".to_string(), + "object_changes".to_string(), + ], + } + .execute(context) + .await?; + + start_call_result.print(true); + + // Assert Balance Changes, effects and object changes are present in the + // response + if let Some(tx_block_response) = start_call_result.tx_block_response() { + assert!(tx_block_response.balance_changes.is_some()); + assert!(tx_block_response.effects.is_some()); + assert!(tx_block_response.object_changes.is_some()); + assert!(tx_block_response.events.is_none()); + assert!(tx_block_response.transaction.is_none()); + } else { + panic!("Transaction block response is None"); + } + + // Make another call, this time with no emit args. This should return the full + // response + let start_call_result = IotaClientCommands::Call { + package: package.reference.object_id, + module: "my_mod".to_string(), + function: "simple_add".to_string(), + type_args: vec![], + gas: None, + gas_budget: rgp * TEST_ONLY_GAS_UNIT_FOR_PUBLISH, + gas_price: None, + args: vec![IotaJsonValue::new(json!(1))?, IotaJsonValue::new(json!(2))?], + serialize_unsigned_transaction: false, + serialize_signed_transaction: false, + emit: vec![], + } + .execute(context) + .await?; + + // Assert all fields are present in the response + if let Some(tx_block_response) = start_call_result.tx_block_response() { + assert!(tx_block_response.balance_changes.is_some()); + assert!(tx_block_response.effects.is_some()); + assert!(tx_block_response.object_changes.is_some()); + assert!(tx_block_response.events.is_some()); + assert!(tx_block_response.transaction.is_some()); + } else { + panic!("Transaction block response is None"); + } + + Ok(()) +} + // fixing issue https://github.com/iotaledger/iota/issues/6546 #[tokio::test] async fn test_regression_6546() -> Result<(), anyhow::Error> { @@ -660,6 +815,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: None, serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -700,6 +856,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: None, serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await; @@ -727,6 +884,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: None, serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await; @@ -751,6 +909,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: Some(1), serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await; @@ -784,6 +943,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: None, serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -805,6 +965,7 @@ async fn test_move_call_args_linter_command() -> Result<(), anyhow::Error> { gas_price: Some(12345), serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -962,6 +1123,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { args: vec![], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -985,6 +1147,7 @@ async fn test_delete_shared_object() -> Result<(), anyhow::Error> { args: vec![IotaJsonValue::from_str(&shared_id.to_string()).unwrap()], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1071,6 +1234,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { args: vec![], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1113,6 +1277,7 @@ async fn test_receive_argument() -> Result<(), anyhow::Error> { ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1199,6 +1364,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { args: vec![], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1241,6 +1407,7 @@ async fn test_receive_argument_by_immut_ref() -> Result<(), anyhow::Error> { ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1327,6 +1494,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { args: vec![], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; @@ -1369,6 +1537,7 @@ async fn test_receive_argument_by_mut_ref() -> Result<(), anyhow::Error> { ], serialize_unsigned_transaction: false, serialize_signed_transaction: false, + emit: Vec::new(), } .execute(context) .await?; diff --git a/crates/iota/tests/data/simple_mod/Move.toml b/crates/iota/tests/data/simple_mod/Move.toml new file mode 100644 index 00000000000..f4bbbe32b93 --- /dev/null +++ b/crates/iota/tests/data/simple_mod/Move.toml @@ -0,0 +1,37 @@ +[package] +name = "simple_mod" +edition = "2024.beta" # edition = "legacy" to use legacy (pre-2024) Move +# license = "" # e.g., "MIT", "GPL", "Apache 2.0" +# authors = ["..."] # e.g., ["Joe Smith (joesmith@noemail.com)", "John Snow (johnsnow@noemail.com)"] + +[dependencies] +Iota = { git = "https://github.com/iotaledger/iota.git", subdir = "crates/iota-framework/packages/iota-framework", rev = "framework/testnet" } + +# For remote import, use the `{ git = "...", subdir = "...", rev = "..." }`. +# Revision can be a branch, a tag, and a commit hash. +# MyRemotePackage = { git = "https://some.remote/host.git", subdir = "remote/path", rev = "main" } + +# For local dependencies use `local = path`. Path is relative to the package root +# Local = { local = "../path/to" } + +# To resolve a version conflict and force a specific version for dependency +# override use `override = true` +# Override = { local = "../conflicting/version", override = true } + +[addresses] +simple_mod = "0x0" + +# Named addresses will be accessible in Move as `@name`. They're also exported: +# for example, `std = "0x1"` is exported by the Standard Library. +# alice = "0xA11CE" + +[dev-dependencies] +# The dev-dependencies section allows overriding dependencies for `--test` and +# `--dev` modes. You can introduce test-only dependencies here. +# Local = { local = "../path/to/dev-build" } + +[dev-addresses] +# The dev-addresses section allows overwriting named addresses for the `--test` +# and `--dev` modes. +# alice = "0xB0B" + diff --git a/crates/iota/tests/data/simple_mod/sources/simple_mod.move b/crates/iota/tests/data/simple_mod/sources/simple_mod.move new file mode 100644 index 00000000000..2b05780b55c --- /dev/null +++ b/crates/iota/tests/data/simple_mod/sources/simple_mod.move @@ -0,0 +1,5 @@ +module simple_mod::my_mod { + public fun simple_add(a: u64, b: u64): u64 { + a + b + } +} \ No newline at end of file diff --git a/crates/test-cluster/src/lib.rs b/crates/test-cluster/src/lib.rs index 10905559749..022b2b13097 100644 --- a/crates/test-cluster/src/lib.rs +++ b/crates/test-cluster/src/lib.rs @@ -562,7 +562,7 @@ impl TestCluster { /// ExecutionStatus::Success. This function is recommended for /// transaction execution since it most resembles the production path. pub async fn execute_transaction(&self, tx: Transaction) -> IotaTransactionBlockResponse { - self.wallet.execute_transaction_must_succeed(tx).await + self.wallet.execute_transaction_must_succeed(tx, None).await } /// Different from `execute_transaction` which returns RPC effects types, @@ -582,7 +582,10 @@ impl TestCluster { let results = self .submit_transaction_to_validators(tx.clone(), &self.get_validator_pubkeys()) .await?; - self.wallet.execute_transaction_may_fail(tx).await.unwrap(); + self.wallet + .execute_transaction_may_fail(tx, None) + .await + .unwrap(); Ok(results) } @@ -677,7 +680,7 @@ impl TestCluster { .transfer_iota(amount, funding_address) .build(), ); - context.execute_transaction_must_succeed(tx).await; + context.execute_transaction_must_succeed(tx, None).await; context .get_one_gas_object_owned_by_address(funding_address)