From 015435b96d85e1d4b96c657d33f00afcdb6d9efe Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Mon, 23 Sep 2024 14:43:35 +1000 Subject: [PATCH] move types into signer and replace existing signing logic --- cmd/soroban-cli/src/commands/tx/sign.rs | 15 ++-- cmd/soroban-cli/src/config/mod.rs | 14 ++-- cmd/soroban-cli/src/config/sign_with.rs | 11 ++- cmd/soroban-cli/src/signer.rs | 88 ++++++++++++++++++----- cmd/soroban-cli/src/signer/types.rs | 93 ------------------------- 5 files changed, 88 insertions(+), 133 deletions(-) delete mode 100644 cmd/soroban-cli/src/signer/types.rs diff --git a/cmd/soroban-cli/src/commands/tx/sign.rs b/cmd/soroban-cli/src/commands/tx/sign.rs index bae7cad70..f5987ab34 100644 --- a/cmd/soroban-cli/src/commands/tx/sign.rs +++ b/cmd/soroban-cli/src/commands/tx/sign.rs @@ -33,15 +33,12 @@ 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, - ) - .await?; + 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())?.trim()); Ok(()) } diff --git a/cmd/soroban-cli/src/config/mod.rs b/cmd/soroban-cli/src/config/mod.rs index 86055a101..c0dc2d694 100644 --- a/cmd/soroban-cli/src/config/mod.rs +++ b/cmd/soroban-cli/src/config/mod.rs @@ -4,9 +4,11 @@ use clap::{arg, command}; use serde::{Deserialize, Serialize}; use soroban_rpc::Client; +use soroban_sdk::xdr::{TransactionV1Envelope, VecM}; use crate::{ - signer, + print::Print, + signer::{self, LocalKey, SignerKind, StellarSigner}, xdr::{Transaction, TransactionEnvelope}, Pwd, }; @@ -66,10 +68,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 = StellarSigner { + kind: SignerKind::Local(LocalKey::new(key, false)), + printer: Print::new(false), + }; + Ok(signer.sign_tx(tx, network)?) } pub async fn sign_soroban_authorizations( diff --git a/cmd/soroban-cli/src/config/sign_with.rs b/cmd/soroban-cli/src/config/sign_with.rs index b86047a1c..c4f4e6c95 100644 --- a/cmd/soroban-cli/src/config/sign_with.rs +++ b/cmd/soroban-cli/src/config/sign_with.rs @@ -1,7 +1,4 @@ -use crate::{ - signer::{self, types::sign_tx_env}, - xdr::TransactionEnvelope, -}; +use crate::{signer, xdr::TransactionEnvelope}; use clap::arg; use super::{ @@ -15,7 +12,7 @@ pub enum Error { #[error(transparent)] Network(#[from] network::Error), #[error(transparent)] - Signer(#[from] signer::types::Error), + Signer(#[from] signer::Error), #[error(transparent)] Secret(#[from] secret::Error), #[error(transparent)] @@ -49,7 +46,7 @@ pub struct Args { } impl Args { - pub async fn sign_tx_env( + pub fn sign_tx_env( &self, tx: TransactionEnvelope, locator: &locator::Args, @@ -59,6 +56,6 @@ impl Args { 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, false, quiet)?; - Ok(sign_tx_env(&signer, tx, network).await?) + Ok(signer.sign_tx_env(tx, network)?) } } diff --git a/cmd/soroban-cli/src/signer.rs b/cmd/soroban-cli/src/signer.rs index 9097b4a5f..eae9fae30 100644 --- a/cmd/soroban-cli/src/signer.rs +++ b/cmd/soroban-cli/src/signer.rs @@ -6,12 +6,10 @@ use soroban_env_host::xdr::{ InvokeHostFunctionOp, Limits, Operation, OperationBody, PublicKey, ScAddress, ScMap, ScSymbol, ScVal, Signature, SignatureHint, SorobanAddressCredentials, SorobanAuthorizationEntry, SorobanAuthorizedFunction, SorobanCredentials, Transaction, TransactionEnvelope, - TransactionV1Envelope, Uint256, WriteXdr, + TransactionV1Envelope, Uint256, VecM, WriteXdr, }; -pub mod types; -use crate::utils::transaction_hash; -pub use types::{LocalKey, SignerKind, StellarSigner}; +use crate::{config::network::Network, print::Print, utils::transaction_hash}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -27,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 { @@ -192,21 +192,71 @@ fn sign_soroban_authorization_entry( Ok(auth) } -pub fn sign_tx( - 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); +pub struct StellarSigner { + 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()?), - }; +pub enum SignerKind { + Local(LocalKey), +} + +impl StellarSigner { + 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 with hash: {}", + 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 struct LocalKey { + key: ed25519_dalek::SigningKey, + #[allow(dead_code)] + prompt: bool, +} + +impl LocalKey { + pub fn new(key: ed25519_dalek::SigningKey, prompt: bool) -> Self { + Self { key, prompt } + } +} - Ok(TransactionEnvelope::Tx(TransactionV1Envelope { - tx: tx.clone(), - signatures: [decorated_signature].try_into()?, - })) +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/signer/types.rs b/cmd/soroban-cli/src/signer/types.rs deleted file mode 100644 index 610674637..000000000 --- a/cmd/soroban-cli/src/signer/types.rs +++ /dev/null @@ -1,93 +0,0 @@ -use ed25519_dalek::ed25519::signature::Signer; - -use crate::{ - config::network::Network, - print::Print, - utils::transaction_hash, - xdr::{ - self, DecoratedSignature, Signature, SignatureHint, TransactionEnvelope, - TransactionV1Envelope, - }, -}; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("Contract addresses are not supported to sign auth entries {address}")] - ContractAddressAreNotSupported { address: String }, - #[error(transparent)] - Ed25519(#[from] ed25519_dalek::SignatureError), - #[error("Missing signing key for account {address}")] - MissingSignerForAddress { address: String }, - #[error(transparent)] - Xdr(#[from] xdr::Error), - #[error(transparent)] - Rpc(#[from] crate::rpc::Error), - #[error("User cancelled signing, perhaps need to remove --check")] - UserCancelledSigning, - #[error("Only Transaction envelope V1 type is supported")] - UnsupportedTransactionEnvelopeType, -} - -pub struct StellarSigner { - pub kind: SignerKind, - pub printer: Print, -} - -pub enum SignerKind { - Local(LocalKey), -} - -impl StellarSigner { - pub fn sign_tx( - &self, - txn: &xdr::Transaction, - network: &Network, - ) -> Result { - let tx_hash = transaction_hash(txn, &network.network_passphrase)?; - let hex_hash = hex::encode(tx_hash); - self.printer - .infoln(format!("Signing transaction with hash: {hex_hash}")); - match &self.kind { - SignerKind::Local(key) => key.sign_tx_hash(tx_hash), - } - } -} - -pub async fn sign_tx_env( - signer: &StellarSigner, - txn_env: TransactionEnvelope, - network: &Network, -) -> Result { - match txn_env { - TransactionEnvelope::Tx(TransactionV1Envelope { tx, signatures }) => { - let decorated_signature = signer.sign_tx(&tx, network)?; - let mut sigs = signatures.to_vec(); - sigs.push(decorated_signature); - Ok(TransactionEnvelope::Tx(TransactionV1Envelope { - tx, - signatures: sigs.try_into()?, - })) - } - _ => Err(Error::UnsupportedTransactionEnvelopeType), - } -} - -pub struct LocalKey { - key: ed25519_dalek::SigningKey, - #[allow(dead_code)] - prompt: bool, -} - -impl LocalKey { - pub fn new(key: ed25519_dalek::SigningKey, prompt: bool) -> Self { - Self { key, prompt } - } -} - -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 }) - } -}