Skip to content

Commit

Permalink
feat: --no-build command allows returning built transaction
Browse files Browse the repository at this point in the history
--sim-only for assembling transactions
  • Loading branch information
willemneal committed May 2, 2024
1 parent 6253b7a commit 4d20c27
Show file tree
Hide file tree
Showing 16 changed files with 354 additions and 107 deletions.
35 changes: 19 additions & 16 deletions cmd/crates/soroban-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,22 +236,25 @@ impl TestEnv {
},
hd_path: None,
};
cmd.run_against_rpc_server(
Some(&global::Args {
locator: config::locator::Args {
global: false,
config_dir,
},
filter_logs: Vec::default(),
quiet: false,
verbose: false,
very_verbose: false,
list: false,
no_cache: false,
}),
Some(&config),
)
.await
Ok(cmd
.run_against_rpc_server(
Some(&global::Args {
locator: config::locator::Args {
global: false,
config_dir,
},
filter_logs: Vec::default(),
quiet: false,
verbose: false,
very_verbose: false,
list: false,
no_cache: false,
}),
Some(&config),
)
.await?
.res()
.unwrap())
}

/// Reference to current directory of the `TestEnv`.
Expand Down
24 changes: 20 additions & 4 deletions cmd/crates/soroban-test/tests/it/integration/hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ use crate::integration::util::extend_contract;
use super::util::{deploy_hello, extend, HELLO_WORLD};

#[allow(clippy::too_many_lines)]
#[tokio::test]
async fn invoke_view_with_non_existent_source_account() {
let sandbox = &TestEnv::new();
let id = deploy_hello(sandbox).await;
let world = "world";
let mut cmd = hello_world_cmd(&id, world);
cmd.config.source_account = String::new();
cmd.is_view = true;
let res = sandbox.run_cmd_with(cmd, "test").await.unwrap();
assert_eq!(res, format!(r#"["Hello",{world:?}]"#));
}

#[tokio::test]
async fn invoke() {
let sandbox = &TestEnv::new();
Expand Down Expand Up @@ -140,12 +152,16 @@ fn invoke_hello_world(sandbox: &TestEnv, id: &str) {
.success();
}

async fn invoke_hello_world_with_lib(e: &TestEnv, id: &str) {
let cmd = contract::invoke::Cmd {
fn hello_world_cmd(id: &str, arg: &str) -> contract::invoke::Cmd {
contract::invoke::Cmd {
contract_id: id.to_string(),
slop: vec!["hello".into(), "--world=world".into()],
slop: vec!["hello".into(), format!("--world={arg}").into()],
..Default::default()
};
}
}

async fn invoke_hello_world_with_lib(e: &TestEnv, id: &str) {
let cmd = hello_world_cmd(id, "world");
let res = e.run_cmd_with(cmd, "test").await.unwrap();
assert_eq!(res, r#"["Hello","world"]"#);
}
Expand Down
15 changes: 11 additions & 4 deletions cmd/soroban-cli/src/commands/contract/deploy/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ use std::{array::TryFromSliceError, fmt::Debug, num::ParseIntError};
use crate::{
commands::{
config::{self, data},
global, network, NetworkRunnable,
global, network,
txn_result::TxnResult,
NetworkRunnable,
},
rpc::{Client, Error as SorobanRpcError},
utils::{contract_id_hash_from_asset, parsing::parse_asset},
Expand Down Expand Up @@ -80,7 +82,7 @@ impl NetworkRunnable for Cmd {
&self,
args: 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 @@ -108,8 +110,11 @@ impl NetworkRunnable for Cmd {
network_passphrase,
&key,
)?;
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 txn = self.fee.apply_to_assembled_txn(txn)?;
let get_txn_resp = client
.send_assembled_transaction(txn, &key, &[], network_passphrase, None, None)
.await?
Expand All @@ -118,7 +123,9 @@ impl NetworkRunnable for Cmd {
data::write(get_txn_resp, &network.rpc_uri()?)?;
}

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

Expand Down
24 changes: 18 additions & 6 deletions cmd/soroban-cli/src/commands/contract/deploy/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ use soroban_env_host::{
use crate::commands::{
config::data,
contract::{self, id::wasm::get_contract_id},
global, network, NetworkRunnable,
global, network,
txn_result::{self, TxnResult},
NetworkRunnable,
};
use crate::{
commands::{config, contract::install, HEADING_RPC},
Expand Down Expand Up @@ -93,6 +95,8 @@ pub enum Error {
#[error(transparent)]
WasmId(#[from] contract::id::wasm::Error),
#[error(transparent)]
TxnResult(#[from] txn_result::Error),
#[error(transparent)]
Data(#[from] data::Error),
#[error(transparent)]
Network(#[from] network::Error),
Expand All @@ -115,18 +119,20 @@ 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();
fee.build_only = false;
let hash = install::Cmd {
wasm: wasm::Args { wasm: wasm.clone() },
config: config.clone(),
fee: self.fee.clone(),
fee,
ignore_checks: self.ignore_checks,
}
.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 @@ -169,16 +175,22 @@ impl NetworkRunnable for Cmd {
salt,
&key,
)?;
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);
let txn = self.fee.apply_to_assembled_txn(txn)?;
let get_txn_resp = client
.send_assembled_transaction(txn, &key, &[], &network.network_passphrase, None, None)
.await?
.try_into()?;
if global_args.map_or(true, |a| !a.no_cache) {
data::write(get_txn_resp, &network.rpc_uri()?)?;
}
Ok(stellar_strkey::Contract(contract_id.0).to_string())
Ok(TxnResult::Res(
stellar_strkey::Contract(contract_id.0).to_string(),
))
}
}

Expand Down
20 changes: 14 additions & 6 deletions cmd/soroban-cli/src/commands/contract/extend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use soroban_env_host::xdr::{
use crate::{
commands::{
config::{self, data},
global, network, NetworkRunnable,
global, network,
txn_result::TxnResult,
NetworkRunnable,
},
key,
rpc::{self, Client},
Expand Down Expand Up @@ -87,7 +89,11 @@ pub enum Error {
impl Cmd {
#[allow(clippy::too_many_lines)]
pub async fn run(&self) -> Result<(), Error> {
let ttl_ledger = self.run_against_rpc_server(None, None).await?;
let res = self.run_against_rpc_server(None, None).await?;
let TxnResult::Res(ttl_ledger) = &res else {
println!("{}", res.xdr().unwrap());
return Ok(());
};
if self.ttl_ledger_only {
println!("{ttl_ledger}");
} else {
Expand Down Expand Up @@ -117,7 +123,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 @@ -161,7 +167,9 @@ impl NetworkRunnable for Cmd {
resource_fee: 0,
}),
};

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 @@ -194,7 +202,7 @@ impl NetworkRunnable for Cmd {
let entry = client.get_full_ledger_entries(&keys).await?;
let extension = entry.entries[0].live_until_ledger_seq;
if entry.latest_ledger + i64::from(extend_to) < i64::from(extension) {
return Ok(extension);
return Ok(TxnResult::Res(extension));
}
}

Expand All @@ -209,7 +217,7 @@ impl NetworkRunnable for Cmd {
}),
..
}),
) => Ok(*live_until_ledger_seq),
) => Ok(TxnResult::Res(*live_until_ledger_seq)),
_ => Err(Error::LedgerEntryNotFound),
}
}
Expand Down
14 changes: 11 additions & 3 deletions cmd/soroban-cli/src/commands/contract/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use stellar_strkey::DecodeError;

use super::super::config::{self, locator};
use crate::commands::network::{self, Network};
use crate::commands::txn_result::TxnResult;
use crate::commands::{global, NetworkRunnable};
use crate::{
rpc::{self, Client},
Expand Down Expand Up @@ -116,7 +117,14 @@ impl Cmd {
}

pub async fn get_bytes(&self) -> Result<Vec<u8>, Error> {
self.run_against_rpc_server(None, None).await
// This is safe because fetch doesn't create a transaction
unsafe {
Ok(self
.run_against_rpc_server(None, None)
.await?
.res()
.unwrap_unchecked())
}
}

pub fn network(&self) -> Result<Network, Error> {
Expand All @@ -137,7 +145,7 @@ impl NetworkRunnable for Cmd {
&self,
_args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<Vec<u8>, Error> {
) -> Result<TxnResult<Vec<u8>>, Error> {
let network = config.map_or_else(|| self.network(), |c| Ok(c.get_network()?))?;
tracing::trace!(?network);
let contract_id = self.contract_id()?;
Expand All @@ -146,7 +154,7 @@ impl NetworkRunnable for Cmd {
.verify_network_passphrase(Some(&network.network_passphrase))
.await?;
// async closures are not yet stable
Ok(client.get_remote_wasm(&contract_id).await?)
Ok(TxnResult::Res(client.get_remote_wasm(&contract_id).await?))
}
}
pub fn get_contract_wasm_from_storage(
Expand Down
18 changes: 12 additions & 6 deletions cmd/soroban-cli/src/commands/contract/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use soroban_env_host::xdr::{

use super::restore;
use crate::commands::network;
use crate::commands::txn_result::TxnResult;
use crate::commands::{config::data, global, NetworkRunnable};
use crate::key;
use crate::rpc::{self, Client};
Expand Down Expand Up @@ -72,7 +73,10 @@ pub enum Error {

impl Cmd {
pub async fn run(&self) -> Result<(), Error> {
let res_str = hex::encode(self.run_against_rpc_server(None, None).await?);
let res_str = match self.run_against_rpc_server(None, None).await? {
TxnResult::Xdr(xdr) => xdr,
TxnResult::Res(hash) => hex::encode(hash),
};
println!("{res_str}");
Ok(())
}
Expand All @@ -86,7 +90,7 @@ impl NetworkRunnable for Cmd {
&self,
args: Option<&global::Args>,
config: Option<&config::Args>,
) -> Result<Hash, Error> {
) -> Result<TxnResult<Hash>, Error> {
let config = config.unwrap_or(&self.config);
let contract = self.wasm.read()?;
let network = config.get_network()?;
Expand Down Expand Up @@ -125,6 +129,9 @@ impl NetworkRunnable for Cmd {
let (tx_without_preflight, hash) =
build_install_contract_code_tx(&contract, sequence + 1, self.fee.fee, &key)?;

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?;
Expand All @@ -142,7 +149,7 @@ impl NetworkRunnable for Cmd {
// Skip reupload if this isn't V0 because V1 extension already
// exists.
if code.ext.ne(&ContractCodeEntryExt::V0) {
return Ok(hash);
return Ok(TxnResult::Res(hash));
}
}
_ => {
Expand All @@ -151,11 +158,10 @@ impl NetworkRunnable for Cmd {
}
}
}

let txn = client
.create_assembled_transaction(&tx_without_preflight)
.await?;
let txn = self.fee.apply_to_assembled_txn(txn);
let txn = self.fee.apply_to_assembled_txn(txn)?;
let txn_resp = client
.send_assembled_transaction(txn, &key, &[], &network.network_passphrase, None, None)
.await?;
Expand Down Expand Up @@ -189,7 +195,7 @@ impl NetworkRunnable for Cmd {
if args.map_or(true, |a| !a.no_cache) {
data::write_spec(&hash.to_string(), &wasm_spec.spec)?;
}
Ok(hash)
Ok(TxnResult::Res(hash))
}
}

Expand Down
Loading

0 comments on commit 4d20c27

Please sign in to comment.