diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 835d2066b3..161535cd0c 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -253,7 +253,7 @@ impl TestEnv { Some(&config), ) .await? - .res() + .into_res() .unwrap()) } diff --git a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs index 65557eda9f..e77f7015cd 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/asset.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs @@ -76,13 +76,13 @@ impl Cmd { #[async_trait::async_trait] impl NetworkRunnable for Cmd { type Error = Error; - type Result = String; + type Result = stellar_strkey::Contract; async fn run_against_rpc_server( &self, args: Option<&global::Args>, config: Option<&config::Args>, - ) -> Result, Error> { + ) -> Result, Error> { let config = config.unwrap_or(&self.config); // Parse asset let asset = parse_asset(&self.asset)?; @@ -115,6 +115,10 @@ impl NetworkRunnable for Cmd { } let txn = client.create_assembled_transaction(&tx).await?; let txn = self.fee.apply_to_assembled_txn(txn)?; + let txn = match txn { + TxnResult::Xdr(raw) => return Ok(TxnResult::Xdr(raw)), + TxnResult::Res(txn) => txn, + }; let get_txn_resp = client .send_assembled_transaction(txn, &key, &[], network_passphrase, None, None) .await? @@ -123,9 +127,7 @@ impl NetworkRunnable for Cmd { data::write(get_txn_resp, &network.rpc_uri()?)?; } - Ok(TxnResult::Xdr( - stellar_strkey::Contract(contract_id.0).to_string(), - )) + Ok(TxnResult::Res(stellar_strkey::Contract(contract_id.0))) } } diff --git a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs index 7a2b929d41..3cb0344986 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs @@ -100,6 +100,8 @@ pub enum Error { Data(#[from] data::Error), #[error(transparent)] Network(#[from] network::Error), + #[error(transparent)] + Wasm(#[from] wasm::Error), } impl Cmd { @@ -122,17 +124,22 @@ impl NetworkRunnable for Cmd { ) -> Result, 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, - ignore_checks: self.ignore_checks, - } - .run_against_rpc_server(global_args, Some(config)) - .await?; - hex::encode(hash.try_res()?) + let hash = if self.fee.build_only { + wasm::Args { wasm: wasm.clone() }.hash()? + } else { + let mut fee = self.fee.clone(); + fee.build_only = false; + install::Cmd { + wasm: wasm::Args { wasm: wasm.clone() }, + config: config.clone(), + fee, + ignore_checks: self.ignore_checks, + } + .run_against_rpc_server(global_args, Some(config)) + .await? + .try_into_res()? + }; + hex::encode(hash) } else { self.wasm_hash .as_ref() @@ -181,6 +188,10 @@ impl NetworkRunnable for Cmd { let txn = client.create_assembled_transaction(&txn).await?; let txn = self.fee.apply_to_assembled_txn(txn)?; + let txn = match txn { + TxnResult::Xdr(raw) => return Ok(TxnResult::Xdr(raw)), + TxnResult::Res(txn) => txn, + }; let get_txn_resp = client .send_assembled_transaction(txn, &key, &[], &network.network_passphrase, None, None) .await? diff --git a/cmd/soroban-cli/src/commands/contract/fetch.rs b/cmd/soroban-cli/src/commands/contract/fetch.rs index 5b223e71ad..d9cb8d4279 100644 --- a/cmd/soroban-cli/src/commands/contract/fetch.rs +++ b/cmd/soroban-cli/src/commands/contract/fetch.rs @@ -75,6 +75,8 @@ pub enum Error { Io(#[from] std::io::Error), #[error("missing result")] MissingResult, + #[error("Unexpected XDR")] + UnexpectedXdr, #[error("unexpected contract code data type: {0:?}")] UnexpectedContractCodeDataType(LedgerEntryData), #[error("reading file {0:?}: {1}")] @@ -117,13 +119,9 @@ impl Cmd { } pub async fn get_bytes(&self) -> Result, Error> { - // This is safe because fetch doesn't create a transaction - unsafe { - Ok(self - .run_against_rpc_server(None, None) - .await? - .res() - .unwrap_unchecked()) + match self.run_against_rpc_server(None, None).await? { + TxnResult::Xdr(_) => Err(Error::UnexpectedXdr), + TxnResult::Res(v) => Ok(v), } } @@ -153,7 +151,6 @@ impl NetworkRunnable for Cmd { client .verify_network_passphrase(Some(&network.network_passphrase)) .await?; - // async closures are not yet stable Ok(TxnResult::Res(client.get_remote_wasm(&contract_id).await?)) } } diff --git a/cmd/soroban-cli/src/commands/contract/id/asset.rs b/cmd/soroban-cli/src/commands/contract/id/asset.rs index 34e5767a6d..e036b7939a 100644 --- a/cmd/soroban-cli/src/commands/contract/id/asset.rs +++ b/cmd/soroban-cli/src/commands/contract/id/asset.rs @@ -26,11 +26,14 @@ pub enum Error { } impl Cmd { pub fn run(&self) -> Result<(), Error> { + println!("{}", self.contract_address()?); + Ok(()) + } + + pub fn contract_address(&self) -> Result { let asset = parse_asset(&self.asset)?; let network = self.config.get_network()?; let contract_id = contract_id_hash_from_asset(&asset, &network.network_passphrase)?; - let strkey_contract_id = stellar_strkey::Contract(contract_id.0).to_string(); - println!("{strkey_contract_id}"); - Ok(()) + Ok(stellar_strkey::Contract(contract_id.0)) } } diff --git a/cmd/soroban-cli/src/commands/contract/install.rs b/cmd/soroban-cli/src/commands/contract/install.rs index 7208e1a93d..646a2d53ac 100644 --- a/cmd/soroban-cli/src/commands/contract/install.rs +++ b/cmd/soroban-cli/src/commands/contract/install.rs @@ -162,6 +162,10 @@ impl NetworkRunnable for Cmd { .create_assembled_transaction(&tx_without_preflight) .await?; let txn = self.fee.apply_to_assembled_txn(txn)?; + let txn = match txn { + TxnResult::Xdr(raw) => return Ok(TxnResult::Xdr(raw)), + TxnResult::Res(txn) => txn, + }; let txn_resp = client .send_assembled_transaction(txn, &key, &[], &network.network_passphrase, None, None) .await?; diff --git a/cmd/soroban-cli/src/commands/contract/invoke.rs b/cmd/soroban-cli/src/commands/contract/invoke.rs index d297f9c547..47220305d7 100644 --- a/cmd/soroban-cli/src/commands/contract/invoke.rs +++ b/cmd/soroban-cli/src/commands/contract/invoke.rs @@ -383,6 +383,10 @@ impl NetworkRunnable for Cmd { } let txn = client.create_assembled_transaction(&tx).await?; let txn = self.fee.apply_to_assembled_txn(txn)?; + let txn = match txn { + TxnResult::Xdr(raw) => return Ok(TxnResult::Xdr(raw)), + TxnResult::Res(txn) => txn, + }; let sim_res = txn.sim_response(); if global_args.map_or(true, |a| !a.no_cache) { data::write(sim_res.clone().into(), &network.rpc_uri()?)?; diff --git a/cmd/soroban-cli/src/commands/txn_result.rs b/cmd/soroban-cli/src/commands/txn_result.rs index f69f549bef..02cc27f4c0 100644 --- a/cmd/soroban-cli/src/commands/txn_result.rs +++ b/cmd/soroban-cli/src/commands/txn_result.rs @@ -27,7 +27,14 @@ impl TxnResult { } } - pub fn res(self) -> Option { + pub fn res(&self) -> Option<&T> { + match self { + TxnResult::Res(res) => Some(res), + TxnResult::Xdr(_) => None, + } + } + + pub fn into_res(self) -> Option { match self { TxnResult::Res(res) => Some(res), TxnResult::Xdr(_) => None, @@ -38,9 +45,15 @@ impl TxnResult { self.xdr().ok_or(Error::XdrStringExpected) } - pub fn try_res(self) -> Result { + pub fn try_res(&self) -> Result<&T, Error> { self.res().ok_or(Error::ResultExpected) } + pub fn try_into_res(self) -> Result { + match self { + TxnResult::Res(res) => Ok(res), + TxnResult::Xdr(_) => Err(Error::XdrStringExpected), + } + } } impl Display for TxnResult diff --git a/cmd/soroban-cli/src/fee.rs b/cmd/soroban-cli/src/fee.rs index f6ac76d58f..70ad9abd91 100644 --- a/cmd/soroban-cli/src/fee.rs +++ b/cmd/soroban-cli/src/fee.rs @@ -1,9 +1,9 @@ use clap::arg; -use soroban_env_host::xdr::{self, WriteXdr}; +use soroban_env_host::xdr; use soroban_rpc::Assembled; -use crate::commands::HEADING_RPC; +use crate::commands::{txn_result::TxnResult, HEADING_RPC}; #[derive(Debug, clap::Args, Clone)] #[group(skip)] @@ -26,22 +26,20 @@ pub struct Args { } impl Args { - pub fn apply_to_assembled_txn(&self, txn: Assembled) -> Result { + pub fn apply_to_assembled_txn( + &self, + txn: Assembled, + ) -> Result, xdr::Error> { let simulated_txn = if let Some(instructions) = self.instructions { txn.set_max_instructions(instructions) } else { add_padding_to_instructions(txn) }; if self.sim_only { - println!( - "{}", - simulated_txn - .transaction() - .to_xdr_base64(xdr::Limits::none())? - ); - std::process::exit(0); + TxnResult::from_xdr(simulated_txn.transaction()) + } else { + Ok(TxnResult::Res(simulated_txn)) } - Ok(simulated_txn) } } diff --git a/cmd/soroban-cli/src/wasm.rs b/cmd/soroban-cli/src/wasm.rs index 4b8a7f8ca8..6f6daf4622 100644 --- a/cmd/soroban-cli/src/wasm.rs +++ b/cmd/soroban-cli/src/wasm.rs @@ -1,5 +1,6 @@ use clap::arg; -use soroban_env_host::xdr::{self, LedgerKey, LedgerKeyContractCode}; +use sha2::{Digest, Sha256}; +use soroban_env_host::xdr::{self, Hash, LedgerKey, LedgerKeyContractCode}; use soroban_spec_tools::contract::{self, Spec}; use std::{ fs, io, @@ -65,6 +66,10 @@ impl Args { let contents = self.read()?; Ok(Spec::new(&contents)?) } + + pub fn hash(&self) -> Result { + Ok(Hash(Sha256::digest(self.read()?).into())) + } } impl From<&PathBuf> for Args {