From 833230f8a53502e4f4b302af1918c3ced78b9fb9 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Wed, 25 Oct 2023 15:33:40 -0400 Subject: [PATCH] fix: assembly transaction after authorizing & improve txn error output --- cmd/soroban-cli/src/rpc/mod.rs | 73 ++++++++++++++++++++++++---------- cmd/soroban-cli/src/rpc/txn.rs | 5 +-- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/cmd/soroban-cli/src/rpc/mod.rs b/cmd/soroban-cli/src/rpc/mod.rs index 0e44ebc2cd..b1b8a3659a 100644 --- a/cmd/soroban-cli/src/rpc/mod.rs +++ b/cmd/soroban-cli/src/rpc/mod.rs @@ -124,7 +124,7 @@ pub struct SendTransactionResponse { } #[derive(serde::Deserialize, serde::Serialize, Debug)] -pub struct GetTransactionResponse { +pub struct GetTransactionResponseRaw { pub status: String, #[serde( rename = "envelopeXdr", @@ -143,6 +143,33 @@ pub struct GetTransactionResponse { // TODO: add ledger info and application order } +#[derive(serde::Deserialize, serde::Serialize, Debug)] +pub struct GetTransactionResponse { + pub status: String, + pub envelope: Option, + pub result: Option, + pub result_meta: Option, +} + +impl TryInto for GetTransactionResponseRaw { + type Error = xdr::Error; + + fn try_into(self) -> Result { + Ok(GetTransactionResponse { + status: self.status, + envelope: self + .envelope_xdr + .map(ReadXdr::from_xdr_base64) + .transpose()?, + result: self.result_xdr.map(ReadXdr::from_xdr_base64).transpose()?, + result_meta: self + .result_meta_xdr + .map(ReadXdr::from_xdr_base64) + .transpose()?, + }) + } +} + #[derive(serde::Deserialize, serde::Serialize, Debug)] pub struct LedgerEntryResult { pub key: String, @@ -601,7 +628,7 @@ soroban config identity fund {address} --helper-url "# tx: &TransactionEnvelope, ) -> Result<(TransactionResult, TransactionMeta, Vec), Error> { let client = self.client()?; - tracing::trace!(?tx); + tracing::trace!("Sending:\n{tx:#?}"); let SendTransactionResponse { hash, error_result_xdr, @@ -610,7 +637,9 @@ soroban config identity fund {address} --helper-url "# } = client .request("sendTransaction", rpc_params![tx.to_xdr_base64()?]) .await - .map_err(|err| Error::TransactionSubmissionFailed(format!("{err:#?}")))?; + .map_err(|err| { + Error::TransactionSubmissionFailed(format!("No status yet:\n {err:#?}")) + })?; if status == "ERROR" { let error = error_result_xdr @@ -623,7 +652,7 @@ soroban config identity fund {address} --helper-url "# .map_err(|_| Error::InvalidResponse) }) .map(|r| r.result); - tracing::error!(?error); + tracing::error!("TXN failed:\n {error:#?}"); return Err(Error::TransactionSubmissionFailed(format!("{:#?}", error?))); } // even if status == "success" we need to query the transaction status in order to get the result @@ -631,27 +660,27 @@ soroban config identity fund {address} --helper-url "# // Poll the transaction status let start = Instant::now(); loop { - let response = self.get_transaction(&hash).await?; + let response: GetTransactionResponse = self.get_transaction(&hash).await?.try_into()?; match response.status.as_str() { "SUCCESS" => { // TODO: the caller should probably be printing this - tracing::trace!(?response); - let result = TransactionResult::from_xdr_base64( - response.result_xdr.clone().ok_or(Error::MissingResult)?, - )?; - let meta = TransactionMeta::from_xdr_base64( - response - .result_meta_xdr - .clone() - .ok_or(Error::MissingResult)?, - )?; + tracing::trace!("{response:#?}"); + let GetTransactionResponse { + result, + result_meta, + .. + } = response; + let meta = result_meta.ok_or(Error::MissingResult)?; let events = extract_events(&meta); - return Ok((result, meta, events)); + return Ok((result.ok_or(Error::MissingResult)?, meta, events)); } "FAILED" => { - tracing::error!(?response); + tracing::error!("{response:#?}"); // TODO: provide a more elaborate error - return Err(Error::TransactionSubmissionFailed(format!("{response:#?}"))); + return Err(Error::TransactionSubmissionFailed(format!( + "{:#?}", + response.result + ))); } "NOT_FOUND" => (), _ => { @@ -671,13 +700,13 @@ soroban config identity fund {address} --helper-url "# &self, tx: &TransactionEnvelope, ) -> Result { - tracing::trace!(?tx); + tracing::trace!("Simulating:\n{tx:#?}"); let base64_tx = tx.to_xdr_base64()?; let response: SimulateTransactionResponse = self .client()? .request("simulateTransaction", rpc_params![base64_tx]) .await?; - tracing::trace!(?response); + tracing::trace!("Simulation response:\n {response:#?}"); match response.error { None => Ok(response), Some(e) => { @@ -698,7 +727,7 @@ soroban config identity fund {address} --helper-url "# ) -> Result<(TransactionResult, TransactionMeta, Vec), Error> { let raw = txn::Handler::new(tx_without_preflight.clone()); let simulation = raw.simulate(self).await?; - let seq_num = simulation.latest_ledger; + let seq_num = simulation.latest_ledger + 60; //5 min; let authorized = raw .handle_restore(self, &simulation, source_key, network_passphrase) .await? @@ -710,7 +739,7 @@ soroban config identity fund {address} --helper-url "# self.send_transaction(&tx).await } - pub async fn get_transaction(&self, tx_id: &str) -> Result { + pub async fn get_transaction(&self, tx_id: &str) -> Result { Ok(self .client()? .request("getTransaction", rpc_params![tx_id]) diff --git a/cmd/soroban-cli/src/rpc/txn.rs b/cmd/soroban-cli/src/rpc/txn.rs index 283f2b3c52..3f60cb5111 100644 --- a/cmd/soroban-cli/src/rpc/txn.rs +++ b/cmd/soroban-cli/src/rpc/txn.rs @@ -139,11 +139,10 @@ impl Handler { network_passphrase, )?, state: State::Raw, - } - .bump_seq_num(); + }; let sim = txn.simulate(client).await?; Ok(Self { - txn: txn.txn, + txn: assemble(&txn.txn, &sim)?, state: State::Authorized(sim), }) }