diff --git a/cmd/soroban-cli/src/commands/tx/hash.rs b/cmd/soroban-cli/src/commands/tx/hash.rs index dfffb623e..8d8ec6d82 100644 --- a/cmd/soroban-cli/src/commands/tx/hash.rs +++ b/cmd/soroban-cli/src/commands/tx/hash.rs @@ -1,6 +1,6 @@ use hex; -use crate::{commands::global, config::network, signer::types::transaction_hash}; +use crate::{commands::global, config::network, utils::transaction_hash}; #[derive(thiserror::Error, Debug)] pub enum Error { diff --git a/cmd/soroban-cli/src/config/secret.rs b/cmd/soroban-cli/src/config/secret.rs index a4b1069c5..78877faf3 100644 --- a/cmd/soroban-cli/src/config/secret.rs +++ b/cmd/soroban-cli/src/config/secret.rs @@ -4,7 +4,7 @@ use std::{io::Write, str::FromStr}; use stellar_strkey::ed25519::{PrivateKey, PublicKey}; use crate::print::Print; -use crate::signer::types::transaction_hash; +use crate::utils::transaction_hash; use crate::xdr::{self, DecoratedSignature}; use crate::{ signer::{self, LocalKey}, @@ -188,7 +188,7 @@ impl signer::SignTx for StellarSigner { self.printer .infoln(format!("Signing transaction with hash: {hex_hash}")); match &self.kind { - SignerKind::Local(key) => key.sign_tx(txn, network).await, + SignerKind::Local(key) => key.sign_tx_hash(tx_hash), } } } diff --git a/cmd/soroban-cli/src/print.rs b/cmd/soroban-cli/src/print.rs index 2a95267d0..5b98687bd 100644 --- a/cmd/soroban-cli/src/print.rs +++ b/cmd/soroban-cli/src/print.rs @@ -3,7 +3,7 @@ use std::{env, fmt::Display}; use soroban_env_host::xdr::{Error as XdrError, Transaction}; use crate::{ - config::network::Network, signer::types::transaction_hash, utils::explorer_url_for_transaction, + 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 b2f205a63..d56e2ab1d 100644 --- a/cmd/soroban-cli/src/signer.rs +++ b/cmd/soroban-cli/src/signer.rs @@ -5,12 +5,12 @@ use soroban_env_host::xdr::{ self, AccountId, DecoratedSignature, Hash, HashIdPreimage, HashIdPreimageSorobanAuthorization, InvokeHostFunctionOp, Limits, Operation, OperationBody, PublicKey, ScAddress, ScMap, ScSymbol, ScVal, Signature, SignatureHint, SorobanAddressCredentials, SorobanAuthorizationEntry, - SorobanAuthorizedFunction, SorobanCredentials, TransactionEnvelope, - TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, - TransactionV1Envelope, Uint256, WriteXdr, + SorobanAuthorizedFunction, SorobanCredentials, TransactionEnvelope, TransactionV1Envelope, + Uint256, WriteXdr, }; pub mod types; +use crate::utils::transaction_hash; pub use types::{LocalKey, SignTx}; #[derive(thiserror::Error, Debug)] @@ -197,7 +197,7 @@ pub fn sign_tx( tx: &xdr::Transaction, network_passphrase: &str, ) -> Result { - let tx_hash = hash(tx, network_passphrase)?; + let tx_hash = transaction_hash(tx, network_passphrase)?; let tx_signature = key.sign(&tx_hash); let decorated_signature = DecoratedSignature { @@ -210,11 +210,3 @@ pub fn sign_tx( signatures: [decorated_signature].try_into()?, })) } - -pub fn hash(tx: &xdr::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()) -} diff --git a/cmd/soroban-cli/src/signer/types.rs b/cmd/soroban-cli/src/signer/types.rs index b756ccf81..e44935b31 100644 --- a/cmd/soroban-cli/src/signer/types.rs +++ b/cmd/soroban-cli/src/signer/types.rs @@ -1,12 +1,10 @@ use ed25519_dalek::ed25519::signature::Signer; -use sha2::{Digest, Sha256}; use crate::{ config::network::Network, xdr::{ - self, DecoratedSignature, Limits, Signature, SignatureHint, TransactionEnvelope, - TransactionSignaturePayload, TransactionSignaturePayloadTaggedTransaction, - TransactionV1Envelope, WriteXdr, + self, DecoratedSignature, Signature, SignatureHint, TransactionEnvelope, + TransactionV1Envelope, }, }; @@ -28,19 +26,6 @@ pub enum Error { UnsupportedTransactionEnvelopeType, } -/// Calculate the hash of a Transaction -pub fn transaction_hash( - txn: &xdr::Transaction, - network_passphrase: &str, -) -> Result<[u8; 32], xdr::Error> { - let signature_payload = TransactionSignaturePayload { - network_id: hash(network_passphrase), - tagged_transaction: TransactionSignaturePayloadTaggedTransaction::Tx(txn.clone()), - }; - let hash = Sha256::digest(signature_payload.to_xdr(Limits::none())?).into(); - Ok(hash) -} - pub async fn sign_tx_env( signer: &(impl SignTx + std::marker::Sync), txn_env: TransactionEnvelope, @@ -60,10 +45,6 @@ pub async fn sign_tx_env( } } -fn hash(network_passphrase: &str) -> xdr::Hash { - xdr::Hash(Sha256::digest(network_passphrase.as_bytes()).into()) -} - /// A trait for signing Stellar transactions and Soroban authorization entries #[async_trait::async_trait] pub trait SignTx { @@ -92,22 +73,14 @@ impl LocalKey { } } -#[async_trait::async_trait] -impl SignTx for LocalKey { - async fn sign_tx( - &self, - txn: &xdr::Transaction, - Network { - network_passphrase, .. - }: &Network, - ) -> Result { - let hash = transaction_hash(txn, network_passphrase)?; +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() .unwrap(), ); - let signature = Signature(self.key.sign(&hash).to_bytes().to_vec().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 75a18d5e1..f5827f75b 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -4,7 +4,8 @@ use stellar_strkey::ed25519::PrivateKey; use soroban_env_host::xdr::{ Asset, ContractIdPreimage, Error as XdrError, Hash, HashIdPreimage, HashIdPreimageContractId, - Limits, ScMap, ScMapEntry, ScVal, WriteXdr, + Limits, ScMap, ScMapEntry, ScVal, Transaction, TransactionSignaturePayload, + TransactionSignaturePayloadTaggedTransaction, WriteXdr, }; pub use soroban_spec_tools::contract as contract_spec; @@ -18,6 +19,17 @@ pub fn contract_hash(contract: &[u8]) -> Result { Ok(Hash(Sha256::digest(contract).into())) } +/// # Errors +/// +/// Might return an error +pub fn transaction_hash(tx: &Transaction, network_passphrase: &str) -> Result<[u8; 32], XdrError> { + 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()) +} + static EXPLORERS: phf::Map<&'static str, &'static str> = phf_map! { "Test SDF Network ; September 2015" => "https://stellar.expert/explorer/testnet", "Public Global Stellar Network ; September 2015" => "https://stellar.expert/explorer/public",