Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
Problem:(CRO-524) Client may create transactions with potentially spe…
Browse files Browse the repository at this point in the history
…nt utxos

solution:
- add a `pending_transaction` in wallet state, it's a BTreepMap of `txid` -> `pending_info`
- the pending_info includes the `current block height` when the tx broadcast, the returned coin amount and the used `inputs`
- after broadcast a transaction, we update the pending_info
- when make a new transaction, we select the inputs which are in `unspent_transactions` and not in `pending_transactions`
- we remove the `txid` from the `pending_transaction` when we find it in `sync`
- we also remove the `txid` after `sync` finished if it can not be found in the latest `BLOCK_HEIGHT_ENSURE`(which is 50) blocks after it broadcast
- change the wallet balance into 3 types: `total`, `pending`, `available`, we can only use the coins amount which is in `available` when we make a new transaction.
- make integration test worked
  • Loading branch information
linfeng-crypto committed Jan 2, 2020
1 parent bdff46b commit 755095a
Show file tree
Hide file tree
Showing 29 changed files with 803 additions and 218 deletions.
25 changes: 24 additions & 1 deletion client-cli/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,30 @@ impl Command {
let passphrase = ask_passphrase(None)?;
let balance = wallet_client.balance(name, &passphrase)?;

success(&format!("Wallet balance: {}", balance));
let rows = vec![
Row::new(vec![
Cell::new("Total", Default::default()),
Cell::new(format!("{}", balance.total).as_str(), Default::default()),
]),
Row::new(vec![
Cell::new("Pending", Default::default()),
Cell::new(format!("{}", balance.pending).as_str(), Default::default()),
]),
Row::new(vec![
Cell::new("Available", Default::default()),
Cell::new(
format!("{}", balance.available).as_str(),
Default::default(),
),
]),
];

let table = Table::new(rows, Default::default());
table
.print_stdout()
.chain(|| (ErrorKind::IoError, "Unable to print table"))?;

success(&format!("Wallet balance: \n {:?}", balance));
Ok(())
}

Expand Down
66 changes: 52 additions & 14 deletions client-cli/src/command/transaction_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use chain_core::tx::data::input::TxoPointer;
use chain_core::tx::data::output::TxOut;
use chain_core::tx::TxAux;
use client_common::{Error, ErrorKind, PublicKey, Result, ResultExt};
use client_core::types::TransactionPending;
use client_core::WalletClient;
use client_network::NetworkOpsClient;
use hex::decode;
Expand Down Expand Up @@ -119,21 +120,45 @@ fn new_transaction<T: WalletClient, N: NetworkOpsClient>(
) -> Result<()> {
let passphrase = ask_passphrase(None)?;

let transaction = match transaction_type {
TransactionType::Transfer => new_transfer_transaction(wallet_client, name, &passphrase),
TransactionType::Deposit => new_deposit_transaction(network_ops_client, name, &passphrase),
TransactionType::Unbond => new_unbond_transaction(network_ops_client, name, &passphrase),
match transaction_type {
TransactionType::Transfer => {
let (tx_aux, tx_pending) = new_transfer_transaction(wallet_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
wallet_client.update_tx_pending_state(
&name,
&passphrase,
tx_aux.tx_id(),
tx_pending,
)?;
}
TransactionType::Deposit => {
let tx_aux = new_deposit_transaction(network_ops_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
}
TransactionType::Unbond => {
let tx_aux = new_unbond_transaction(network_ops_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
}
TransactionType::Withdraw => {
new_withdraw_transaction(wallet_client, network_ops_client, name, &passphrase)
let (tx_aux, tx_pending) =
new_withdraw_transaction(wallet_client, network_ops_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
wallet_client.update_tx_pending_state(
&name,
&passphrase,
tx_aux.tx_id(),
tx_pending,
)?;
}
TransactionType::Unjail => {
let tx_aux = new_unjail_transaction(network_ops_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
}
TransactionType::Unjail => new_unjail_transaction(network_ops_client, name, &passphrase),
TransactionType::NodeJoin => {
new_node_join_transaction(network_ops_client, name, &passphrase)
let tx_aux = new_node_join_transaction(network_ops_client, name, &passphrase)?;
wallet_client.broadcast_transaction(&tx_aux)?;
}
}?;

wallet_client.broadcast_transaction(&transaction)?;

};
Ok(())
}

Expand All @@ -142,7 +167,7 @@ fn new_withdraw_transaction<T: WalletClient, N: NetworkOpsClient>(
network_ops_client: &N,
name: &str,
passphrase: &SecUtf8,
) -> Result<TxAux> {
) -> Result<(TxAux, TransactionPending)> {
let from_address = ask_staking_address()?;
let to_address = ask_transfer_address()?;
let view_keys = ask_view_keys()?;
Expand Down Expand Up @@ -204,7 +229,7 @@ fn new_transfer_transaction<T: WalletClient>(
wallet_client: &T,
name: &str,
passphrase: &SecUtf8,
) -> Result<TxAux> {
) -> Result<(TxAux, TransactionPending)> {
let outputs = ask_outputs()?;
let view_keys = ask_view_keys()?;

Expand All @@ -226,7 +251,20 @@ fn new_transfer_transaction<T: WalletClient>(

let return_address = wallet_client.new_transfer_address(name, &passphrase)?;

wallet_client.create_transaction(name, &passphrase, outputs, attributes, None, return_address)
let (transaction, used_inputs, return_amount) = wallet_client.create_transaction(
name,
&passphrase,
outputs,
attributes,
None,
return_address,
)?;
let tx_pending = TransactionPending {
block_height: wallet_client.get_current_block_height()?,
used_inputs,
return_amount,
};
Ok((transaction, tx_pending))
}

fn new_unjail_transaction<N: NetworkOpsClient>(
Expand Down
Loading

0 comments on commit 755095a

Please sign in to comment.