Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: add stellar ledger as signer #1627

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2083a7a
feat: initial ledger signer
willemneal Sep 24, 2024
aee08f8
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Oct 7, 2024
b02ffc2
Merge branch 'main' into feat/add_stellar_ledger
willemneal Oct 21, 2024
a67f587
fix: add arg
willemneal Oct 21, 2024
70e58b0
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 1, 2024
0369e05
feat: add ledger key name for lookup and reference as source account
willemneal Nov 1, 2024
91a5f2b
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 1, 2024
6a4986e
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 2, 2024
efd2948
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 5, 2024
518e591
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 5, 2024
1fa59d8
Merge branch 'main' into feat/add_stellar_ledger
willemneal Nov 11, 2024
a0055a9
Merge branch 'main' into feat/add_stellar_ledger
willemneal Nov 14, 2024
5755990
Merge branch 'main' into feat/add_stellar_ledger
willemneal Nov 16, 2024
0aaf7c5
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 18, 2024
8799cd0
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 18, 2024
98b0100
feat(stellar-ledger): make test utilties public
willemneal Nov 18, 2024
37f302d
fix: add first proper test using ledger and CLI
willemneal Nov 19, 2024
09eff2f
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Nov 19, 2024
4680b96
fix: actually test in CI
willemneal Nov 19, 2024
567e2ab
fix: fix tests
willemneal Dec 3, 2024
dd1d079
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Dec 3, 2024
efa4f3a
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Dec 9, 2024
7537edb
fix: use different contracts for each test
willemneal Dec 9, 2024
2d22fb4
fix: use salt for sim test and separate CI tests
willemneal Dec 9, 2024
a1c654b
fix: clippy
willemneal Dec 9, 2024
a04ab20
fix: reuse container for ledger tests
willemneal Dec 9, 2024
4291ad1
Merge branch 'main' into feat/add_stellar_ledger
willemneal Dec 9, 2024
6143b84
fix: clippy and run each test independently
willemneal Dec 10, 2024
9a13673
fix: run each ledger test by themselves
willemneal Dec 10, 2024
a210205
fix: separate into separate job
willemneal Dec 11, 2024
cb3f499
fix: build local transaction to test valid signature instead of relyi…
willemneal Dec 13, 2024
75df1cb
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Dec 13, 2024
c9456fe
Merge remote-tracking branch 'origin/main' into feat/add_stellar_ledger
willemneal Dec 16, 2024
f2d8fe7
fix: split tests to different hd_pahs
willemneal Dec 16, 2024
6212d31
fix: CI install needed deps
willemneal Dec 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/rpc-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- run: rustup update
- run: cargo build
- run: rustup target add wasm32-unknown-unknown
- run: make build-test-wasms
- run: SOROBAN_PORT=8000 cargo test --features it --package soroban-test --test it -- integration
- name: install libudev-dev
run: |
sudo apt install -y libudev-dev
- run: cargo build --features emulator-tests
- run: SOROBAN_PORT=8000 cargo test --features it --features emulator-tests --package soroban-test --test it -- integration
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ test_snapshots
.idea
local.sh
.stellar
.zed
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ version = "=22.0.0-rc.3"
package = "stellar-rpc-client"
version = "=22.0.0-rc.1"

[workspace.dependencies.stellar-ledger]
version = "=22.0.0"
path = "cmd/crates/stellar-ledger"

# Dependencies from elsewhere shared by crates:
[workspace.dependencies]
stellar-strkey = "0.0.11"
Expand Down Expand Up @@ -104,7 +108,10 @@ walkdir = "2.5.0"
toml_edit = "0.22.20"
toml = "0.8.19"
reqwest = "0.12.7"
# testing
predicates = "3.1.2"
testcontainers = { version = "0.20.1" }


[profile.test-wasms]
inherits = "release"
Expand Down
5 changes: 3 additions & 2 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ Given an identity return its address (public key)

###### **Arguments:**

* `<NAME>` — Name of identity to lookup, default test identity used if not provided
* `<NAME>` — Name of identity to lookup, ledger, or secret key

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

Expand All @@ -980,7 +980,7 @@ Fund an identity on a test network

###### **Arguments:**

* `<NAME>` — Name of identity to lookup, default test identity used if not provided
* `<NAME>` — Name of identity to lookup, ledger, or secret key

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

Expand Down Expand Up @@ -1499,6 +1499,7 @@ Sign a transaction envelope appending the signature to the envelope
* `--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`
* `--sign-with-lab` — Sign with https://lab.stellar.org
* `--sign-with-ledger` — Sign with a ledger wallet
* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--rpc-header <RPC_HEADERS>` — RPC Header(s) to include in requests to the RPC provider
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
Expand Down
4 changes: 4 additions & 0 deletions cmd/crates/soroban-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ stellar-strkey = { workspace = true }
sep5 = { workspace = true }
soroban-cli = { workspace = true }
soroban-rpc = { workspace = true }
stellar-ledger = { workspace = true }

thiserror = "1.0.31"
sha2 = "0.10.6"
Expand All @@ -32,6 +33,7 @@ assert_fs = "1.0.7"
predicates = { workspace = true }
fs_extra = "1.3.0"
toml = { workspace = true }
testcontainers = { workspace = true }


[dev-dependencies]
Expand All @@ -42,6 +44,8 @@ walkdir = "2.4.0"
ulid.workspace = true
ed25519-dalek = { workspace = true }
hex = { workspace = true }
test-case = "3.3.1"

[features]
it = []
emulator-tests = ["stellar-ledger/emulator-tests"]
19 changes: 18 additions & 1 deletion cmd/crates/soroban-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use soroban_cli::{
};

mod wasm;

pub use wasm::Wasm;

pub const TEST_ACCOUNT: &str = "test";
Expand Down Expand Up @@ -276,9 +277,10 @@ impl TestEnv {
}

/// Returns the public key corresponding to the test keys's `hd_path`
pub fn test_address(&self, hd_path: usize) -> String {
pub async fn test_address(&self, hd_path: usize) -> String {
self.cmd::<keys::address::Cmd>(&format!("--hd-path={hd_path}"))
.public_key()
.await
.unwrap()
.to_string()
}
Expand Down Expand Up @@ -307,6 +309,21 @@ impl TestEnv {
pub fn client(&self) -> soroban_rpc::Client {
soroban_rpc::Client::new(&self.rpc_url).unwrap()
}

#[cfg(feature = "emulator-tests")]
pub async fn speculos_container(
ledger_device_model: &str,
) -> testcontainers::ContainerAsync<stellar_ledger::emulator_test_support::speculos::Speculos>
{
use stellar_ledger::emulator_test_support::{
enable_hash_signing, get_container, wait_for_emulator_start_text,
};
let container = get_container(ledger_device_model).await;
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;
container
}
}

pub fn temp_ledger_file() -> OsString {
Expand Down
3 changes: 3 additions & 0 deletions cmd/crates/soroban-test/tests/it/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ mod snapshot;
mod tx;
mod util;
mod wrap;

#[cfg(feature = "emulator-tests")]
mod emulator;
83 changes: 83 additions & 0 deletions cmd/crates/soroban-test/tests/it/integration/emulator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use stellar_ledger::{Blob, Error};

use soroban_test::{AssertExt, TestEnv, LOCAL_NETWORK_PASSPHRASE};
use std::sync::Arc;

use soroban_cli::xdr::{
self, Memo, MuxedAccount, Operation, OperationBody, PaymentOp, Preconditions, SequenceNumber,
Transaction, TransactionExt, Uint256,
};

use stellar_ledger::emulator_test_support::*;

use test_case::test_case;

use crate::integration::util::{deploy_contract, DeployKind, HELLO_WORLD};

// #[test_case("nanos"; "when the device is NanoS")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can uncomment these other device model test cases

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was running into issues around the server locally. Since all the accounts share the same seed phrase it was acting as one account. I also tried updating the testcase to add an hd-path, but it was causes issues. So I just wanted one to work on CI and then was going to return to it.

#[test_case("nanox"; "when the device is NanoX")]
// #[test_case("nanosp"; "when the device is NanoS Plus")]
#[tokio::test]
async fn test_get_public_key(ledger_device_model: &str) {
willemneal marked this conversation as resolved.
Show resolved Hide resolved
let sandbox = Arc::new(TestEnv::new());
let container = TestEnv::speculos_container(ledger_device_model).await;
let host_port = container.get_host_port_ipv4(9998).await.unwrap();
let ui_host_port = container.get_host_port_ipv4(5000).await.unwrap();

let ledger = ledger(host_port).await;

let key = ledger.get_public_key(&0.into()).await.unwrap();
let account = &key.to_string();
sandbox.fund_account(account);
sandbox
.new_assert_cmd("contract")
.arg("install")
.args([
"--wasm",
HELLO_WORLD.path().as_os_str().to_str().unwrap(),
"--source",
account,
])
.assert()
.success();

let tx_simulated =
deploy_contract(&sandbox, HELLO_WORLD, DeployKind::SimOnly, Some(account)).await;
dbg!("{tx_simulated}");
let key = ledger.get_public_key(&0.into()).await.unwrap();
println!("{key}");
willemneal marked this conversation as resolved.
Show resolved Hide resolved
let sign = tokio::task::spawn_blocking({
let sandbox = Arc::clone(&sandbox);

move || {
sandbox
.new_assert_cmd("tx")
.arg("sign")
.arg("--sign-with-ledger")
.write_stdin(tx_simulated.as_bytes())
.env("SPECULOS_PORT", host_port.to_string())
.env("RUST_LOGS", "trace")
.assert()
.success()
.stdout_as_str()
}
});
let approve = tokio::task::spawn(approve_tx_hash_signature(
ui_host_port,
ledger_device_model.to_string(),
));

let response = sign.await.unwrap();
approve.await.unwrap();

dbg!("{tx_signed}");

sandbox
.clone()
.new_assert_cmd("tx")
.arg("send")
.write_stdin(response.as_bytes())
.assert()
.success()
.stdout(predicates::str::contains("SUCCESS"));
}
13 changes: 11 additions & 2 deletions cmd/crates/soroban-test/tests/it/integration/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,19 @@ async fn txn_hash() {
#[tokio::test]
async fn build_simulate_sign_send() {
let sandbox = &TestEnv::new();
build_sim_sign_send(sandbox, "test", "--sign-with-key=test").await;
}

pub(crate) async fn build_sim_sign_send(sandbox: &TestEnv, account: &str, sign_with: &str) {
sandbox
.new_assert_cmd("contract")
.arg("install")
.args(["--wasm", HELLO_WORLD.path().as_os_str().to_str().unwrap()])
.args([
"--wasm",
HELLO_WORLD.path().as_os_str().to_str().unwrap(),
"--source",
account,
])
.assert()
.success();

Expand All @@ -69,7 +78,7 @@ async fn build_simulate_sign_send() {
let tx_signed = sandbox
.new_assert_cmd("tx")
.arg("sign")
.arg("--sign-with-key=test")
.arg(sign_with)
.write_stdin(tx_simulated.as_bytes())
.assert()
.success()
Expand Down
14 changes: 6 additions & 8 deletions cmd/crates/stellar-ledger/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ rust-version.workspace = true
publish = false

[dependencies]
soroban-spec = { workspace = true }
thiserror = "1.0.32"
serde = "1.0.82"
serde_derive = "1.0.82"
Expand All @@ -26,7 +25,6 @@ ed25519-dalek = { workspace = true }
stellar-strkey = { workspace = true }
ledger-transport-hid = "0.10.0"
ledger-transport = "0.10.0"
sep5.workspace = true
slip10 = { package = "slipped10", version = "0.4.6" }
tracing = { workspace = true }
hex.workspace = true
Expand All @@ -35,26 +33,26 @@ bollard = { workspace = true }
home = "0.5.9"
tokio = { version = "1", features = ["full"] }
reqwest = { workspace = true, features = ["json"] }
soroban-rpc.workspace = true
phf = { version = "0.11.2", features = ["macros"] }
futures = "0.3.30"
phf = { version = "0.11.2", features = ["macros"], optional = true }
async-trait = { workspace = true }
testcontainers = { workspace = true, optional = true }

[dependencies.stellar-xdr]
workspace = true
features = ["curr", "std", "serde"]

[dev-dependencies]
env_logger = "0.11.3"
futures = "0.3.30"
log = "0.4.21"
once_cell = "1.19.0"
pretty_assertions = "1.2.1"
serial_test = "3.0.0"
httpmock = "0.7.0-rc.1"
test-case = "3.3.1"
testcontainers = "0.20.1"



[features]
emulator-tests = []
default = ["http-transport"]
emulator-tests = ["dep:testcontainers", "http-transport", "dep:phf"]
http-transport = []
7 changes: 7 additions & 0 deletions cmd/crates/stellar-ledger/src/emulator_test_support.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod http_transport;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should http_transport be under the emulator-tests feature flag too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant to add a http-transport feature. above it because some unit tests still needed it.

#[cfg(feature = "emulator-tests")]
pub mod speculos;
#[cfg(feature = "emulator-tests")]
pub mod util;
#[cfg(feature = "emulator-tests")]
pub use util::*;
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl Exchange for EmulatorHttpTransport {
let resp: Response = HttpClient::new()
.post(&self.url)
.headers(headers)
.timeout(Duration::from_secs(25))
.timeout(Duration::from_secs(60))
.json(&request)
.send()
.await
Expand Down
Loading
Loading