From ff57159bb68807c8b2525ad19840edc19d921d80 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Mon, 23 Sep 2024 22:37:38 -0400 Subject: [PATCH 1/3] feat: add `tx sign` (#1590) Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- FULL_HELP_DOCS.md | 19 +++++ Makefile | 4 +- .../soroban-test/tests/it/integration/tx.rs | 32 ++++++- cmd/soroban-cli/src/commands/tx/mod.rs | 6 ++ cmd/soroban-cli/src/commands/tx/sign.rs | 45 ++++++++++ cmd/soroban-cli/src/config/locator.rs | 8 ++ cmd/soroban-cli/src/config/mod.rs | 14 ++-- cmd/soroban-cli/src/config/secret.rs | 21 ++++- cmd/soroban-cli/src/config/sign_with.rs | 53 ++++++++++++ cmd/soroban-cli/src/print.rs | 3 +- cmd/soroban-cli/src/signer.rs | 84 +++++++++++++------ cmd/soroban-cli/src/utils.rs | 30 +------ 12 files changed, 258 insertions(+), 61 deletions(-) create mode 100644 cmd/soroban-cli/src/commands/tx/sign.rs create mode 100644 cmd/soroban-cli/src/config/sign_with.rs diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index b7480cb5ed..9ba32c35a8 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -1291,6 +1291,7 @@ Sign, Simulate, and Send transactions * `simulate` — Simulate a transaction envelope from stdin * `hash` — Calculate the hash of a transaction envelope from stdin +* `sign` — Sign a transaction envelope appending the signature to the envelope @@ -1326,6 +1327,24 @@ Calculate the hash of a transaction envelope from stdin +## `stellar tx sign` + +Sign a transaction envelope appending the signature to the envelope + +**Usage:** `stellar tx sign [OPTIONS]` + +###### **Options:** + +* `--sign-with-key ` — Sign with a local key. Can be an identity (--sign-with-key alice), a secret key (--sign-with-key SC36…), or a seed phrase (--sign-with-key "kite urban…"). If using seed phrase, `--hd-path` defaults to the `0` path +* `--hd-path ` — If using a seed phrase to sign, sets which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." + + + ## `stellar xdr` Decode and encode XDR diff --git a/Makefile b/Makefile index 7e307b16c7..6d55aacc45 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ endif REPOSITORY_BRANCH := "$(shell git rev-parse --abbrev-ref HEAD)" BUILD_TIMESTAMP ?= $(shell date '+%Y-%m-%dT%H:%M:%S') +SOROBAN_PORT?=8000 + # The following works around incompatibility between the rust and the go linkers - # the rust would generate an object file with min-version of 13.0 where-as the go # compiler would generate a binary compatible with 12.3 and up. To align these @@ -53,7 +55,7 @@ test: build-test cargo test e2e-test: - cargo test --test it -- --ignored + cargo test --features it --test it -- integration check: cargo clippy --all-targets diff --git a/cmd/crates/soroban-test/tests/it/integration/tx.rs b/cmd/crates/soroban-test/tests/it/integration/tx.rs index bcb880b18c..c3d2cebd67 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx.rs @@ -4,7 +4,7 @@ use soroban_test::{AssertExt, TestEnv}; use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD}; #[tokio::test] -async fn txn_simulate() { +async fn simulate() { let sandbox = &TestEnv::new(); let xdr_base64_build_only = deploy_contract(sandbox, HELLO_WORLD, DeployKind::BuildOnly).await; let xdr_base64_sim_only = deploy_contract(sandbox, HELLO_WORLD, DeployKind::SimOnly).await; @@ -49,3 +49,33 @@ async fn txn_hash() { assert_eq!(hash.trim(), expected_hash); } + +#[tokio::test] +async fn build_simulate_sign_send() { + let sandbox = &TestEnv::new(); + sandbox + .new_assert_cmd("contract") + .arg("install") + .args(["--wasm", HELLO_WORLD.path().as_os_str().to_str().unwrap()]) + .assert() + .success(); + + let tx_simulated = deploy_contract(sandbox, HELLO_WORLD, DeployKind::SimOnly).await; + dbg!("{tx_simulated}"); + + let tx_signed = sandbox + .new_assert_cmd("tx") + .arg("sign") + .arg("--sign-with-key=test") + .write_stdin(tx_simulated.as_bytes()) + .assert() + .success() + .stdout_as_str(); + dbg!("{tx_signed}"); + + // TODO: Replace with calling tx send when that command is added. + let tx_signed = TransactionEnvelope::from_xdr_base64(tx_signed, Limits::none()).unwrap(); + let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let rpc_result = client.send_transaction_polling(&tx_signed).await.unwrap(); + assert_eq!(rpc_result.status, "SUCCESS"); +} diff --git a/cmd/soroban-cli/src/commands/tx/mod.rs b/cmd/soroban-cli/src/commands/tx/mod.rs index 59f07228ad..5f0f90c4c3 100644 --- a/cmd/soroban-cli/src/commands/tx/mod.rs +++ b/cmd/soroban-cli/src/commands/tx/mod.rs @@ -3,6 +3,7 @@ use clap::Parser; use super::global; pub mod hash; +pub mod sign; pub mod simulate; pub mod xdr; @@ -12,6 +13,8 @@ pub enum Cmd { Simulate(simulate::Cmd), /// Calculate the hash of a transaction envelope from stdin Hash(hash::Cmd), + /// Sign a transaction envelope appending the signature to the envelope + Sign(sign::Cmd), } #[derive(thiserror::Error, Debug)] @@ -22,6 +25,8 @@ pub enum Error { /// An error during hash calculation #[error(transparent)] Hash(#[from] hash::Error), + #[error(transparent)] + Sign(#[from] sign::Error), } impl Cmd { @@ -29,6 +34,7 @@ impl Cmd { match self { Cmd::Simulate(cmd) => cmd.run(global_args).await?, Cmd::Hash(cmd) => cmd.run(global_args)?, + Cmd::Sign(cmd) => cmd.run(global_args).await?, }; Ok(()) } diff --git a/cmd/soroban-cli/src/commands/tx/sign.rs b/cmd/soroban-cli/src/commands/tx/sign.rs new file mode 100644 index 0000000000..92fef74179 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/sign.rs @@ -0,0 +1,45 @@ +use crate::{ + commands::global, + config::{locator, network, sign_with}, + xdr::{self, Limits, WriteXdr}, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + XdrArgs(#[from] super::xdr::Error), + #[error(transparent)] + Network(#[from] network::Error), + #[error(transparent)] + Locator(#[from] locator::Error), + #[error(transparent)] + SignWith(#[from] sign_with::Error), + #[error(transparent)] + Xdr(#[from] xdr::Error), +} + +#[derive(Debug, clap::Parser, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub sign_with: sign_with::Args, + #[command(flatten)] + pub network: network::Args, + #[command(flatten)] + pub locator: locator::Args, +} + +impl Cmd { + #[allow(clippy::unused_async)] + pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let tx_env = super::xdr::tx_envelope_from_stdin()?; + let tx_env_signed = self.sign_with.sign_tx_env( + tx_env, + &self.locator, + &self.network.get(&self.locator)?, + global_args.quiet, + )?; + println!("{}", tx_env_signed.to_xdr_base64(Limits::none())?); + Ok(()) + } +} diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index 86d1004f6d..bc167c977c 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -217,6 +217,14 @@ impl Args { KeyType::Identity.read_with_global(name, &self.local_config()?) } + pub fn key(&self, key_or_name: &str) -> Result { + if let Ok(signer) = key_or_name.parse::() { + Ok(signer) + } else { + self.read_identity(key_or_name) + } + } + pub fn read_network(&self, name: &str) -> Result { let res = KeyType::Network.read_with_global(name, &self.local_config()?); if let Err(Error::ConfigMissing(_, _)) = &res { diff --git a/cmd/soroban-cli/src/config/mod.rs b/cmd/soroban-cli/src/config/mod.rs index ef286f6a06..48eb6dbe84 100644 --- a/cmd/soroban-cli/src/config/mod.rs +++ b/cmd/soroban-cli/src/config/mod.rs @@ -6,7 +6,8 @@ use serde::{Deserialize, Serialize}; use soroban_rpc::Client; use crate::{ - signer, + print::Print, + signer::{self, LocalKey, Signer, SignerKind}, xdr::{Transaction, TransactionEnvelope}, Pwd, }; @@ -18,6 +19,7 @@ pub mod data; pub mod locator; pub mod network; pub mod secret; +pub mod sign_with; pub mod upgrade_check; #[derive(thiserror::Error, Debug)] @@ -65,10 +67,12 @@ impl Args { #[allow(clippy::unused_async)] pub async fn sign(&self, tx: Transaction) -> Result { let key = self.key_pair()?; - let Network { - network_passphrase, .. - } = &self.get_network()?; - Ok(signer::sign_tx(&key, &tx, network_passphrase)?) + let network = &self.get_network()?; + let signer = Signer { + kind: SignerKind::Local(LocalKey { key }), + printer: Print::new(false), + }; + Ok(signer.sign_tx(tx, network)?) } pub async fn sign_soroban_authorizations( diff --git a/cmd/soroban-cli/src/config/secret.rs b/cmd/soroban-cli/src/config/secret.rs index b5b1dd7471..ff1fb7b722 100644 --- a/cmd/soroban-cli/src/config/secret.rs +++ b/cmd/soroban-cli/src/config/secret.rs @@ -3,7 +3,11 @@ use serde::{Deserialize, Serialize}; use std::{io::Write, str::FromStr}; use stellar_strkey::ed25519::{PrivateKey, PublicKey}; -use crate::utils; +use crate::print::Print; +use crate::{ + signer::{self, LocalKey, Signer, SignerKind}, + utils, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -21,6 +25,8 @@ pub enum Error { Ed25519(#[from] ed25519_dalek::SignatureError), #[error("Invalid address {0}")] InvalidAddress(String), + #[error(transparent)] + Signer(#[from] signer::Error), } #[derive(Debug, clap::Args, Clone)] @@ -120,6 +126,19 @@ impl Secret { )?) } + pub fn signer(&self, index: Option, quiet: bool) -> Result { + let kind = match self { + Secret::SecretKey { .. } | Secret::SeedPhrase { .. } => { + let key = self.key_pair(index)?; + SignerKind::Local(LocalKey { key }) + } + }; + Ok(Signer { + kind, + printer: Print::new(quiet), + }) + } + pub fn key_pair(&self, index: Option) -> Result { Ok(utils::into_signing_key(&self.private_key(index)?)) } diff --git a/cmd/soroban-cli/src/config/sign_with.rs b/cmd/soroban-cli/src/config/sign_with.rs new file mode 100644 index 0000000000..685945194d --- /dev/null +++ b/cmd/soroban-cli/src/config/sign_with.rs @@ -0,0 +1,53 @@ +use crate::{signer, xdr::TransactionEnvelope}; +use clap::arg; + +use super::{ + locator, + network::{self, Network}, + secret, +}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Network(#[from] network::Error), + #[error(transparent)] + Signer(#[from] signer::Error), + #[error(transparent)] + Secret(#[from] secret::Error), + #[error(transparent)] + Locator(#[from] locator::Error), + #[error(transparent)] + Rpc(#[from] soroban_rpc::Error), + #[error("No sign with key provided")] + NoSignWithKey, + #[error(transparent)] + StrKey(#[from] stellar_strkey::DecodeError), +} + +#[derive(Debug, clap::Args, Clone, Default)] +#[group(skip)] +pub struct Args { + /// Sign with a local key. Can be an identity (--sign-with-key alice), a secret key (--sign-with-key SC36…), or a seed phrase (--sign-with-key "kite urban…"). If using seed phrase, `--hd-path` defaults to the `0` path. + #[arg(long, env = "STELLAR_SIGN_WITH_KEY")] + pub sign_with_key: Option, + + #[arg(long, requires = "sign_with_key")] + /// If using a seed phrase to sign, sets which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` + pub hd_path: Option, +} + +impl Args { + pub fn sign_tx_env( + &self, + tx: TransactionEnvelope, + locator: &locator::Args, + network: &Network, + quiet: bool, + ) -> Result { + let key_or_name = self.sign_with_key.as_deref().ok_or(Error::NoSignWithKey)?; + let secret = locator.key(key_or_name)?; + let signer = secret.signer(self.hd_path, quiet)?; + Ok(signer.sign_tx_env(tx, network)?) + } +} diff --git a/cmd/soroban-cli/src/print.rs b/cmd/soroban-cli/src/print.rs index f772eb6493..5b98687bdf 100644 --- a/cmd/soroban-cli/src/print.rs +++ b/cmd/soroban-cli/src/print.rs @@ -3,8 +3,7 @@ use std::{env, fmt::Display}; use soroban_env_host::xdr::{Error as XdrError, Transaction}; use crate::{ - config::network::Network, - utils::{explorer_url_for_transaction, transaction_hash}, + config::network::Network, utils::explorer_url_for_transaction, utils::transaction_hash, }; const TERMS: &[&str] = &["Apple_Terminal", "vscode"]; diff --git a/cmd/soroban-cli/src/signer.rs b/cmd/soroban-cli/src/signer.rs index 580a61a5e0..36ae55053a 100644 --- a/cmd/soroban-cli/src/signer.rs +++ b/cmd/soroban-cli/src/signer.rs @@ -1,4 +1,4 @@ -use ed25519_dalek::ed25519::signature::Signer; +use ed25519_dalek::ed25519::signature::Signer as _; use sha2::{Digest, Sha256}; use soroban_env_host::xdr::{ @@ -6,10 +6,11 @@ use soroban_env_host::xdr::{ InvokeHostFunctionOp, Limits, Operation, OperationBody, PublicKey, ScAddress, ScMap, ScSymbol, ScVal, Signature, SignatureHint, SorobanAddressCredentials, SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials, Transaction, TransactionEnvelope, - TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, - TransactionV1Envelope, Uint256, WriteXdr, + TransactionV1Envelope, Uint256, VecM, WriteXdr, }; +use crate::{config::network::Network, print::Print, utils::transaction_hash}; + #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Contract addresses are not supported to sign auth entries {address}")] @@ -24,6 +25,8 @@ pub enum Error { UserCancelledSigning, #[error(transparent)] Xdr(#[from] xdr::Error), + #[error("Only Transaction envelope V1 type is supported")] + UnsupportedTransactionEnvelopeType, } fn requires_auth(txn: &Transaction) -> Option { @@ -189,29 +192,62 @@ fn sign_soroban_authorization_entry( Ok(auth) } -pub fn sign_tx( - key: &ed25519_dalek::SigningKey, - tx: &Transaction, - network_passphrase: &str, -) -> Result { - let tx_hash = hash(tx, network_passphrase)?; - let tx_signature = key.sign(&tx_hash); +pub struct Signer { + pub kind: SignerKind, + pub printer: Print, +} - let decorated_signature = DecoratedSignature { - hint: SignatureHint(key.verifying_key().to_bytes()[28..].try_into()?), - signature: Signature(tx_signature.to_bytes().try_into()?), - }; +#[allow(clippy::module_name_repetitions)] +pub enum SignerKind { + Local(LocalKey), +} - Ok(TransactionEnvelope::Tx(TransactionV1Envelope { - tx: tx.clone(), - signatures: [decorated_signature].try_into()?, - })) +impl Signer { + pub fn sign_tx( + &self, + tx: Transaction, + network: &Network, + ) -> Result { + let tx_env = TransactionEnvelope::Tx(TransactionV1Envelope { + tx, + signatures: VecM::default(), + }); + self.sign_tx_env(tx_env, network) + } + + pub fn sign_tx_env( + &self, + tx_env: TransactionEnvelope, + network: &Network, + ) -> Result { + match tx_env { + TransactionEnvelope::Tx(TransactionV1Envelope { tx, signatures }) => { + let tx_hash = transaction_hash(&tx, &network.network_passphrase)?; + self.printer + .infoln(format!("Signing transaction: {}", hex::encode(tx_hash),)); + let decorated_signature = match &self.kind { + SignerKind::Local(key) => key.sign_tx_hash(tx_hash)?, + }; + let mut sigs = signatures.into_vec(); + sigs.push(decorated_signature); + Ok(TransactionEnvelope::Tx(TransactionV1Envelope { + tx, + signatures: sigs.try_into()?, + })) + } + _ => Err(Error::UnsupportedTransactionEnvelopeType), + } + } } -pub fn hash(tx: &Transaction, network_passphrase: &str) -> Result<[u8; 32], xdr::Error> { - let signature_payload = TransactionSignaturePayload { - network_id: Hash(Sha256::digest(network_passphrase).into()), - tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(tx.clone()), - }; - Ok(Sha256::digest(signature_payload.to_xdr(Limits::none())?).into()) +pub struct LocalKey { + pub key: ed25519_dalek::SigningKey, +} + +impl LocalKey { + pub fn sign_tx_hash(&self, tx_hash: [u8; 32]) -> Result { + let hint = SignatureHint(self.key.verifying_key().to_bytes()[28..].try_into()?); + let signature = Signature(self.key.sign(&tx_hash).to_bytes().to_vec().try_into()?); + Ok(DecoratedSignature { hint, signature }) + } } diff --git a/cmd/soroban-cli/src/utils.rs b/cmd/soroban-cli/src/utils.rs index f8ebb8b37b..f5827f75b8 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -1,13 +1,11 @@ -use ed25519_dalek::Signer; use phf::phf_map; use sha2::{Digest, Sha256}; use stellar_strkey::ed25519::PrivateKey; use soroban_env_host::xdr::{ - Asset, ContractIdPreimage, DecoratedSignature, Error as XdrError, Hash, HashIdPreimage, - HashIdPreimageContractId, Limits, ScMap, ScMapEntry, ScVal, Signature, SignatureHint, - Transaction, TransactionEnvelope, TransactionSignaturePayload, - TransactionSignaturePayloadTaggedTransaction, TransactionV1Envelope, WriteXdr, + Asset, ContractIdPreimage, Error as XdrError, Hash, HashIdPreimage, HashIdPreimageContractId, + Limits, ScMap, ScMapEntry, ScVal, Transaction, TransactionSignaturePayload, + TransactionSignaturePayloadTaggedTransaction, WriteXdr, }; pub use soroban_spec_tools::contract as contract_spec; @@ -49,28 +47,6 @@ pub fn explorer_url_for_contract(network: &Network, contract_id: &str) -> Option .map(|base_url| format!("{base_url}/contract/{contract_id}")) } -/// # Errors -/// -/// Might return an error -pub fn sign_transaction( - key: &ed25519_dalek::SigningKey, - tx: &Transaction, - network_passphrase: &str, -) -> Result { - let tx_hash = transaction_hash(tx, network_passphrase)?; - let tx_signature = key.sign(&tx_hash); - - let decorated_signature = DecoratedSignature { - hint: SignatureHint(key.verifying_key().to_bytes()[28..].try_into()?), - signature: Signature(tx_signature.to_bytes().try_into()?), - }; - - Ok(TransactionEnvelope::Tx(TransactionV1Envelope { - tx: tx.clone(), - signatures: vec![decorated_signature].try_into()?, - })) -} - /// # Errors /// /// Might return an error From ce3190925d780dc674de99851e895d77f59a39da Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Tue, 24 Sep 2024 00:42:19 -0400 Subject: [PATCH 2/3] feat: tx send (#1592) Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- FULL_HELP_DOCS.md | 17 ++++++ .../soroban-test/tests/it/integration/tx.rs | 16 +++-- cmd/soroban-cli/src/commands/tx/mod.rs | 8 ++- cmd/soroban-cli/src/commands/tx/send.rs | 59 +++++++++++++++++++ 4 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 cmd/soroban-cli/src/commands/tx/send.rs diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 9ba32c35a8..43e8370f63 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -1292,6 +1292,7 @@ Sign, Simulate, and Send transactions * `simulate` — Simulate a transaction envelope from stdin * `hash` — Calculate the hash of a transaction envelope from stdin * `sign` — Sign a transaction envelope appending the signature to the envelope +* `send` — Send a transaction envelope to the network @@ -1345,6 +1346,22 @@ Sign a transaction envelope appending the signature to the envelope +## `stellar tx send` + +Send a transaction envelope to the network + +**Usage:** `stellar tx send [OPTIONS]` + +###### **Options:** + +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--global` — Use global config +* `--config-dir ` — Location of config directory, default is "." + + + ## `stellar xdr` Decode and encode XDR diff --git a/cmd/crates/soroban-test/tests/it/integration/tx.rs b/cmd/crates/soroban-test/tests/it/integration/tx.rs index c3d2cebd67..34c6f086dd 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx.rs @@ -1,7 +1,8 @@ +use soroban_rpc::GetTransactionResponse; use soroban_sdk::xdr::{Limits, ReadXdr, TransactionEnvelope, WriteXdr}; use soroban_test::{AssertExt, TestEnv}; -use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD}; +use crate::integration::util::{deploy_contract, deploy_hello, DeployKind, HELLO_WORLD}; #[tokio::test] async fn simulate() { @@ -73,9 +74,12 @@ async fn build_simulate_sign_send() { .stdout_as_str(); dbg!("{tx_signed}"); - // TODO: Replace with calling tx send when that command is added. - let tx_signed = TransactionEnvelope::from_xdr_base64(tx_signed, Limits::none()).unwrap(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); - let rpc_result = client.send_transaction_polling(&tx_signed).await.unwrap(); - assert_eq!(rpc_result.status, "SUCCESS"); + let output = sandbox + .new_assert_cmd("tx") + .arg("send") + .write_stdin(tx_signed.as_bytes()) + .assert() + .success() + .stdout_as_str(); + assert_eq!(output, "SUCCESS"); } diff --git a/cmd/soroban-cli/src/commands/tx/mod.rs b/cmd/soroban-cli/src/commands/tx/mod.rs index 5f0f90c4c3..587a75fda2 100644 --- a/cmd/soroban-cli/src/commands/tx/mod.rs +++ b/cmd/soroban-cli/src/commands/tx/mod.rs @@ -3,6 +3,7 @@ use clap::Parser; use super::global; pub mod hash; +pub mod send; pub mod sign; pub mod simulate; pub mod xdr; @@ -15,18 +16,20 @@ pub enum Cmd { Hash(hash::Cmd), /// Sign a transaction envelope appending the signature to the envelope Sign(sign::Cmd), + /// Send a transaction envelope to the network + Send(send::Cmd), } #[derive(thiserror::Error, Debug)] pub enum Error { - /// An error during the simulation #[error(transparent)] Simulate(#[from] simulate::Error), - /// An error during hash calculation #[error(transparent)] Hash(#[from] hash::Error), #[error(transparent)] Sign(#[from] sign::Error), + #[error(transparent)] + Send(#[from] send::Error), } impl Cmd { @@ -35,6 +38,7 @@ impl Cmd { Cmd::Simulate(cmd) => cmd.run(global_args).await?, Cmd::Hash(cmd) => cmd.run(global_args)?, Cmd::Sign(cmd) => cmd.run(global_args).await?, + Cmd::Send(cmd) => cmd.run(global_args).await?, }; Ok(()) } diff --git a/cmd/soroban-cli/src/commands/tx/send.rs b/cmd/soroban-cli/src/commands/tx/send.rs new file mode 100644 index 0000000000..c3856114d8 --- /dev/null +++ b/cmd/soroban-cli/src/commands/tx/send.rs @@ -0,0 +1,59 @@ +use async_trait::async_trait; +use soroban_rpc::GetTransactionResponse; + +use crate::commands::{global, NetworkRunnable}; +use crate::config::{self, locator, network}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + XdrArgs(#[from] super::xdr::Error), + #[error(transparent)] + Network(#[from] network::Error), + #[error(transparent)] + Config(#[from] config::Error), + #[error(transparent)] + Rpc(#[from] crate::rpc::Error), + #[error(transparent)] + SerdeJson(#[from] serde_json::Error), +} + +#[derive(Debug, clap::Parser, Clone)] +#[group(skip)] +/// Command to send a transaction envelope to the network +/// e.g. `cat file.txt | soroban tx send` +pub struct Cmd { + #[clap(flatten)] + pub network: network::Args, + #[clap(flatten)] + pub locator: locator::Args, +} + +impl Cmd { + pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let response = self.run_against_rpc_server(Some(global_args), None).await?; + println!("{}", serde_json::to_string_pretty(&response)?); + Ok(()) + } +} + +#[async_trait] +impl NetworkRunnable for Cmd { + type Error = Error; + + type Result = GetTransactionResponse; + async fn run_against_rpc_server( + &self, + _: Option<&global::Args>, + config: Option<&config::Args>, + ) -> Result { + let network = if let Some(config) = config { + config.get_network()? + } else { + self.network.get(&self.locator)? + }; + let client = crate::rpc::Client::new(&network.rpc_url)?; + let tx_env = super::xdr::tx_envelope_from_stdin()?; + Ok(client.send_transaction_polling(&tx_env).await?) + } +} From ac5cc57559d69c5b78eed55891d5b0300f1f14b2 Mon Sep 17 00:00:00 2001 From: Elizabeth Engelman <4752801+elizabethengelman@users.noreply.github.com> Date: Tue, 24 Sep 2024 00:52:47 -0400 Subject: [PATCH 3/3] chore: update testcontainers (#1602) Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- Cargo.lock | 719 +++++++++++++++--- Cargo.toml | 16 +- cmd/crates/stellar-ledger/Cargo.toml | 2 +- .../tests/test/emulator_tests.rs | 87 +-- .../stellar-ledger/tests/utils/speculos.rs | 78 +- 5 files changed, 690 insertions(+), 212 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 788fc8e597..c683baba48 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -386,7 +386,7 @@ checksum = "531b97fb4cd3dfdce92c35dedbfdc1f0b9d8091c8ca943d6dae340ef5012d514" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -542,14 +542,20 @@ dependencies = [ "futures-core", "futures-util", "hex", + "home", "http 1.1.0", "http-body-util", "hyper 1.4.1", "hyper-named-pipe", + "hyper-rustls 0.26.0", "hyper-util", "hyperlocal-next", "log", "pin-project-lite", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pemfile 2.1.3", + "rustls-pki-types", "serde", "serde_derive", "serde_json", @@ -621,7 +627,7 @@ dependencies = [ "num-bigint", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -742,7 +748,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -944,7 +950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -984,7 +990,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1011,7 +1017,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1028,7 +1034,7 @@ checksum = "b45506e3c66512b0a65d291a6b452128b7b1dd9841e20d1e151addbd2c00ea50" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1052,7 +1058,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1063,9 +1069,15 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.39", + "syn 2.0.77", ] +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + [[package]] name = "der" version = "0.7.9" @@ -1094,7 +1106,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1148,6 +1160,15 @@ dependencies = [ "dirs-sys 0.3.7", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys 0.4.1", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1198,6 +1219,17 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "docker_credential" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + [[package]] name = "dotenvy" version = "0.15.7" @@ -1323,6 +1355,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "env_filter" version = "0.1.2" @@ -1606,7 +1650,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -1719,7 +1763,7 @@ dependencies = [ "gix-worktree-state", "once_cell", "parking_lot", - "reqwest", + "reqwest 0.11.27", "smallvec", "thiserror", ] @@ -2031,7 +2075,7 @@ checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -2331,7 +2375,7 @@ dependencies = [ "gix-quote", "gix-sec", "gix-url", - "reqwest", + "reqwest 0.11.27", "thiserror", ] @@ -2495,6 +2539,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.3.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2555,6 +2618,51 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "hidapi" version = "1.5.0" @@ -2595,6 +2703,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + [[package]] name = "http" version = "0.2.12" @@ -2707,7 +2826,7 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "httparse", @@ -2730,6 +2849,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", + "h2 0.4.6", "http 1.1.0", "http-body 1.0.1", "httparse", @@ -2766,9 +2886,47 @@ dependencies = [ "hyper 0.14.30", "log", "rustls 0.21.12", - "rustls-native-certs", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "log", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.12", + "rustls-native-certs 0.8.0", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.26.0", + "tower-service", + "webpki-roots 0.26.3", ] [[package]] @@ -2848,6 +3006,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -2952,6 +3120,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2 0.5.7", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -3033,7 +3213,7 @@ checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" dependencies = [ "async-trait", "hyper 0.14.30", - "hyper-rustls", + "hyper-rustls 0.24.2", "jsonrpsee-core", "jsonrpsee-types", "serde", @@ -3209,6 +3389,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -3240,6 +3426,21 @@ dependencies = [ "value-bag", ] +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.1.0" @@ -3257,7 +3458,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3372,7 +3573,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3447,7 +3648,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3531,6 +3732,31 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax 0.8.4", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax 0.8.4", + "structmeta", + "syn 2.0.77", +] + [[package]] name = "paste" version = "1.0.15" @@ -3598,7 +3824,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3642,7 +3868,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3794,7 +4020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -3808,9 +4034,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -3821,11 +4047,65 @@ version = "28.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.0.0", + "rustls 0.23.12", + "socket2 0.5.7", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand", + "ring", + "rustc-hash 2.0.0", + "rustls 0.23.12", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +dependencies = [ + "libc", + "once_cell", + "socket2 0.5.7", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "quote" -version = "1.0.33" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -3950,11 +4230,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", + "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.30", - "hyper-rustls", + "hyper-rustls 0.24.2", "hyper-tls", "ipnet", "js-sys", @@ -3965,15 +4245,15 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.12", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 0.1.2", "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", @@ -3983,6 +4263,62 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "hickory-resolver", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls 0.27.3", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.12", + "rustls-native-certs 0.7.3", + "rustls-pemfile 2.1.3", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.26.3", + "windows-registry", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -4049,7 +4385,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.39", + "syn 2.0.77", "walkdir", ] @@ -4075,6 +4411,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc_version" version = "0.4.0" @@ -4123,6 +4465,20 @@ dependencies = [ "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.6", + "subtle", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.12" @@ -4145,7 +4501,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.3", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.1.3", + "rustls-pki-types", "schannel", "security-framework", ] @@ -4159,6 +4541,16 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.8.0" @@ -4246,7 +4638,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4329,7 +4721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cec6914e06f503f83e431e1762c82003c5233b1dffb6185e51e4c40dd1c26eaa" dependencies = [ "slipped10", - "stellar-strkey", + "stellar-strkey 0.0.8", "thiserror", "tiny-bip39", ] @@ -4362,7 +4754,7 @@ checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4373,7 +4765,7 @@ checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4405,7 +4797,7 @@ checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4456,7 +4848,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4481,7 +4873,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4663,14 +5055,14 @@ dependencies = [ [[package]] name = "soroban-builtin-sdk-macros" -version = "21.2.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44877373b3dc6c662377cb1600e3a62706d75e484b6064f9cd22e467c676b159" +checksum = "2f57a68ef8777e28e274de0f3a88ad9a5a41d9a2eb461b4dd800b086f0e83b80" dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4692,7 +5084,7 @@ dependencies = [ "crate-git-revision 0.0.4", "csv", "directories", - "dirs", + "dirs 4.0.0", "dotenvy", "ed25519-dalek 2.1.1", "ethnum", @@ -4736,7 +5128,7 @@ dependencies = [ "soroban-spec-tools", "soroban-spec-typescript", "stellar-rpc-client", - "stellar-strkey", + "stellar-strkey 0.0.11", "stellar-xdr", "strsim 0.10.0", "strum 0.17.1", @@ -4762,9 +5154,9 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "21.2.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590add16843a61b01844e19e89bccaaee6aa21dc76809017b0662c17dc139ee9" +checksum = "2fd1c89463835fe6da996318156d39f424b4f167c725ec692e5a7a2d4e694b3d" dependencies = [ "arbitrary", "crate-git-revision 0.0.6", @@ -4781,9 +5173,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "21.2.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec8dc43acdd6c7e7b371acf44fc1a7dac24934ae3b2f05fafd618818548176" +checksum = "6bfb2536811045d5cd0c656a324cbe9ce4467eb734c7946b74410d90dea5d0ce" dependencies = [ "soroban-env-common", "static_assertions", @@ -4791,9 +5183,9 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "21.2.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e25aaffe0c62eb65e0e349f725b4b8b13ad0764d78a15aab5bbccb5c4797726" +checksum = "2b7a32c28f281c423189f1298960194f0e0fc4eeb72378028171e556d8cd6160" dependencies = [ "backtrace", "curve25519-dalek 4.1.3", @@ -4818,15 +5210,15 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.8", "wasmparser 0.116.1", ] [[package]] name = "soroban-env-macros" -version = "21.2.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e16b761459fdf3c4b62b24df3941498d14e5246e6fadfb4774ed8114d243aa4" +checksum = "242926fe5e0d922f12d3796cd7cd02dd824e5ef1caa088f45fce20b618309f64" dependencies = [ "itertools 0.11.0", "proc-macro2", @@ -4834,7 +5226,7 @@ dependencies = [ "serde", "serde_json", "stellar-xdr", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -4843,9 +5235,9 @@ version = "21.5.0" [[package]] name = "soroban-ledger-snapshot" -version = "21.2.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667a040c424d5a479387a6ca71f9591c364cdd2cfdfb1f4227753b4d1bab2a80" +checksum = "9cf596b2083946a95914a55d7d29cee6a8095b515fd06211851f45bf6af5a496" dependencies = [ "serde", "serde_json", @@ -4857,9 +5249,9 @@ dependencies = [ [[package]] name = "soroban-sdk" -version = "21.2.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e76cfdcf2610f97d595db27dd164abe8f38c00b745e822220c2874c185d9c6f" +checksum = "69e39bf9e8ab05579c836e8e5be5f2f4c5ba75e7337ece20e975e82fc3a9d41e" dependencies = [ "arbitrary", "bytes-lit", @@ -4872,14 +5264,14 @@ dependencies = [ "soroban-env-host", "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.8", ] [[package]] name = "soroban-sdk-macros" -version = "21.5.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0772e87f2f675afdb4617b3e084bee7d92204d32cf1cd664a756fd0f4af5608e" +checksum = "da03fa00b8ca6e392f013359c06d790d2d379f9c8d6f8a6dfe563ec64311e5d3" dependencies = [ "crate-git-revision 0.0.6", "darling", @@ -4892,14 +5284,14 @@ dependencies = [ "soroban-spec", "soroban-spec-rust", "stellar-xdr", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] name = "soroban-spec" -version = "21.5.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40917f326155433baf8d6fa36b3006c19139cf0acc01acf4eaf2516b3eaa23e3" +checksum = "64c723195463d8742bcb481520bd8b8325da66c39ea236ad46261e6af992e8a8" dependencies = [ "base64 0.13.1", "stellar-xdr", @@ -4923,9 +5315,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "21.5.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11343e04efdaf247f0cd9c8517cb093f60bd2490f8ee76c9f86e2c50308d443" +checksum = "c0f1b0ec2af54e38f138910f09e101b100130efe625f69ece51c76dd4f06f8b2" dependencies = [ "prettyplease", "proc-macro2", @@ -4933,7 +5325,7 @@ dependencies = [ "sha2 0.10.8", "soroban-spec", "stellar-xdr", - "syn 2.0.39", + "syn 2.0.77", "thiserror", ] @@ -4948,7 +5340,7 @@ dependencies = [ "serde_json", "soroban-env-host", "soroban-spec", - "stellar-strkey", + "stellar-strkey 0.0.11", "stellar-xdr", "thiserror", "tokio", @@ -4996,7 +5388,7 @@ dependencies = [ "soroban-spec", "soroban-spec-tools", "stellar-rpc-client", - "stellar-strkey", + "stellar-strkey 0.0.11", "thiserror", "tokio", "toml 0.8.19", @@ -5007,9 +5399,9 @@ dependencies = [ [[package]] name = "soroban-token-sdk" -version = "21.2.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a758c3af83d174cd5f512d28a1c03983fc10888f75ebcc884ce303e782d409" +checksum = "0c6ede0da76646037f3ea5db9ccd37830865444bb24f137cb8f0af8282c784f5" dependencies = [ "soroban-sdk", ] @@ -5075,7 +5467,7 @@ dependencies = [ "once_cell", "phf", "pretty_assertions", - "reqwest", + "reqwest 0.11.27", "sep5", "serde", "serde_derive", @@ -5086,7 +5478,7 @@ dependencies = [ "soroban-env-host", "soroban-spec", "stellar-rpc-client", - "stellar-strkey", + "stellar-strkey 0.0.11", "stellar-xdr", "test-case", "testcontainers", @@ -5111,7 +5503,7 @@ dependencies = [ "serde-aux", "serde_json", "sha2 0.10.8", - "stellar-strkey", + "stellar-strkey 0.0.8", "stellar-xdr", "termcolor", "termcolor_output", @@ -5131,6 +5523,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "stellar-strkey" +version = "0.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0989c9a05eccbd08b60e603a1c7e3ed3ec92c0de73b8681fc964d272ab2b2697" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", +] + [[package]] name = "stellar-xdr" version = "21.2.0" @@ -5147,7 +5549,7 @@ dependencies = [ "serde", "serde_json", "serde_with", - "stellar-strkey", + "stellar-strkey 0.0.8", "thiserror", ] @@ -5176,6 +5578,29 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn 2.0.77", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "strum" version = "0.17.1" @@ -5232,9 +5657,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.39" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -5247,6 +5672,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -5347,7 +5781,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -5358,7 +5792,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", "test-case-core", ] @@ -5407,38 +5841,51 @@ dependencies = [ [[package]] name = "testcontainers" -version = "0.15.0" -source = "git+https://github.com/testcontainers/testcontainers-rs.git?rev=4b3e4f08a2c0bdf521636b03f959f004e6d216aa#4b3e4f08a2c0bdf521636b03f959f004e6d216aa" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cbe485aafddfd8b2d01665937c95498d894c07fabd9c4e06a53c7da4ccc56" dependencies = [ + "async-trait", + "bollard", "bollard-stubs", + "bytes", + "dirs 5.0.1", + "docker_credential", + "either", "futures", - "hex", - "hmac 0.12.1", "log", - "rand", + "memchr", + "parse-display", + "pin-project-lite", + "reqwest 0.12.7", "serde", "serde_json", - "sha2 0.10.8", + "serde_with", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "url", ] [[package]] name = "thiserror" -version = "1.0.55" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3de26b0965292219b4287ff031fcba86837900fe9cd2b34ea8ad893c0953d2" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.55" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268026685b2be38d7103e9e507c938a1fcb3d7e6eb15e87870b617bf37b6d581" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -5495,7 +5942,7 @@ dependencies = [ "once_cell", "pbkdf2", "rand", - "rustc-hash", + "rustc-hash 1.1.0", "sha2 0.10.8", "thiserror", "unicode-normalization", @@ -5553,7 +6000,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -5576,6 +6023,39 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.12", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -5704,7 +6184,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -5846,8 +6326,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", + "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] @@ -5941,7 +6422,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -5975,7 +6456,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6120,6 +6601,12 @@ dependencies = [ "rustix 0.38.34", ] +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -6160,6 +6647,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -6360,7 +6877,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] [[package]] @@ -6380,5 +6897,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.39", + "syn 2.0.77", ] diff --git a/Cargo.toml b/Cargo.toml index c3108dc784..f7185b9ed1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,16 +15,16 @@ version = "21.5.0" rust-version = "1.79.0" [workspace.dependencies.soroban-env-host] -version = "=21.2.0" +version = "=21.2.1" [workspace.dependencies.soroban-simulation] -version = "21.2.0" +version = "=21.2.1" [workspace.dependencies.soroban-spec] -version = "=21.5.0" +version = "=21.7.2" [workspace.dependencies.soroban-spec-rust] -version = "=21.5.0" +version = "=21.7.2" [workspace.dependencies.soroban-spec-json] version = "=21.5.0" @@ -39,13 +39,13 @@ version = "21.5.0" path = "./cmd/crates/soroban-spec-tools" [workspace.dependencies.soroban-sdk] -version = "=21.2.0" +version = "=21.7.2" [workspace.dependencies.soroban-token-sdk] -version = "=21.2.0" +version = "=21.7.2" [workspace.dependencies.soroban-ledger-snapshot] -version = "=21.2.0" +version = "=21.7.2" [workspace.dependencies.soroban-cli] version = "=21.5.0" @@ -60,7 +60,7 @@ version = "21.2.0" default-features = true [workspace.dependencies] -stellar-strkey = "0.0.8" +stellar-strkey = "0.0.11" sep5 = "0.0.4" base64 = "0.21.2" thiserror = "1.0.46" diff --git a/cmd/crates/stellar-ledger/Cargo.toml b/cmd/crates/stellar-ledger/Cargo.toml index d8847c7d7c..b8894b71d2 100644 --- a/cmd/crates/stellar-ledger/Cargo.toml +++ b/cmd/crates/stellar-ledger/Cargo.toml @@ -49,7 +49,7 @@ pretty_assertions = "1.2.1" serial_test = "3.0.0" httpmock = "0.7.0-rc.1" test-case = "*" -testcontainers = { git = "https://github.com/testcontainers/testcontainers-rs.git", rev = "4b3e4f08a2c0bdf521636b03f959f004e6d216aa" } +testcontainers = "0.20.1" [features] diff --git a/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs b/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs index 6e9235bb49..d45981eef3 100644 --- a/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs +++ b/cmd/crates/stellar-ledger/tests/test/emulator_tests.rs @@ -17,8 +17,7 @@ use std::{collections::HashMap, time::Duration}; use stellar_xdr::curr::{ Memo, MuxedAccount, PaymentOp, Preconditions, SequenceNumber, TransactionExt, }; - -use testcontainers::{clients, core::Port, RunnableImage}; +use testcontainers::{core::ContainerPort, runners::AsyncRunner, ContainerAsync, ImageExt}; use tokio::time::sleep; static PORT_RANGE: Lazy>> = Lazy::new(|| Mutex::new(40000..50000)); @@ -40,21 +39,16 @@ mod test_helpers { } use test_case::test_case; -use test_helpers::test::{ - emulator_http_transport::EmulatorHttpTransport, - speculos::{Args, Speculos}, -}; +use test_helpers::test::{emulator_http_transport::EmulatorHttpTransport, speculos::Speculos}; #[test_case("nanos".to_string() ; "when the device is NanoS")] #[test_case("nanox".to_string() ; "when the device is NanoX")] #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_get_public_key(ledger_device_model: String) { - let runnable_image = get_runnable_image(ledger_device_model.clone()); - let docker = clients::Cli::default(); - let node = docker.run(runnable_image); - let host_port = node.get_host_port_ipv4(9998); - let ui_host_port: u16 = node.get_host_port_ipv4(5000); + let container = get_container(ledger_device_model.clone()).await; + let host_port = container.get_host_port_ipv4(9998).await.unwrap(); + let ui_host_port: u16 = container.get_host_port_ipv4(5000).await.unwrap(); wait_for_emulator_start_text(ui_host_port).await; let ledger = ledger(host_port).await; @@ -68,13 +62,10 @@ async fn test_get_public_key(ledger_device_model: String) { assert_eq!(public_key_string, expected_public_key); } Err(e) => { - node.stop(); println!("{e}"); assert!(false); } } - - node.stop(); } #[test_case("nanos".to_string() ; "when the device is NanoS")] @@ -82,11 +73,9 @@ async fn test_get_public_key(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_get_app_configuration(ledger_device_model: String) { - let runnable_image = get_runnable_image(ledger_device_model.clone()); - let docker = clients::Cli::default(); - let node = docker.run(runnable_image); - let host_port = node.get_host_port_ipv4(9998); - let ui_host_port: u16 = node.get_host_port_ipv4(5000); + let container = get_container(ledger_device_model.clone()).await; + let host_port = container.get_host_port_ipv4(9998).await.unwrap(); + let ui_host_port: u16 = container.get_host_port_ipv4(5000).await.unwrap(); wait_for_emulator_start_text(ui_host_port).await; let ledger = ledger(host_port).await; @@ -96,13 +85,10 @@ async fn test_get_app_configuration(ledger_device_model: String) { assert_eq!(config, vec![0, 5, 0, 3]); } Err(e) => { - node.stop(); println!("{e}"); assert!(false); } }; - - node.stop(); } #[test_case("nanos".to_string() ; "when the device is NanoS")] @@ -110,11 +96,9 @@ async fn test_get_app_configuration(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx(ledger_device_model: String) { - let runnable_image = get_runnable_image(ledger_device_model.clone()); - let docker = clients::Cli::default(); - let node = docker.run(runnable_image); - let host_port = node.get_host_port_ipv4(9998); - let ui_host_port: u16 = node.get_host_port_ipv4(5000); + let container = get_container(ledger_device_model.clone()).await; + let host_port = container.get_host_port_ipv4(9998).await.unwrap(); + let ui_host_port: u16 = container.get_host_port_ipv4(5000).await.unwrap(); wait_for_emulator_start_text(ui_host_port).await; let ledger = Arc::new(ledger(host_port).await); @@ -185,13 +169,10 @@ async fn test_sign_tx(ledger_device_model: String) { assert_eq!( hex::encode(response), "5c2f8eb41e11ab922800071990a25cf9713cc6e7c43e50e0780ddc4c0c6da50c784609ef14c528a12f520d8ea9343b49083f59c51e3f28af8c62b3edeaade60e"); } Err(e) => { - node.stop(); println!("{e}"); assert!(false); } }; - - node.stop(); } #[test_case("nanos".to_string() ; "when the device is NanoS")] @@ -199,11 +180,9 @@ async fn test_sign_tx(ledger_device_model: String) { #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx_hash_when_hash_signing_is_not_enabled(ledger_device_model: String) { - let runnable_image = get_runnable_image(ledger_device_model.clone()); - let docker = clients::Cli::default(); - let node = docker.run(runnable_image); - let host_port = node.get_host_port_ipv4(9998); - let ui_host_port: u16 = node.get_host_port_ipv4(5000); + let container = get_container(ledger_device_model.clone()).await; + let host_port = container.get_host_port_ipv4(9998).await.unwrap(); + let ui_host_port: u16 = container.get_host_port_ipv4(5000).await.unwrap(); wait_for_emulator_start_text(ui_host_port).await; let ledger = ledger(host_port).await; @@ -216,11 +195,8 @@ async fn test_sign_tx_hash_when_hash_signing_is_not_enabled(ledger_device_model: assert_eq!(msg, "Ledger APDU retcode: 0x6C66"); // this error code is SW_TX_HASH_SIGNING_MODE_NOT_ENABLED https://github.com/LedgerHQ/app-stellar/blob/develop/docs/COMMANDS.md } else { - node.stop(); panic!("Unexpected result: {:?}", result); } - - node.stop(); } #[test_case("nanos".to_string() ; "when the device is NanoS")] @@ -228,11 +204,9 @@ async fn test_sign_tx_hash_when_hash_signing_is_not_enabled(ledger_device_model: #[test_case("nanosp".to_string() ; "when the device is NanoS Plus")] #[tokio::test] async fn test_sign_tx_hash_when_hash_signing_is_enabled(ledger_device_model: String) { - let runnable_image = get_runnable_image(ledger_device_model.clone()); - let docker = clients::Cli::default(); - let node = docker.run(runnable_image); - let host_port = node.get_host_port_ipv4(9998); - let ui_host_port: u16 = node.get_host_port_ipv4(5000); + let container = get_container(ledger_device_model.clone()).await; + let host_port = container.get_host_port_ipv4(9998).await.unwrap(); + let ui_host_port: u16 = container.get_host_port_ipv4(5000).await.unwrap(); wait_for_emulator_start_text(ui_host_port).await; enable_hash_signing(ui_host_port).await; @@ -248,7 +222,6 @@ async fn test_sign_tx_hash_when_hash_signing_is_enabled(ledger_device_model: Str ) { Ok(()) => {} Err(e) => { - node.stop(); panic!("Unexpected result: {e}"); } } @@ -267,12 +240,9 @@ async fn test_sign_tx_hash_when_hash_signing_is_enabled(ledger_device_model: Str assert_eq!( hex::encode(response), "e0fa9d19f34ddd494bbb794645fc82eb5ebab29e74160f1b1d5697e749aada7c6b367236df87326b0fdc921ed39702242fc8b14414f4e0ee3e775f1fd0208101"); } Err(e) => { - node.stop(); panic!("Unexpected result: {e}"); } } - - node.stop(); } async fn click(ui_host_port: u16, url: &str) { @@ -330,23 +300,14 @@ struct EventsResponse { events: Vec, } -fn get_runnable_image(ledger_device_model: String) -> RunnableImage { - let args = Args { - ledger_device_model, - }; - let runnable_image: RunnableImage = (Speculos::new(), args).into(); - - // doing this to randomize the ports on the host so that parallel tests don't clobber each other +async fn get_container(ledger_device_model: String) -> ContainerAsync { let (tcp_port_1, tcp_port_2) = get_available_ports(2); - runnable_image - .with_mapped_port(Port { - local: tcp_port_1, - internal: 9998, - }) - .with_mapped_port(Port { - local: tcp_port_2, - internal: 5000, - }) + Speculos::new(ledger_device_model) + .with_mapped_port(tcp_port_1, ContainerPort::Tcp(9998)) + .with_mapped_port(tcp_port_2, ContainerPort::Tcp(5000)) + .start() + .await + .unwrap() } fn get_available_ports(n: usize) -> (u16, u16) { diff --git a/cmd/crates/stellar-ledger/tests/utils/speculos.rs b/cmd/crates/stellar-ledger/tests/utils/speculos.rs index caccdfc389..57439b0af6 100644 --- a/cmd/crates/stellar-ledger/tests/utils/speculos.rs +++ b/cmd/crates/stellar-ledger/tests/utils/speculos.rs @@ -1,5 +1,8 @@ -use std::{collections::HashMap, path::PathBuf}; -use testcontainers::{core::WaitFor, Image, ImageArgs}; +use std::{borrow::Cow, collections::HashMap, path::PathBuf}; +use testcontainers::{ + core::{Mount, WaitFor}, + Image, +}; const NAME: &str = "docker.io/zondax/builder-zemu"; const TAG: &str = "speculos-3a3439f6b45eca7f56395673caaf434c202e7005"; @@ -24,72 +27,69 @@ impl From<&Map> for HashMap { } #[derive(Debug, Default)] -pub struct Speculos(HashMap, HashMap); +pub struct Speculos { + env: HashMap, + volumes: Vec, + cmd: String, +} + const DEFAULT_APP_PATH: &str = "/project/app/bin"; impl Speculos { #[allow(dead_code)] - pub fn new() -> Self { + pub fn new(ledger_device_model: String) -> Self { #[allow(unused_mut)] let apps_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("tests") .join("test_fixtures") .join("apps"); - let mut volumes = HashMap::new(); - volumes.insert( - apps_dir.to_str().unwrap().to_string(), - DEFAULT_APP_PATH.to_string(), - ); - Speculos(ENV.into(), volumes) - } -} - -#[derive(Debug, Clone)] -pub struct Args { - pub ledger_device_model: String, -} - -impl Default for Args { - fn default() -> Self { - Self { - ledger_device_model: "nanos".to_string(), + let volumes = vec![Mount::bind_mount( + apps_dir.to_str().unwrap(), + DEFAULT_APP_PATH, + )]; + let cmd = Self::get_cmd(ledger_device_model); + Speculos { + env: ENV.into(), + volumes, + cmd, } } -} -impl ImageArgs for Args { - fn into_iterator(self) -> Box> { - let device_model = self.ledger_device_model.clone(); + fn get_cmd(ledger_device_model: String) -> String { + let device_model = ledger_device_model.clone(); let container_elf_path = match device_model.as_str() { "nanos" => format!("{DEFAULT_APP_PATH}/stellarNanoSApp.elf"), "nanosp" => format!("{DEFAULT_APP_PATH}/stellarNanoSPApp.elf"), "nanox" => format!("{DEFAULT_APP_PATH}/stellarNanoXApp.elf"), _ => panic!("Unsupported device model"), }; - let command_string = format!("/home/zondax/speculos/speculos.py --log-level speculos:DEBUG --color JADE_GREEN --display headless -s {TEST_SEED_PHRASE} -m {device_model} {container_elf_path}"); - Box::new(vec![command_string].into_iter()) + format!("/home/zondax/speculos/speculos.py --log-level speculos:DEBUG --color JADE_GREEN --display headless -s {TEST_SEED_PHRASE} -m {device_model} {container_elf_path}") } } impl Image for Speculos { - type Args = Args; - - fn name(&self) -> String { - NAME.to_owned() + fn name(&self) -> &str { + NAME } - fn tag(&self) -> String { - TAG.to_owned() + fn tag(&self) -> &str { + TAG } fn ready_conditions(&self) -> Vec { vec![WaitFor::message_on_stdout("HTTP proxy started...")] } - fn env_vars(&self) -> Box + '_> { - Box::new(self.0.iter()) + fn env_vars( + &self, + ) -> impl IntoIterator>, impl Into>)> { + self.env.clone().into_iter().collect::>() } - fn volumes(&self) -> Box + '_> { - Box::new(self.1.iter()) + fn mounts(&self) -> impl IntoIterator { + self.volumes.iter() } -} + + fn cmd(&self) -> impl IntoIterator>> { + vec![self.cmd.clone()].into_iter() + } +} \ No newline at end of file