From ab0763bffdc2bb3b61395834aac8ac60c2d5ded8 Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Wed, 23 Aug 2023 15:30:16 +0100 Subject: [PATCH] Handle restorePreamble in cli prepare_and_send helper --- cmd/soroban-cli/src/rpc/mod.rs | 58 +++++++++++++++++++------- cmd/soroban-cli/src/rpc/transaction.rs | 23 ++++++++++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/cmd/soroban-cli/src/rpc/mod.rs b/cmd/soroban-cli/src/rpc/mod.rs index e817b2a38b..21f03cf28d 100644 --- a/cmd/soroban-cli/src/rpc/mod.rs +++ b/cmd/soroban-cli/src/rpc/mod.rs @@ -24,7 +24,7 @@ use tokio::time::sleep; use crate::utils::{self, contract_spec}; mod transaction; -use transaction::{assemble, sign_soroban_authorizations}; +use transaction::{assemble, build_restore_txn, sign_soroban_authorizations}; const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION"); @@ -201,7 +201,18 @@ pub struct SimulateHostFunctionResult { pub xdr: String, } -#[derive(serde::Deserialize, serde::Serialize, Debug, Default)] +#[derive(serde::Deserialize, serde::Serialize, Debug)] +pub struct SimulateTransactionResponseRestorePreamble { + #[serde(rename = "transactionData")] + pub transaction_data: String, + #[serde( + rename = "minResourceFee", + deserialize_with = "deserialize_number_from_string" + )] + pub min_resource_fee: u32, +} + +#[derive(serde::Deserialize, serde::Serialize, Debug)] pub struct SimulateTransactionResponse { #[serde( rename = "minResourceFee", @@ -231,7 +242,9 @@ pub struct SimulateTransactionResponse { rename = "latestLedger", deserialize_with = "deserialize_number_from_string" )] - pub latest_ledger: u64, + pub latest_ledger: u32, + #[serde(rename = "restorePreamble")] + restore_preamble: Option, #[serde(skip_serializing_if = "Option::is_none", default)] pub error: Option, } @@ -626,7 +639,13 @@ soroban config identity fund {address} --helper-url "# pub async fn prepare_transaction( &self, tx: &Transaction, - ) -> Result<(Transaction, Vec), Error> { + ) -> Result< + ( + Transaction, + Option, + ), + Error, + > { tracing::trace!(?tx); let sim_response = self .simulate_transaction(&TransactionEnvelope::Tx(TransactionV1Envelope { @@ -634,14 +653,10 @@ soroban config identity fund {address} --helper-url "# signatures: VecM::default(), })) .await?; - - let events = sim_response - .events - .iter() - .map(DiagnosticEvent::from_xdr_base64) - .collect::, _>>()?; - - Ok((assemble(tx, &sim_response)?, events)) + Ok(( + assemble(tx, &sim_response, log_events)?, + sim_response.restore_preamble, + )) } pub async fn prepare_and_send_transaction( @@ -654,7 +669,20 @@ soroban config identity fund {address} --helper-url "# log_resources: Option, ) -> Result<(TransactionResult, TransactionMeta, Vec), Error> { let GetLatestLedgerResponse { sequence, .. } = self.get_latest_ledger().await?; - let (unsigned_tx, events) = self.prepare_transaction(tx_without_preflight).await?; + let (mut unsigned_tx, restore_preamble) = self + .prepare_transaction(tx_without_preflight, log_events) + .await?; + if let Some(restore) = restore_preamble { + // Build and submit the restore transaction + self.send_transaction(&utils::sign_transaction( + source_key, + &build_restore_txn(&unsigned_tx, &restore)?, + network_passphrase, + )?) + .await?; + // Increment the original txn's seq_num so it doesn't conflict + unsigned_tx.seq_num = SequenceNumber(unsigned_tx.seq_num.0 + 1); + } let (part_signed_tx, signed_auth_entries) = sign_soroban_authorizations( &unsigned_tx, source_key, @@ -671,7 +699,9 @@ soroban config identity fund {address} --helper-url "# (part_signed_tx, events) } else { // re-simulate to calculate the new fees - self.prepare_transaction(&part_signed_tx).await? + self.prepare_transaction(&part_signed_tx, log_events) + .await? + .0 }; // Try logging stuff if requested diff --git a/cmd/soroban-cli/src/rpc/transaction.rs b/cmd/soroban-cli/src/rpc/transaction.rs index 551013ba65..5793d51188 100644 --- a/cmd/soroban-cli/src/rpc/transaction.rs +++ b/cmd/soroban-cli/src/rpc/transaction.rs @@ -213,6 +213,29 @@ pub fn sign_soroban_authorization_entry( Ok(auth) } +pub fn build_restore_txn( + parent: &Transaction, + restore: &SimulateTransactionResponseRestorePreamble, +) -> Result { + let transaction_data = SorobanTransactionData::from_xdr_base64(restore.transaction_data)?; + Ok(Transaction { + source_account: parent.source_account.clone(), + fee: parent.fee + restore.min_resource_fee, + seq_num: parent.seq_num, + cond: Preconditions::None, + memo: Memo::None, + operations: vec![Operation { + source_account: None, + body: OperationBody::RestoreFootprint(RestoreFootprintOp { + ext: ExtensionPoint::V0, + }), + }] + .try_into() + .unwrap(), + ext: TransactionExt::V1(transaction_data), + }) +} + #[cfg(test)] mod tests { use super::*;