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

Problem:(CRO-524) Client may create transactions with potentially spent utxos #701

Merged
merged 1 commit into from
Jan 6, 2020

Conversation

linfeng-crypto
Copy link
Contributor

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_transaction
  • 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.

@codecov
Copy link

codecov bot commented Dec 18, 2019

Codecov Report

Merging #701 into master will increase coverage by 0.05%.
The diff coverage is 68.43%.

@@            Coverage Diff             @@
##           master     #701      +/-   ##
==========================================
+ Coverage   69.12%   69.18%   +0.05%     
==========================================
  Files         132      132              
  Lines       16896    17184     +288     
==========================================
+ Hits        11680    11888     +208     
- Misses       5216     5296      +80
Impacted Files Coverage Δ
...builder/unauthorized_wallet_transaction_builder.rs 0% <ø> (ø) ⬆️
client-rpc/src/rpc/staking_rpc.rs 0% <0%> (ø) ⬆️
client-rpc/src/program.rs 0% <0%> (ø) ⬆️
client-rpc/src/server.rs 8.84% <0%> (-0.16%) ⬇️
client-cli/src/command.rs 0% <0%> (ø) ⬆️
client-cli/src/command/transaction_command.rs 0% <0%> (ø) ⬆️
...tion_builder/default_wallet_transaction_builder.rs 88.98% <100%> (+0.4%) ⬆️
client-core/src/wallet/syncer_logic.rs 93.19% <100%> (+0.11%) ⬆️
client-rpc/src/rpc/wallet_rpc.rs 64.36% <38.88%> (+1.12%) ⬆️
client-core/src/wallet/default_wallet_client.rs 42.81% <53.84%> (+0.07%) ⬆️
... and 9 more

client-cli/src/command.rs Show resolved Hide resolved

wallet_client.broadcast_transaction(&transaction)?;

if let Some(tp) = tx_pending {
wallet_client.update_tx_pending_state(&name, &passphrase, transaction.tx_id(), tp)?;
Copy link
Collaborator

@devashishdxt devashishdxt Dec 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating pending_state looks like business logic which should be a part of client-core instead of client-cli. Maybe inside broadcast_transaction()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, cause broadcast_transaction is a solo logic that just broadcast the tx to tendermint and not needs name and passphrase, updating the wallet state is also a part of wallet client jobs like broadcasting the tx.

@@ -38,7 +40,7 @@ pub trait WalletTransactionBuilder: Send + Sync {
outputs: Vec<TxOut>,
return_address: ExtendedAddr,
attributes: TxAttributes,
) -> Result<TxAux>;
) -> Result<(TxAux, Vec<TxoPointer>, Coin)>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update documentation with details of returned values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -461,6 +461,26 @@ where
self.tendermint_client
.broadcast_transaction(&tx_aux.encode())
}
#[inline]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[inline]

Ok(current_block_height)
}

#[inline]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[inline]

Copy link
Collaborator

@leejw51crypto leejw51crypto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

Copy link
Contributor

@tomtau tomtau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge conflicts with master

@linfeng-crypto linfeng-crypto force-pushed the CRO-524 branch 2 times, most recently from 7ced010 to 7896c80 Compare December 19, 2019 11:30
@tomtau
Copy link
Contributor

tomtau commented Dec 20, 2019

bors r+

bors bot added a commit that referenced this pull request Dec 20, 2019
701: Problem:(CRO-524) Client may create transactions with potentially spent utxos r=tomtau a=linfeng-crypto

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_transaction`
- 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.

Co-authored-by: linfeng <linfeng@crypto.com>
@bors
Copy link
Contributor

bors bot commented Dec 20, 2019

Build failed

@tomtau tomtau self-requested a review December 20, 2019 03:26
Copy link
Contributor

@tomtau tomtau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems the integration tests fail:

  9 failing
6231	
6232	  1) Wallet Auto-sync
6233	       can auto-sync unlocked wallets:
6234	     AssertionError: Sender balance should be deducted by transfer amount: expected { Object (available, pending, ...) } to equal 'NaN'
6235	      at Context.<anonymous> (test/hdrestore-auto-sync.test.ts:168:43)
6236	      at process._tickCallback (internal/process/next_tick.js:68:7)
6237	
6238	
6239	  2) Wallet transaction
6240	       "before all" hook in "Wallet transaction":
6241	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6242	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6243	      at process._tickCallback (internal/process/next_tick.js:68:7)
6244	
6245	
6246	  3) Wallet Auto-sync
6247	       "before all" hook for "can auto-sync unlocked wallets":
6248	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6249	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6250	      at process._tickCallback (internal/process/next_tick.js:68:7)
6251	
6252	
6253	  4) Wallet management
6254	       "before all" hook for "can restore hd-wallet with specified name":
6255	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6256	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6257	      at process._tickCallback (internal/process/next_tick.js:68:7)
6258	
6259	
6260	  5) Wallet transaction
6261	       "before all" hook in "Wallet transaction":
6262	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6263	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6264	      at process._tickCallback (internal/process/next_tick.js:68:7)
6265	
6266	
6267	  6) Staking
6268	       "before all" hook for "unbond of same amount and nonce from different account should have different txid":
6269	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6270	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6271	      at process._tickCallback (internal/process/next_tick.js:68:7)
6272	
6273	
6274	  7) Wallet Auto-sync
6275	       "before all" hook for "can auto-sync unlocked wallets":
6276	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6277	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6278	      at process._tickCallback (internal/process/next_tick.js:68:7)
6279	
6280	
6281	  8) Wallet management
6282	       "before all" hook for "cannot access un-existing wallet":
6283	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None
6284	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
6285	      at process._tickCallback (internal/process/next_tick.js:68:7)
6286	
6287	
6288	  9) Wallet transaction
6289	       "before all" hook in "Wallet transaction":
6290	     Error: Error when withdrawing all unbonded stake: Validation error: Failed to validate staking account: output with no credited value, origin: None

@linfeng-crypto
Copy link
Contributor Author

Because the balance format changed from Coin to a struct, so there are many errors, I'll fix it.

.print_stdout()
.chain(|| (ErrorKind::IoError, "Unable to print table"))?;

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@linfeng-crypto linfeng-crypto force-pushed the CRO-524 branch 3 times, most recently from 97b082f to ea4a85e Compare December 23, 2019 09:29
Copy link
Collaborator

@calvinaco calvinaco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good to me. I left some comment to make it more configurable and some minor indentation issues.

@linfeng-crypto linfeng-crypto force-pushed the CRO-524 branch 2 times, most recently from a51007f to 55476d3 Compare December 30, 2019 07:29
@tomtau tomtau self-requested a review January 2, 2020 01:52
Copy link
Contributor

@tomtau tomtau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems there are some merge conflicts with the latest master

@tomtau
Copy link
Contributor

tomtau commented Jan 3, 2020

bors try+

@linfeng-crypto linfeng-crypto force-pushed the CRO-524 branch 2 times, most recently from b4fddea to 96f2b77 Compare January 3, 2020 03:55
@tomtau
Copy link
Contributor

tomtau commented Jan 3, 2020

bors try

@bors
Copy link
Contributor

bors bot commented Jan 3, 2020

try

Already running a review

@tomtau
Copy link
Contributor

tomtau commented Jan 3, 2020

bors r+

bors bot added a commit that referenced this pull request Jan 3, 2020
701: Problem:(CRO-524) Client may create transactions with potentially spent utxos r=tomtau a=linfeng-crypto

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_transaction`
- 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.

Co-authored-by: linfeng <linfeng@crypto.com>
@bors
Copy link
Contributor

bors bot commented Jan 3, 2020

Build failed

@tomtau
Copy link
Contributor

tomtau commented Jan 3, 2020

seems there's some problem in the integration tests:


12648	  Wallet Auto-sync
12649	[Log] Synchronizing wallet "Default"
12650	    1) "before all" hook for "can auto-sync unlocked wallets"
12651	
12652	  Wallet transaction
12653	[Log] Synchronizing wallet "Default"
12654	    2) "before all" hook in "Wallet transaction"
12655	
12656	
12657	  Wallet Auto-sync
12658	[Log] Synchronizing wallet "Default"
12659	    3) "before all" hook for "can auto-sync unlocked wallets"
12660	
12661	
12662	  Wallet management
12663	[Log] Synchronizing wallet "Default"
12664	    4) "before all" hook for "can restore hd-wallet with specified name"
12665	
12666	
12667	  Wallet transaction
12668	[Log] Synchronizing wallet "Default"
12669	    5) "before all" hook in "Wallet transaction"
12670	
12671	
12672	  Staking
12673	[Log] Synchronizing wallet "Default"
12674	    6) "before all" hook for "unbond of same amount and nonce from different account should have different txid"
12675	
12676	
12677	  Wallet Auto-sync
12678	[Log] Synchronizing wallet "Default"
12679	    7) "before all" hook for "can auto-sync unlocked wallets"
12680	
12681	
12682	  Wallet management
12683	[Log] Synchronizing wallet "Default"
12684	    8) "before all" hook for "cannot access un-existing wallet"
12685	
12686	
12687	  Wallet transaction
12688	[Log] Synchronizing wallet "Default"
12689	    9) "before all" hook in "Wallet transaction"
12690	
12691	
12692	
12693	  0 passing (41ms)
12694	  9 failing
12695	
12696	
12697	  1) Wallet Auto-sync
12698	       "before all" hook for "can auto-sync unlocked wallets":
12699	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12700	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12701	      at process._tickCallback (internal/process/next_tick.js:68:7)
12702	
12703	
12704	  2) Wallet transaction
12705	       "before all" hook in "Wallet transaction":
12706	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12707	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12708	      at process._tickCallback (internal/process/next_tick.js:68:7)
12709	
12710	
12711	  3) Wallet Auto-sync
12712	       "before all" hook for "can auto-sync unlocked wallets":
12713	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12714	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12715	      at process._tickCallback (internal/process/next_tick.js:68:7)
12716	
12717	
12718	  4) Wallet management
12719	       "before all" hook for "can restore hd-wallet with specified name":
12720	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12721	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12722	      at process._tickCallback (internal/process/next_tick.js:68:7)
12723	
12724	
12725	  5) Wallet transaction
12726	       "before all" hook in "Wallet transaction":
12727	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12728	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12729	      at process._tickCallback (internal/process/next_tick.js:68:7)
12730	
12731	
12732	  6) Staking
12733	       "before all" hook for "unbond of same amount and nonce from different account should have different txid":
12734	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12735	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12736	      at process._tickCallback (internal/process/next_tick.js:68:7)
12737	
12738	
12739	  7) Wallet Auto-sync
12740	       "before all" hook for "can auto-sync unlocked wallets":
12741	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12742	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12743	      at process._tickCallback (internal/process/next_tick.js:68:7)
12744	
12745	
12746	  8) Wallet management
12747	       "before all" hook for "cannot access un-existing wallet":
12748	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12749	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12750	      at process._tickCallback (internal/process/next_tick.js:68:7)
12751	
12752	
12753	  9) Wallet transaction
12754	       "before all" hook in "Wallet transaction":
12755	     Error: Error when synchronizing Default wallet: connect ECONNREFUSED 127.0.0.1:37972
12756	      at Object.exports.asyncMiddleman (test/core/utils.ts:81:9)
12757	      at process._tickCallback (internal/process/next_tick.js:68:7)

bors bot added a commit that referenced this pull request Jan 6, 2020
@bors
Copy link
Contributor

bors bot commented Jan 6, 2020

try

Build failed

…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
@tomtau
Copy link
Contributor

tomtau commented Jan 6, 2020

bors retry

bors bot added a commit that referenced this pull request Jan 6, 2020
701: Problem:(CRO-524) Client may create transactions with potentially spent utxos r=tomtau a=linfeng-crypto

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_transaction`
- 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.

Co-authored-by: linfeng <linfeng@crypto.com>
@bors
Copy link
Contributor

bors bot commented Jan 6, 2020

@bors bors bot merged commit ee28a09 into crypto-com:master Jan 6, 2020
@linfeng-crypto linfeng-crypto deleted the CRO-524 branch January 6, 2020 07:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants