Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/ledger-emulator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
sudo apt update && sudo apt install -y libudev-dev libdbus-1-dev
- run: |
cargo test --manifest-path cmd/crates/stellar-ledger/Cargo.toml --features "emulator-tests" -- --nocapture
- run: cargo build --features emulator-tests
- run: cargo build --features emulator-tests,additional-libs
- run: |
cargo test --features emulator-tests --package soroban-test --test it -- emulator
4 changes: 2 additions & 2 deletions cmd/soroban-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ version_lt_23 = []
version_gte_23 = []
opt = ["dep:wasm-opt"]
emulator-tests = ["stellar-ledger/emulator-tests"]
additional-libs = ["dep:keyring"]
additional-libs = ["dep:keyring", "dep:stellar-ledger"]

[dependencies]
stellar-xdr = { workspace = true, features = ["cli"] }
Expand All @@ -53,7 +53,7 @@ soroban-ledger-snapshot = { workspace = true }
stellar-strkey = { workspace = true }
soroban-sdk = { workspace = true }
soroban-rpc = { workspace = true }
stellar-ledger = { workspace = true }
stellar-ledger = { workspace = true, optional = true }

clap = { workspace = true, features = [
"derive",
Expand Down
4 changes: 3 additions & 1 deletion cmd/soroban-cli/src/config/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub enum Error {
InvalidKeyName(String),
#[error("Ledger not supported in this context")]
LedgerNotSupported,
#[error(transparent)]
Ledger(#[from] signer::ledger::Error),
}

impl FromStr for UnresolvedMuxedAccount {
Expand Down Expand Up @@ -85,7 +87,7 @@ impl UnresolvedMuxedAccount {
) -> Result<xdr::MuxedAccount, Error> {
match self {
UnresolvedMuxedAccount::Ledger(hd_path) => Ok(xdr::MuxedAccount::Ed25519(
ledger(*hd_path).await?.public_key().await?.0.into(),
ledger::new(*hd_path).await?.public_key().await?.0.into(),
)),
UnresolvedMuxedAccount::Resolved(_) | UnresolvedMuxedAccount::AliasOrSecret(_) => {
self.resolve_muxed_account_sync(locator, hd_path)
Expand Down
6 changes: 3 additions & 3 deletions cmd/soroban-cli/src/config/secret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ pub enum Error {
InvalidSecretOrSeedPhrase,
#[error(transparent)]
Signer(#[from] signer::Error),

#[error("Ledger does not reveal secret key")]
LedgerDoesNotRevealSecretKey,

#[error(transparent)]
SecureStore(#[from] secure_store::Error),
#[error("Secure Store does not reveal secret key")]
SecureStoreDoesNotRevealSecretKey,
#[error(transparent)]
Ledger(#[from] signer::ledger::Error),
}

#[derive(Debug, clap::Args, Clone)]
Expand Down Expand Up @@ -143,7 +143,7 @@ impl Secret {
.unwrap_or_default()
.try_into()
.expect("uszie bigger than u32");
SignerKind::Ledger(ledger(hd_path).await?)
SignerKind::Ledger(ledger::new(hd_path).await?)
}
Secret::SecureStore { entry_name } => SignerKind::SecureStore(SecureStoreEntry {
name: entry_name.to_string(),
Expand Down
4 changes: 3 additions & 1 deletion cmd/soroban-cli/src/config/sign_with.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum Error {
StrKey(#[from] stellar_strkey::DecodeError),
#[error(transparent)]
Xdr(#[from] xdr::Error),
#[error(transparent)]
Ledger(#[from] signer::ledger::Error),
}

#[derive(Debug, clap::Args, Clone, Default)]
Expand Down Expand Up @@ -72,7 +74,7 @@ impl Args {
print,
}
} else if self.sign_with_ledger {
let ledger = ledger(
let ledger = ledger::new(
self.hd_path
.unwrap_or_default()
.try_into()
Expand Down
3 changes: 1 addition & 2 deletions cmd/soroban-cli/src/signer/keyring.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::print::Print;
use ed25519_dalek::Signer;
use keyring::Entry;
use sep5::seed_phrase::SeedPhrase;
use zeroize::Zeroize;

use keyring::Entry;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[cfg(feature = "additional-libs")]
Expand Down
150 changes: 150 additions & 0 deletions cmd/soroban-cli/src/signer/ledger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
use crate::xdr::{self, DecoratedSignature, Transaction};

pub use ledger_impl::*;

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Ledger Device keys are not allowed: additional-libs feature must be enabled")]
FeatureNotEnabled,

#[cfg(feature = "additional-libs")]
#[error(transparent)]
StellarLedger(#[from] stellar_ledger::Error),

#[error(transparent)]
TryFromSlice(#[from] std::array::TryFromSliceError),

#[error(transparent)]
Xdr(#[from] xdr::Error),
}

#[cfg(feature = "additional-libs")]
mod ledger_impl {
use super::*;
use crate::xdr::{Hash, Signature, SignatureHint};
use sha2::{Digest, Sha256};
use stellar_ledger::{Blob as _, Exchange, LedgerSigner};

#[cfg(not(feature = "emulator-tests"))]
pub type LedgerType = Ledger<stellar_ledger::TransportNativeHID>;
#[cfg(feature = "emulator-tests")]
pub type LedgerType = Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>;

pub struct Ledger<T: Exchange> {
pub(crate) index: u32,
pub(crate) signer: LedgerSigner<T>,
}

#[cfg(not(feature = "emulator-tests"))]
pub async fn new(hd_path: u32) -> Result<Ledger<stellar_ledger::TransportNativeHID>, Error> {
let signer = stellar_ledger::native()?;
Ok(Ledger {
index: hd_path,
signer,
})
}

#[cfg(feature = "emulator-tests")]
pub async fn new(
hd_path: u32,
) -> Result<Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>, Error>
{
use stellar_ledger::emulator_test_support::ledger as emulator_ledger;
// port from SPECULOS_PORT ENV var
let host_port: u16 = std::env::var("SPECULOS_PORT")
.expect("SPECULOS_PORT env var not set")
.parse()
.expect("port must be a number");
let signer = emulator_ledger(host_port).await;

Ok(Ledger {
index: hd_path,
signer,
})
}

impl<T: Exchange> Ledger<T> {
pub async fn sign_transaction_hash(
&self,
tx_hash: &[u8; 32],
) -> Result<DecoratedSignature, Error> {
let key = self.public_key().await?;
let hint = SignatureHint(key.0[28..].try_into()?);
let signature = Signature(
self.signer
.sign_transaction_hash(self.index, tx_hash)
.await?
.try_into()?,
);
Ok(DecoratedSignature { hint, signature })
}

pub async fn sign_transaction(
&self,
tx: Transaction,
network_passphrase: &str,
) -> Result<DecoratedSignature, Error> {
let network_id = Hash(Sha256::digest(network_passphrase).into());
let signature = self
.signer
.sign_transaction(self.index, tx, network_id)
.await?;
let key = self.public_key().await?;
let hint = SignatureHint(key.0[28..].try_into()?);
let signature = Signature(signature.try_into()?);
Ok(DecoratedSignature { hint, signature })
}

pub async fn public_key(&self) -> Result<stellar_strkey::ed25519::PublicKey, Error> {
Ok(self.signer.get_public_key(&self.index.into()).await?)
}
}
}

#[cfg(not(feature = "additional-libs"))]
mod ledger_impl {
use super::{DecoratedSignature, Error, Transaction};
use std::marker::PhantomData;

pub type LedgerType = Ledger<GenericExchange>;

pub trait Exchange {}
pub struct Ledger<T: Exchange> {
_marker: PhantomData<T>,
}

#[allow(clippy::unused_async)]
pub async fn new(_hd_path: u32) -> Result<Ledger<GenericExchange>, Error> {
Err(Error::FeatureNotEnabled)
}

impl<T: Exchange> Ledger<T> {
#[allow(clippy::unused_async)]
pub async fn sign_transaction_hash(
&self,
_tx_hash: &[u8; 32],
) -> Result<DecoratedSignature, Error> {
Err(Error::FeatureNotEnabled)
}

#[allow(clippy::unused_async)]
pub async fn sign_transaction(
&self,
_tx: Transaction,
_network_passphrase: &str,
) -> Result<DecoratedSignature, Error> {
Err(Error::FeatureNotEnabled)
}

#[allow(clippy::unused_async)]
pub async fn public_key(&self) -> Result<stellar_strkey::ed25519::PublicKey, Error> {
Err(Error::FeatureNotEnabled)
}
}

pub struct GenericExchange {}

impl Exchange for GenericExchange {}

impl GenericExchange {}
}
88 changes: 7 additions & 81 deletions cmd/soroban-cli/src/signer/mod.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
use ed25519_dalek::ed25519::signature::Signer as _;
use sha2::{Digest, Sha256};

use crate::xdr::{
self, AccountId, DecoratedSignature, Hash, HashIdPreimage, HashIdPreimageSorobanAuthorization,
InvokeHostFunctionOp, Limits, Operation, OperationBody, PublicKey, ScAddress, ScMap, ScSymbol,
ScVal, Signature, SignatureHint, SorobanAddressCredentials, SorobanAuthorizationEntry,
SorobanAuthorizedFunction, SorobanCredentials, Transaction, TransactionEnvelope,
TransactionV1Envelope, Uint256, VecM, WriteXdr,
};
use stellar_ledger::{Blob as _, Exchange, LedgerSigner};
use ed25519_dalek::ed25519::signature::Signer as _;
use sha2::{Digest, Sha256};

use crate::{config::network::Network, print::Print, utils::transaction_hash};

pub mod secure_store;
pub mod ledger;

#[cfg(feature = "additional-libs")]
mod keyring;
pub mod secure_store;

#[derive(thiserror::Error, Debug)]
pub enum Error {
Expand All @@ -30,8 +29,6 @@ pub enum Error {
#[error("User cancelled signing, perhaps need to add -y")]
UserCancelledSigning,
#[error(transparent)]
Ledger(#[from] stellar_ledger::Error),
#[error(transparent)]
Xdr(#[from] xdr::Error),
#[error("Only Transaction envelope V1 type is supported")]
UnsupportedTransactionEnvelopeType,
Expand All @@ -43,6 +40,8 @@ pub enum Error {
ReturningSignatureFromLab,
#[error(transparent)]
SecureStore(#[from] secure_store::Error),
#[error(transparent)]
Ledger(#[from] ledger::Error),
}

fn requires_auth(txn: &Transaction) -> Option<xdr::Operation> {
Expand Down Expand Up @@ -216,10 +215,7 @@ pub struct Signer {
#[allow(clippy::module_name_repetitions, clippy::large_enum_variant)]
pub enum SignerKind {
Local(LocalKey),
#[cfg(not(feature = "emulator-tests"))]
Ledger(Ledger<stellar_ledger::TransportNativeHID>),
#[cfg(feature = "emulator-tests")]
Ledger(Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>),
Ledger(ledger::LedgerType),
Lab,
SecureStore(SecureStoreEntry),
}
Expand Down Expand Up @@ -269,76 +265,6 @@ pub struct LocalKey {
pub key: ed25519_dalek::SigningKey,
}

#[allow(dead_code)]
pub struct Ledger<T: Exchange> {
pub(crate) index: u32,
pub(crate) signer: LedgerSigner<T>,
}

impl<T: Exchange> Ledger<T> {
pub async fn sign_transaction_hash(
&self,
tx_hash: &[u8; 32],
) -> Result<DecoratedSignature, Error> {
let key = self.public_key().await?;
let hint = SignatureHint(key.0[28..].try_into()?);
let signature = Signature(
self.signer
.sign_transaction_hash(self.index, tx_hash)
.await?
.try_into()?,
);
Ok(DecoratedSignature { hint, signature })
}

pub async fn sign_transaction(
&self,
tx: Transaction,
network_passphrase: &str,
) -> Result<DecoratedSignature, Error> {
let network_id = Hash(Sha256::digest(network_passphrase).into());
let signature = self
.signer
.sign_transaction(self.index, tx, network_id)
.await?;
let key = self.public_key().await?;
let hint = SignatureHint(key.0[28..].try_into()?);
let signature = Signature(signature.try_into()?);
Ok(DecoratedSignature { hint, signature })
}

pub async fn public_key(&self) -> Result<stellar_strkey::ed25519::PublicKey, Error> {
Ok(self.signer.get_public_key(&self.index.into()).await?)
}
}

#[cfg(not(feature = "emulator-tests"))]
pub async fn ledger(hd_path: u32) -> Result<Ledger<stellar_ledger::TransportNativeHID>, Error> {
let signer = stellar_ledger::native()?;
Ok(Ledger {
index: hd_path,
signer,
})
}

#[cfg(feature = "emulator-tests")]
pub async fn ledger(
hd_path: u32,
) -> Result<Ledger<stellar_ledger::emulator_test_support::http_transport::Emulator>, Error> {
use stellar_ledger::emulator_test_support::ledger as emulator_ledger;
// port from SPECULOS_PORT ENV var
let host_port: u16 = std::env::var("SPECULOS_PORT")
.expect("SPECULOS_PORT env var not set")
.parse()
.expect("port must be a number");
let signer = emulator_ledger(host_port).await;

Ok(Ledger {
index: hd_path,
signer,
})
}

impl LocalKey {
pub fn sign_tx_hash(&self, tx_hash: [u8; 32]) -> Result<DecoratedSignature, Error> {
let hint = SignatureHint(self.key.verifying_key().to_bytes()[28..].try_into()?);
Expand Down