Skip to content

Commit

Permalink
Add option for compose transaction to only return a tx
Browse files Browse the repository at this point in the history
  • Loading branch information
OBorce committed Jan 31, 2024
1 parent 4c9d889 commit 068ac7f
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 40 deletions.
5 changes: 3 additions & 2 deletions test/functional/test_framework/wallet_cli_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,9 @@ async def get_raw_signed_transaction(self, tx_id: str) -> str:
async def send_to_address(self, address: str, amount: int, selected_utxos: List[UtxoOutpoint] = []) -> str:
return await self._write_command(f"address-send {address} {amount} {' '.join(map(str, selected_utxos))}\n")

async def compose_transaction(self, outputs: List[TxOutput], selected_utxos: List[UtxoOutpoint]) -> str:
return await self._write_command(f"transaction-compose {' '.join(map(str, outputs))} --utxos {' --utxos '.join(map(str, selected_utxos))}\n")
async def compose_transaction(self, outputs: List[TxOutput], selected_utxos: List[UtxoOutpoint], only_transaction: bool = False) -> str:
only_tx = "--only-transaction" if only_transaction else ""
return await self._write_command(f"transaction-compose {' '.join(map(str, outputs))} --utxos {' --utxos '.join(map(str, selected_utxos))} {only_tx}\n")

async def send_tokens_to_address(self, token_id: str, address: str, amount: Union[float, str]):
return await self._write_command(f"token-send {token_id} {address} {amount}\n")
Expand Down
12 changes: 10 additions & 2 deletions test/functional/wallet_tx_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,21 @@ def make_output(pub_key_bytes):
assert_equal(len(utxos), len(addresses))

# compose a transaction with all our utxos and n outputs to the other acc and 1 as change
output = await wallet.compose_transaction(outputs, utxos)
self.log.info(f"compose output: '{output}'")
output = await wallet.compose_transaction(outputs, utxos, True)
assert_in("The hex encoded transaction is", output)
# check the fees include the 0.1 + any extra utxos
assert_in(f"Coins amount: {((len(addresses) - (num_outputs + 1))*coins_to_send)}.1", output)
encoded_tx = output.split('\n')[1]

output = await wallet.compose_transaction(outputs, utxos, False)
assert_in("The hex encoded transaction is", output)
# check the fees include the 0.1 + any extra utxos
assert_in(f"Coins amount: {((len(addresses) - (num_outputs + 1))*coins_to_send)}.1", output)
encoded_ptx = output.split('\n')[1]

# partially_signed_tx is bigger than just the tx
assert len(encoded_tx) < len(encoded_ptx)

output = await wallet.sign_raw_transaction(encoded_tx)
self.log.info(f"sign output: '{output}'")
assert_in("The transaction has been fully signed signed", output)
Expand Down
38 changes: 25 additions & 13 deletions wallet/wallet-cli-lib/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ use mempool::tx_options::TxOptionsOverrides;
use p2p_types::{bannable_address::BannableAddress, ip_or_socket_address::IpOrSocketAddress};
use serialization::{hex::HexEncode, hex_encoded::HexEncoded};
use utils::qrcode::QrCode;
use wallet::{account::PartiallySignedTransaction, version::get_version, WalletError};
use wallet::{
account::{PartiallySignedTransaction, TransactionToSign},
version::get_version,
WalletError,
};
use wallet_controller::{ControllerConfig, NodeInterface, PeerId, DEFAULT_ACCOUNT_INDEX};
use wallet_rpc_lib::{
config::WalletRpcConfig, types::NewTransaction, CreatedWallet, WalletRpc, WalletRpcServer,
Expand Down Expand Up @@ -628,6 +632,9 @@ pub enum WalletCommand {
/// block(000000000000000000059fa50103b9683e51e5aba83b8a34c9b98ce67d66136c,2)
#[arg(long="utxos", default_values_t = Vec::<String>::new())]
utxos: Vec<String>,

#[arg(long = "only-transaction", default_value_t = false)]
only_transaction: bool,
},

/// Abandon an unconfirmed transaction in the wallet database, and make the consumed inputs available to be used again
Expand Down Expand Up @@ -773,11 +780,6 @@ where
.ok_or(WalletCliError::NoWallet)
}

pub fn tx_submitted_command() -> ConsoleCommand {
let status_text = "The transaction was submitted successfully";
ConsoleCommand::Print(status_text.to_owned())
}

pub fn new_tx_submitted_command(new_tx: NewTransaction) -> ConsoleCommand {
let status_text = format!(
"The transaction was submitted successfully with ID:\n{}",
Expand Down Expand Up @@ -1209,13 +1211,18 @@ where
}

WalletCommand::SubmitTransaction { transaction } => {
self.wallet_rpc
let new_tx = self
.wallet_rpc
.submit_raw_transaction(transaction, TxOptionsOverrides::default())
.await?;
Ok(Self::tx_submitted_command())
Ok(Self::new_tx_submitted_command(new_tx))
}

WalletCommand::TransactionCompose { outputs, utxos } => {
WalletCommand::TransactionCompose {
outputs,
utxos,
only_transaction,
} => {
eprintln!("outputs: {outputs:?}");
eprintln!("utxos: {utxos:?}");
let outputs: Vec<TxOutput> = outputs
Expand All @@ -1229,11 +1236,16 @@ where
.collect::<Result<Vec<_>, WalletCliError<N>>>(
)?;

let (tx, fees) = self.wallet_rpc.compose_transaction(input_utxos, outputs).await?;
let (tx, fees) = self
.wallet_rpc
.compose_transaction(input_utxos, outputs, only_transaction)
.await?;
let (coins, tokens) = fees.into_coins_and_tokens();

let mut output =
format!("The hex encoded transaction is:\n{}\n", HexEncoded::new(tx));
let encoded_tx = match tx {
TransactionToSign::Tx(tx) => HexEncoded::new(tx).to_string(),
TransactionToSign::Partial(tx) => HexEncoded::new(tx).to_string(),
};
let mut output = format!("The hex encoded transaction is:\n{encoded_tx}\n");

writeln!(
&mut output,
Expand Down
40 changes: 24 additions & 16 deletions wallet/wallet-controller/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ pub use node_comm::{
use wallet::{
account::{
currency_grouper::{self, Currency},
PartiallySignedTransaction,
PartiallySignedTransaction, TransactionToSign,
},
get_tx_output_destination,
wallet::WalletPoolsFilter,
Expand Down Expand Up @@ -617,7 +617,8 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> Controll
&self,
inputs: Vec<UtxoOutPoint>,
outputs: Vec<TxOutput>,
) -> Result<(PartiallySignedTransaction, Balances), ControllerError<T>> {
only_transaction: bool,
) -> Result<(TransactionToSign, Balances), ControllerError<T>> {
let input_utxos = self.fetch_utxos(&inputs).await?;
let fees = self.get_fees(&input_utxos, &outputs)?;
let fees = into_balances(&self.rpc_client, &self.chain_config, fees).await?;
Expand All @@ -628,22 +629,29 @@ impl<T: NodeInterface + Clone + Send + Sync + 'static, W: WalletEvents> Controll
let tx = Transaction::new(0, inputs, outputs)
.map_err(|err| ControllerError::WalletError(WalletError::TransactionCreation(err)))?;

let destinations = input_utxos
.iter()
.map(|txo| {
get_tx_output_destination(txo, &|_| None)
.ok_or_else(|| WalletError::UnsupportedTransactionOutput(Box::new(txo.clone())))
})
.collect::<Result<Vec<_>, WalletError>>()
let tx = if only_transaction {
TransactionToSign::Tx(tx)
} else {
let destinations = input_utxos
.iter()
.map(|txo| {
get_tx_output_destination(txo, &|_| None).ok_or_else(|| {
WalletError::UnsupportedTransactionOutput(Box::new(txo.clone()))
})
})
.collect::<Result<Vec<_>, WalletError>>()
.map_err(ControllerError::WalletError)?;

let tx = PartiallySignedTransaction::new(
tx,
vec![None; num_inputs],
input_utxos.into_iter().map(Option::Some).collect(),
destinations.into_iter().map(Option::Some).collect(),
)
.map_err(ControllerError::WalletError)?;

let tx = PartiallySignedTransaction::new(
tx,
vec![None; num_inputs],
input_utxos.into_iter().map(Option::Some).collect(),
destinations.into_iter().map(Option::Some).collect(),
)
.map_err(ControllerError::WalletError)?;
TransactionToSign::Partial(tx)
};

Ok((tx, fees))
}
Expand Down
2 changes: 1 addition & 1 deletion wallet/wallet-rpc-lib/src/rpc/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ trait WalletRpc {
&self,
tx: HexEncoded<SignedTransaction>,
options: TxOptionsOverrides,
) -> rpc::RpcResult<()>;
) -> rpc::RpcResult<NewTransaction>;

#[method(name = "address_send")]
async fn send_coins(
Expand Down
17 changes: 12 additions & 5 deletions wallet/wallet-rpc-lib/src/rpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ use common::{
Block, ChainConfig, DelegationId, Destination, GenBlock, PoolId, SignedTransaction,
Transaction, TxOutput, UtxoOutPoint,
},
primitives::{id::WithId, per_thousand::PerThousand, Amount, BlockHeight, DecimalAmount, Id},
primitives::{
id::WithId, per_thousand::PerThousand, Amount, BlockHeight, DecimalAmount, Id, Idable,
},
};
pub use interface::WalletRpcServer;
pub use rpc::{rpc_creds::RpcCreds, Rpc};
Expand Down Expand Up @@ -353,15 +355,17 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static> WalletRpc<N> {
&self,
tx: HexEncoded<SignedTransaction>,
options: TxOptionsOverrides,
) -> WRpcResult<(), N> {
) -> WRpcResult<NewTransaction, N> {
let tx = tx.take();
let block_height = self.best_block().await?.height;
check_transaction(&self.chain_config, block_height, &tx).map_err(|err| {
RpcError::Controller(ControllerError::WalletError(
WalletError::InvalidTransaction(err),
))
})?;
self.node.submit_transaction(tx, options).await.map_err(RpcError::RpcError)
let tx_id = tx.transaction().get_id();
self.node.submit_transaction(tx, options).await.map_err(RpcError::RpcError)?;
Ok(NewTransaction { tx_id })
}

pub async fn sign_raw_transaction(
Expand Down Expand Up @@ -695,10 +699,13 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static> WalletRpc<N> {
&self,
inputs: Vec<UtxoOutPoint>,
outputs: Vec<TxOutput>,
) -> WRpcResult<(PartiallySignedTransaction, Balances), N> {
only_transaction: bool,
) -> WRpcResult<(TransactionToSign, Balances), N> {
self.wallet
.call_async(move |w| {
Box::pin(async move { w.compose_transaction(inputs, outputs).await })
Box::pin(
async move { w.compose_transaction(inputs, outputs, only_transaction).await },
)
})
.await?
}
Expand Down
2 changes: 1 addition & 1 deletion wallet/wallet-rpc-lib/src/rpc/server_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl<N: NodeInterface + Clone + Send + Sync + 'static + Debug> WalletRpcServer f
&self,
tx: HexEncoded<SignedTransaction>,
options: TxOptionsOverrides,
) -> rpc::RpcResult<()> {
) -> rpc::RpcResult<NewTransaction> {
rpc::handle_result(self.submit_raw_transaction(tx, options).await)
}

Expand Down

0 comments on commit 068ac7f

Please sign in to comment.