diff --git a/apps/explorer/tests/search.spec.ts b/apps/explorer/tests/search.spec.ts index 1e3895b906d21..0957079a8698f 100644 --- a/apps/explorer/tests/search.spec.ts +++ b/apps/explorer/tests/search.spec.ts @@ -32,7 +32,7 @@ test('can search for transaction', async ({ page }) => { const address = await faucet(); const tx = await mint(address); - const txid = tx.certificate.transactionDigest; + const txid = tx.effects.effects.transactionDigest; await page.goto('/'); await search(page, txid); await expect(page).toHaveURL(`/transaction/${txid}`); diff --git a/apps/explorer/tests/transaction.spec.ts b/apps/explorer/tests/transaction.spec.ts index 7fe7ea27aefb6..cbe7b36f0f255 100644 --- a/apps/explorer/tests/transaction.spec.ts +++ b/apps/explorer/tests/transaction.spec.ts @@ -7,7 +7,7 @@ import { faucet, mint } from './utils/localnet'; test('displays the transaction timestamp', async ({ page }) => { const address = await faucet(); const tx = await mint(address); - const txid = tx.certificate.transactionDigest; + const txid = tx.effects.effects.transactionDigest; await page.goto(`/transaction/${txid}`); await expect( page.getByTestId('transaction-timestamp').locator('div').nth(1) @@ -17,7 +17,7 @@ test('displays the transaction timestamp', async ({ page }) => { test('displays gas breakdown', async ({ page }) => { const address = await faucet(); const tx = await mint(address); - const txid = tx.certificate.transactionDigest; + const txid = tx.effects.effects.transactionDigest; await page.goto(`/transaction/${txid}`); await expect(page.getByTestId('gas-breakdown')).toBeVisible(); }); diff --git a/crates/sui-core/src/transaction_orchestrator.rs b/crates/sui-core/src/transaction_orchestrator.rs index 76f9db2fc997e..58ff20227933a 100644 --- a/crates/sui-core/src/transaction_orchestrator.rs +++ b/crates/sui-core/src/transaction_orchestrator.rs @@ -192,7 +192,7 @@ where } = response; if !wait_for_local_execution { return Ok(ExecuteTransactionResponse::EffectsCert(Box::new(( - tx_cert.into(), + Some(tx_cert.into()), effects_cert.into(), false, )))); @@ -206,12 +206,12 @@ where .await { Ok(_) => Ok(ExecuteTransactionResponse::EffectsCert(Box::new(( - tx_cert.into(), + Some(tx_cert.into()), effects_cert.into(), true, )))), Err(_) => Ok(ExecuteTransactionResponse::EffectsCert(Box::new(( - tx_cert.into(), + Some(tx_cert.into()), effects_cert.into(), false, )))), diff --git a/crates/sui-json-rpc-types/src/lib.rs b/crates/sui-json-rpc-types/src/lib.rs index 660d1fea9c4a6..7292567b7b591 100644 --- a/crates/sui-json-rpc-types/src/lib.rs +++ b/crates/sui-json-rpc-types/src/lib.rs @@ -413,7 +413,9 @@ pub struct SuiTBlsSignRandomnessObjectResponse { #[allow(clippy::large_enum_variant)] #[derive(Serialize, Deserialize, Debug, JsonSchema)] pub struct SuiExecuteTransactionResponse { - pub certificate: SuiCertifiedTransaction, + // If this transaction was already finalized previously, there is no guarantee that a + // certificate is still available. + pub certificate: Option, pub effects: SuiCertifiedTransactionEffects, // If the transaction is confirmed to be executed locally // before this response. @@ -428,7 +430,10 @@ impl SuiExecuteTransactionResponse { Ok(match resp { ExecuteTransactionResponse::EffectsCert(cert) => { let (certificate, effects, is_executed_locally) = *cert; - let certificate: SuiCertifiedTransaction = certificate.try_into()?; + let certificate: Option = match certificate { + Some(c) => Some(c.try_into()?), + None => None, + }; let effects: SuiCertifiedTransactionEffects = SuiCertifiedTransactionEffects::try_from(effects, resolver)?; SuiExecuteTransactionResponse { diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index e12b8dda7edfd..029e3eaf146cc 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -5298,13 +5298,19 @@ "SuiExecuteTransactionResponse": { "type": "object", "required": [ - "certificate", "confirmed_local_execution", "effects" ], "properties": { "certificate": { - "$ref": "#/components/schemas/CertifiedTransaction" + "anyOf": [ + { + "$ref": "#/components/schemas/CertifiedTransaction" + }, + { + "type": "null" + } + ] }, "confirmed_local_execution": { "type": "boolean" diff --git a/crates/sui-sdk/src/apis.rs b/crates/sui-sdk/src/apis.rs index 55fd6cf2830b5..c1113e3eb5705 100644 --- a/crates/sui-sdk/src/apis.rs +++ b/crates/sui-sdk/src/apis.rs @@ -478,6 +478,7 @@ impl QuorumDriver { tx: VerifiedTransaction, request_type: Option, ) -> SuiRpcResult { + let tx_digest = *tx.digest(); let (tx_bytes, signature) = tx.to_tx_bytes_and_signature(); let request_type = request_type.unwrap_or(ExecuteTransactionRequestType::WaitForLocalExecution); @@ -495,8 +496,8 @@ impl QuorumDriver { Ok(match request_type { ExecuteTransactionRequestType::WaitForEffectsCert => TransactionExecutionResult { - tx_digest: certificate.transaction_digest, - tx_cert: Some(certificate), + tx_digest, + tx_cert: certificate, effects: Some(effects.effects), confirmed_local_execution, timestamp_ms: None, @@ -504,12 +505,11 @@ impl QuorumDriver { }, ExecuteTransactionRequestType::WaitForLocalExecution => { if !confirmed_local_execution { - Self::wait_until_fullnode_sees_tx(&self.api, certificate.transaction_digest) - .await?; + Self::wait_until_fullnode_sees_tx(&self.api, tx_digest).await?; } TransactionExecutionResult { - tx_digest: certificate.transaction_digest, - tx_cert: Some(certificate), + tx_digest, + tx_cert: certificate, effects: Some(effects.effects), confirmed_local_execution, timestamp_ms: None, diff --git a/crates/sui-types/src/messages.rs b/crates/sui-types/src/messages.rs index 3e5be81246d9b..e67058a4425c5 100644 --- a/crates/sui-types/src/messages.rs +++ b/crates/sui-types/src/messages.rs @@ -2427,7 +2427,7 @@ pub type IsTransactionExecutedLocally = bool; pub enum ExecuteTransactionResponse { EffectsCert( Box<( - CertifiedTransaction, + Option, CertifiedTransactionEffects, IsTransactionExecutedLocally, )>, diff --git a/crates/sui/tests/full_node_tests.rs b/crates/sui/tests/full_node_tests.rs index ef55c22c1aa10..225cc040193d1 100644 --- a/crates/sui/tests/full_node_tests.rs +++ b/crates/sui/tests/full_node_tests.rs @@ -955,7 +955,7 @@ async fn test_full_node_transaction_orchestrator_basic() -> Result<(), anyhow::E effects_cert: certified_txn_effects, } = rx.recv().await.unwrap().unwrap(); let (ct, cte, is_executed_locally) = *res; - assert_eq!(*ct.digest(), digest); + assert_eq!(*ct.unwrap().digest(), digest); assert_eq!(*certified_txn.digest(), digest); assert_eq!(*cte.digest(), *certified_txn_effects.digest()); assert!(is_executed_locally); @@ -980,7 +980,7 @@ async fn test_full_node_transaction_orchestrator_basic() -> Result<(), anyhow::E effects_cert: certified_txn_effects, } = rx.recv().await.unwrap().unwrap(); let (ct, cte, is_executed_locally) = *res; - assert_eq!(*ct.digest(), digest); + assert_eq!(*ct.unwrap().digest(), digest); assert_eq!(*certified_txn.digest(), digest); assert_eq!(*cte.digest(), *certified_txn_effects.digest()); assert!(!is_executed_locally); @@ -1037,11 +1037,11 @@ async fn test_execute_tx_with_serialized_signature() -> Result<(), anyhow::Error .unwrap(); let SuiExecuteTransactionResponse { - certificate, - effects: _, + certificate: _, + effects, confirmed_local_execution, } = response; - assert_eq!(&certificate.transaction_digest, tx_digest); + assert_eq!(&effects.effects.transaction_digest, tx_digest); assert!(confirmed_local_execution); } Ok(()) @@ -1077,11 +1077,11 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: .unwrap(); let SuiExecuteTransactionResponse { - certificate, - effects: _, + certificate: _, + effects, confirmed_local_execution, } = response; - assert_eq!(&certificate.transaction_digest, tx_digest); + assert_eq!(&effects.effects.transaction_digest, tx_digest); assert!(confirmed_local_execution); let _response: SuiTransactionResponse = jsonrpc_client @@ -1102,11 +1102,11 @@ async fn test_full_node_transaction_orchestrator_rpc_ok() -> Result<(), anyhow:: .unwrap(); let SuiExecuteTransactionResponse { - certificate, - effects: _, + certificate: _, + effects, confirmed_local_execution, } = response; - assert_eq!(&certificate.transaction_digest, tx_digest); + assert_eq!(&effects.effects.transaction_digest, tx_digest); assert!(!confirmed_local_execution); Ok(()) diff --git a/crates/sui/tests/transaction_orchestrator_tests.rs b/crates/sui/tests/transaction_orchestrator_tests.rs index cd40b7133944a..44c2bd4b1b7a7 100644 --- a/crates/sui/tests/transaction_orchestrator_tests.rs +++ b/crates/sui/tests/transaction_orchestrator_tests.rs @@ -7,7 +7,7 @@ use sui_core::transaction_orchestrator::TransactiondOrchestrator; use sui_macros::sim_test; use sui_types::crypto::{get_key_pair, AccountKeyPair}; use sui_types::messages::{ - CertifiedTransaction, ExecuteTransactionRequest, ExecuteTransactionRequestType, + CertifiedTransactionEffects, ExecuteTransactionRequest, ExecuteTransactionRequestType, ExecuteTransactionResponse, TransactionData, VerifiedTransaction, }; use sui_types::object::generate_test_gas_objects_with_owner; @@ -206,7 +206,7 @@ async fn test_tx_across_epoch_boundaries() { let (sender, keypair) = get_key_pair::(); let gas_objects = generate_test_gas_objects_with_owner(1, sender); let (result_tx, mut result_rx) = - tokio::sync::mpsc::channel::(total_tx_cnt); + tokio::sync::mpsc::channel::(total_tx_cnt); let (config, mut gas_objects) = test_authority_configs_with_objects(gas_objects); let authorities = spawn_test_authorities([], &config).await; @@ -247,8 +247,8 @@ async fn test_tx_across_epoch_boundaries() { { Ok(ExecuteTransactionResponse::EffectsCert(res)) => { info!(?tx_digest, "tx result: ok"); - let (tx_cert, _, _) = *res; - result_tx.send(tx_cert).await.unwrap(); + let (_, effects_cert, _) = *res; + result_tx.send(effects_cert).await.unwrap(); } Err(QuorumDriverError::TimeoutBeforeFinality) => { info!(?tx_digest, "tx result: timeout and will retry") @@ -277,7 +277,7 @@ async fn test_tx_across_epoch_boundaries() { // The transaction must finalize in epoch 1 let start = std::time::Instant::now(); match tokio::time::timeout(tokio::time::Duration::from_secs(15), result_rx.recv()).await { - Ok(Some(tx_cert)) if tx_cert.auth_sig().epoch == 1 => (), + Ok(Some(effects_cert)) if effects_cert.epoch() == 1 => (), other => panic!("unexpected error: {:?}", other), } info!("test completed in {:?}", start.elapsed()); diff --git a/sdk/typescript/src/types/transactions.ts b/sdk/typescript/src/types/transactions.ts index acde15ff3f27e..d9382ecd01a1b 100644 --- a/sdk/typescript/src/types/transactions.ts +++ b/sdk/typescript/src/types/transactions.ts @@ -238,7 +238,7 @@ export const SuiExecuteTransactionResponse = union([ }), }), object({ - certificate: CertifiedTransaction, + certificate: optional(CertifiedTransaction), effects: SuiCertifiedTransactionEffects, confirmed_local_execution: boolean(), }),