Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into feat/tx_builder
Browse files Browse the repository at this point in the history
  • Loading branch information
willemneal committed Sep 24, 2024
2 parents 628ca62 + ac5cc57 commit 9287ce1
Show file tree
Hide file tree
Showing 18 changed files with 1,035 additions and 274 deletions.
719 changes: 618 additions & 101 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand All @@ -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"
Expand Down
36 changes: 36 additions & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,8 @@ 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
* `new` — Create a new transaction


Expand Down Expand Up @@ -1327,6 +1329,40 @@ 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_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 <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_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."



## `stellar tx send`

Send a transaction envelope to the network

**Usage:** `stellar tx send [OPTIONS]`

###### **Options:**

* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."



## `stellar tx new`

Create a new transaction
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
38 changes: 36 additions & 2 deletions cmd/crates/soroban-test/tests/it/integration/tx.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
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};

mod operations;

#[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, None).await;
Expand Down Expand Up @@ -53,3 +54,36 @@ 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}");

let output = sandbox
.new_assert_cmd("tx")
.arg("send")
.write_stdin(tx_signed.as_bytes())
.assert()
.success()
.stdout_as_str();
assert_eq!(output, "SUCCESS");
}
2 changes: 1 addition & 1 deletion cmd/crates/stellar-ledger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
87 changes: 24 additions & 63 deletions cmd/crates/stellar-ledger/tests/test/emulator_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Mutex<Range<u16>>> = Lazy::new(|| Mutex::new(40000..50000));
Expand All @@ -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;
Expand All @@ -68,25 +62,20 @@ 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")]
#[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_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;
Expand All @@ -96,25 +85,20 @@ 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")]
#[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_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);
Expand Down Expand Up @@ -185,25 +169,20 @@ 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")]
#[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_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;
Expand All @@ -216,23 +195,18 @@ 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")]
#[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_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;
Expand All @@ -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}");
}
}
Expand All @@ -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) {
Expand Down Expand Up @@ -330,23 +300,14 @@ struct EventsResponse {
events: Vec<EmulatorEvent>,
}

fn get_runnable_image(ledger_device_model: String) -> RunnableImage<Speculos> {
let args = Args {
ledger_device_model,
};
let runnable_image: RunnableImage<Speculos> = (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<Speculos> {
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) {
Expand Down
Loading

0 comments on commit 9287ce1

Please sign in to comment.