Skip to content

Commit

Permalink
feat: TxnResult for returning result or base64 xdr
Browse files Browse the repository at this point in the history
  • Loading branch information
willemneal authored and gitbutler-client committed Mar 28, 2024
1 parent 4716bec commit 5f7a6e7
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 37 deletions.
10 changes: 7 additions & 3 deletions cmd/soroban-cli/src/commands/contract/deploy/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl NetworkRunnable for Cmd {
&self,
_: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<String, Error> {
) -> Result<TxnResult<String>, Error> {
let config = config.unwrap_or(&self.config);
// Parse asset
let asset = parse_asset(&self.asset)?;
Expand Down Expand Up @@ -101,14 +101,18 @@ impl NetworkRunnable for Cmd {
network_passphrase,
&key,
)?;
self.fee.exit_if_build_only(&tx)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&tx)?);
}
let txn = client.create_assembled_transaction(&tx).await?;
let txn = self.fee.apply_to_assembled_txn(txn)?;
client
.send_assembled_transaction(txn, &key, &[], network_passphrase, None, None)
.await?;

Ok(stellar_strkey::Contract(contract_id.0).to_string())
Ok(TxnResult::Xdr(
stellar_strkey::Contract(contract_id.0).to_string(),
))
}
}

Expand Down
13 changes: 9 additions & 4 deletions cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl NetworkRunnable for Cmd {
&self,
global_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<String, Error> {
) -> Result<TxnResult<String>, Error> {
let config = config.unwrap_or(&self.config);
let wasm_hash = if let Some(wasm) = &self.wasm {
let mut fee = self.fee.clone();
Expand All @@ -123,7 +123,7 @@ impl NetworkRunnable for Cmd {
}
.run_against_rpc_server(global_args, Some(config))
.await?;
hex::encode(hash)
hex::encode(hash.try_res()?)
} else {
self.wasm_hash
.as_ref()
Expand Down Expand Up @@ -166,13 +166,18 @@ impl NetworkRunnable for Cmd {
salt,
&key,
)?;
self.fee.exit_if_build_only(&txn)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&txn)?);
}

let txn = client.create_assembled_transaction(&txn).await?;
let txn = self.fee.apply_to_assembled_txn(txn)?;
client
.send_assembled_transaction(txn, &key, &[], &network.network_passphrase, None, None)
.await?;
Ok(stellar_strkey::Contract(contract_id.0).to_string())
Ok(TxnResult::Res(
stellar_strkey::Contract(contract_id.0).to_string(),
))
}
}

Expand Down
8 changes: 5 additions & 3 deletions cmd/soroban-cli/src/commands/contract/extend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl NetworkRunnable for Cmd {
&self,
_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<u32, Self::Error> {
) -> Result<TxnResult<u32>, Self::Error> {
let config = config.unwrap_or(&self.config);
let network = config.get_network()?;
tracing::trace!(?network);
Expand Down Expand Up @@ -154,7 +154,9 @@ impl NetworkRunnable for Cmd {
resource_fee: 0,
}),
};
self.fee.exit_if_build_only(&tx)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&tx)?);
}
let res = client
.prepare_and_send_transaction(&tx, &key, &[], &network.network_passphrase, None, None)
.await?;
Expand Down Expand Up @@ -199,7 +201,7 @@ impl NetworkRunnable for Cmd {
}),
..
}),
) => Ok(*live_until_ledger_seq),
) => Ok(TxnResult::Res(*live_until_ledger_seq)),
_ => Err(Error::LedgerEntryNotFound),
}
}
Expand Down
6 changes: 4 additions & 2 deletions cmd/soroban-cli/src/commands/contract/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ impl NetworkRunnable for Cmd {
let (tx_without_preflight, hash) =
build_install_contract_code_tx(&contract, sequence + 1, self.fee.fee, &key)?;

self.fee.exit_if_build_only(&tx_without_preflight)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&tx_without_preflight)?);
}
let code_key =
xdr::LedgerKey::ContractCode(xdr::LedgerKeyContractCode { hash: hash.clone() });
let contract_data = client.get_ledger_entries(&[code_key]).await?;
if !contract_data.entries.unwrap_or_default().is_empty() {
return Ok(hash);
return Ok(TxnResult::Res(hash));
}
let txn = client
.create_assembled_transaction(&tx_without_preflight)
Expand Down
11 changes: 7 additions & 4 deletions cmd/soroban-cli/src/commands/contract/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use super::super::{
config::{self, locator},
events,
};
use crate::commands::txn_result::TxnResult;
use crate::commands::NetworkRunnable;
use crate::{commands::global, rpc, Pwd};
use soroban_spec_tools::{contract, Spec};
Expand Down Expand Up @@ -258,12 +259,12 @@ impl Cmd {
}

pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
let res = self.invoke(global_args).await?;
let res = self.invoke(global_args).await?;
println!("{res}");
Ok(())
}

pub async fn invoke(&self, global_args: &global::Args) -> Result<String, Error> {
pub async fn invoke(&self, global_args: &global::Args) -> Result<TxnResult<String>, Error> {
self.run_against_rpc_server(Some(global_args), None).await
}

Expand Down Expand Up @@ -300,7 +301,7 @@ impl NetworkRunnable for Cmd {
&self,
global_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<String, Error> {
) -> Result<TxnResult<String>, Error> {
let config = config.unwrap_or(&self.config);
let network = config.get_network()?;
tracing::trace!(?network);
Expand Down Expand Up @@ -334,7 +335,9 @@ impl NetworkRunnable for Cmd {
self.fee.fee,
&key,
)?;
self.fee.exit_if_build_only(&tx)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&tx)?);
}
let txn = client.create_assembled_transaction(&tx).await?;
let txn = self.fee.apply_to_assembled_txn(txn)?;
let (return_value, events) = if self.is_view() {
Expand Down
14 changes: 10 additions & 4 deletions cmd/soroban-cli/src/commands/contract/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use soroban_env_host::{
use soroban_sdk::xdr::Limits;

use crate::{
commands::{config, global, NetworkRunnable},
commands::{config, global, txn_result::TxnResult, NetworkRunnable},
key,
rpc::{self, Client, FullLedgerEntries, FullLedgerEntry},
};
Expand Down Expand Up @@ -91,7 +91,13 @@ pub enum Error {

impl Cmd {
pub async fn run(&self) -> Result<(), Error> {
let entries = self.run_against_rpc_server(None, None).await?;
let entries = match self.run_against_rpc_server(None, None).await? {
TxnResult::Res(res) => res,
TxnResult::Xdr(xdr) => {
println!("{xdr}");
return Ok(());
}
};
self.output_entries(&entries)
}

Expand Down Expand Up @@ -178,12 +184,12 @@ impl NetworkRunnable for Cmd {
&self,
_: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<FullLedgerEntries, Error> {
) -> Result<TxnResult<FullLedgerEntries>, Error> {
let config = config.unwrap_or(&self.config);
let network = config.get_network()?;
tracing::trace!(?network);
let client = Client::new(&network.rpc_url)?;
let keys = self.key.parse_keys()?;
Ok(client.get_full_ledger_entries(&keys).await?)
Ok(TxnResult::Res(client.get_full_ledger_entries(&keys).await?))
}
}
26 changes: 20 additions & 6 deletions cmd/soroban-cli/src/commands/contract/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use crate::{
commands::{
config::{self, locator},
contract::extend,
global, NetworkRunnable,
global,
txn_result::{self, TxnResult},
NetworkRunnable,
},
key,
rpc::{self, Client},
Expand Down Expand Up @@ -83,13 +85,21 @@ pub enum Error {
Key(#[from] key::Error),
#[error(transparent)]
Extend(#[from] extend::Error),

#[error(transparent)]
TxnResult(#[from] txn_result::Error),
}

impl Cmd {
#[allow(clippy::too_many_lines)]
pub async fn run(&self) -> Result<(), Error> {
let expiration_ledger_seq = self.run_against_rpc_server(None, None).await?;

let expiration_ledger_seq = match self.run_against_rpc_server(None, None).await? {
TxnResult::Res(res) => res,
TxnResult::Xdr(xdr) => {
println!("{xdr}");
return Ok(());
}
};
if let Some(ledgers_to_extend) = self.ledgers_to_extend {
extend::Cmd {
key: self.key.clone(),
Expand Down Expand Up @@ -117,7 +127,7 @@ impl NetworkRunnable for Cmd {
&self,
_: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<u32, Error> {
) -> Result<TxnResult<u32>, Error> {
let config = config.unwrap_or(&self.config);
let network = config.get_network()?;
tracing::trace!(?network);
Expand Down Expand Up @@ -158,7 +168,9 @@ impl NetworkRunnable for Cmd {
resource_fee: 0,
}),
};
self.fee.exit_if_build_only(&tx)?;
if self.fee.build_only {
return Ok(TxnResult::from_xdr(&tx)?);
}
let res = client
.prepare_and_send_transaction(&tx, &key, &[], &network.network_passphrase, None, None)
.await?;
Expand Down Expand Up @@ -192,7 +204,9 @@ impl NetworkRunnable for Cmd {
operations[0].changes.len()
);
}
parse_operations(operations).ok_or(Error::MissingOperationResult)
Ok(TxnResult::Res(
parse_operations(operations).ok_or(Error::MissingOperationResult)?,
))
}
}

Expand Down
7 changes: 5 additions & 2 deletions cmd/soroban-cli/src/commands/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub enum Error {
Locator(#[from] locator::Error),
#[error(transparent)]
Config(#[from] config::Error),
#[error(transparent)]
TxnResult(#[from] super::txn_result::Error),
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum)]
Expand Down Expand Up @@ -167,7 +169,8 @@ impl Cmd {
})?;
}

let response = self.run_against_rpc_server(None, None).await?;
let txn_res = self.run_against_rpc_server(None, None).await?;
let response = txn_res.try_res()?;

for event in &response.events {
match self.output {
Expand Down Expand Up @@ -214,7 +217,7 @@ impl NetworkRunnable for Cmd {
&self,
_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<rpc::GetEventsResponse, Error> {
) -> Result<TxnResult<rpc::GetEventsResponse>, Error> {
let start = self.start()?;
let network = if let Some(config) = config {
Ok(config.get_network()?)
Expand Down
4 changes: 3 additions & 1 deletion cmd/soroban-cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub mod network;
pub mod plugin;
pub mod version;

pub mod txn_result;

pub const HEADING_RPC: &str = "Options (RPC)";
const ABOUT: &str = "Build, deploy, & interact with contracts; set identities to sign with; configure networks; generate keys; and more.
Expand Down Expand Up @@ -169,5 +171,5 @@ pub trait NetworkRunnable {
&self,
global_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<Self::Result, Self::Error>;
) -> Result<txn_result::TxnResult<Self::Result>, Self::Error>;
}
56 changes: 56 additions & 0 deletions cmd/soroban-cli/src/commands/txn_result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::fmt::{Display, Formatter};

use soroban_sdk::xdr::{self, Limits, WriteXdr};

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Expect xdr string")]
XdrStringExpected,
#[error("Expect result")]
ResultExpected,
}

pub enum TxnResult<T> {
Xdr(String),
Res(T),
}

impl<T> TxnResult<T> {
pub fn from_xdr(res: &impl WriteXdr) -> Result<Self, xdr::Error> {
Ok(TxnResult::Xdr(res.to_xdr_base64(Limits::none())?))
}

pub fn xdr(&self) -> Option<&str> {
match self {
TxnResult::Xdr(xdr) => Some(xdr),
TxnResult::Res(_) => None,
}
}

pub fn res(self) -> Option<T> {
match self {
TxnResult::Res(res) => Some(res),
TxnResult::Xdr(_) => None,
}
}

pub fn try_xdr(&self) -> Result<&str, Error> {
self.xdr().ok_or(Error::XdrStringExpected)
}

pub fn try_res(self) -> Result<T, Error> {
self.res().ok_or(Error::ResultExpected)
}
}

impl<T> Display for TxnResult<T>
where
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
TxnResult::Xdr(xdr) => write!(f, "{xdr}"),
TxnResult::Res(res) => write!(f, "{res}"),
}
}
}
8 changes: 0 additions & 8 deletions cmd/soroban-cli/src/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ pub struct Args {
}

impl Args {
pub fn exit_if_build_only(&self, txn: &xdr::Transaction) -> Result<(), xdr::Error> {
if self.build_only {
println!("{}", txn.to_xdr_base64(xdr::Limits::none())?);
std::process::exit(0);
}
Ok(())
}

pub fn apply_to_assembled_txn(&self, txn: Assembled) -> Result<Assembled, xdr::Error> {
let simulated_txn = if let Some(instructions) = self.instructions {
txn.set_max_instructions(instructions)
Expand Down

0 comments on commit 5f7a6e7

Please sign in to comment.