Skip to content

Commit

Permalink
feat(wallet): send a cancel message to a receiver when it responds to…
Browse files Browse the repository at this point in the history
… a canceled transaction (#3976)

Description
---
This will send a cancel message to a receiving node when it responds to an already canceled transaction. 

Motivation and Context
---
This catches an edge case where the sender can cancel a stale transaction when the receiver is offline, but when it comes online it tries to continue the transaction. 

How Has This Been Tested?
---
Included new cucumber test.
  • Loading branch information
SWvheerden authored Apr 4, 2022
1 parent 0b29c89 commit 96d24c6
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 1 deletion.
1 change: 1 addition & 0 deletions base_layer/p2p/src/proto/message_type.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum TariMessageType {
TariMessageTypeMempoolResponse = 72;
TariMessageTypeTransactionFinalized = 73;
TariMessageTypeTransactionCancelled = 74;

// -- DAN Messages --
TariMessageTypeDanConsensusMessage = 101;
// -- Extended --
Expand Down
7 changes: 6 additions & 1 deletion base_layer/wallet/src/transaction_service/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,6 @@ where
self.last_seen_tip_height,
None,
);

let join_handle = tokio::spawn(protocol.execute());
join_handles.push(join_handle);

Expand Down Expand Up @@ -1574,6 +1573,12 @@ where
"A repeated Transaction (TxId: {}) has been received but has been previously cancelled or rejected",
tx.tx_id
);
tokio::spawn(send_transaction_cancelled_message(
tx.tx_id,
source_pubkey,
self.resources.outbound_message_service.clone(),
));

return Ok(());
}

Expand Down
18 changes: 18 additions & 0 deletions integration_tests/features/WalletTransactions.feature
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,21 @@ Feature: Wallet Transactions
And I wait 5 seconds
Then I restart wallet WALLET_RECV
Then I wait for wallet WALLET_RECV to have at least 1000000 uT

@critical
Scenario: Wallet should cancel stale transactions
Given I have a seed node NODE
And I have 1 base nodes connected to all seed nodes
And I have non-default wallet WALLET_SENDER connected to all seed nodes using StoreAndForwardOnly
And I have wallet WALLET_RECV connected to all seed nodes
And I have mining node MINER connected to base node NODE and wallet WALLET_SENDER
And mining node MINER mines 5 blocks
Then all nodes are at height 5
Then I wait for wallet WALLET_SENDER to have at least 10000000000 uT
And I stop wallet WALLET_RECV
When I wait 15 seconds
And I send 1000000 uT without waiting for broadcast from wallet WALLET_SENDER to wallet WALLET_RECV at fee 100
Then I cancel last transaction in wallet WALLET_SENDER
Then I restart wallet WALLET_RECV
When I wait 15 seconds
When wallet WALLET_RECV detects last transaction is Cancelled
30 changes: 30 additions & 0 deletions integration_tests/features/support/wallet_steps.js
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,36 @@ Then(
}
);

Then(
/wallet (.*) detects last transaction is Cancelled/,
{ timeout: 120 * 1000 },
async function (walletName) {
const wallet = this.getWallet(walletName);
const walletClient = await wallet.connectClient();

let lastTxId = this.lastResult.results[0].transaction_id;
console.log(
"Waiting for Transaction ",
lastTxId,
"to be cancelled in wallet",
walletName
);

await waitFor(
async () => walletClient.isTransactionCancelled(lastTxId),
true,
115 * 1000,
5 * 1000,
5
);
const transactionPending = await walletClient.isTransactionPending(
lastTxId
);

expect(transactionPending).to.equal(true);
}
);

Then(
/wallet (.*) detects all transactions are at least Completed/,
{ timeout: 1200 * 1000 }, // Must allow for many transactions; dynamic time out used below
Expand Down
16 changes: 16 additions & 0 deletions integration_tests/helpers/walletClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,22 @@ class WalletClient {
}
}

async isTransactionCancelled(tx_id) {
try {
const txnDetails = await this.getTransactionInfo({
transaction_ids: [tx_id.toString()],
});
if (transactionStatus().indexOf(txnDetails.transactions[0].status) == 7) {
return true;
} else {
return false;
}
} catch (err) {
// Any error here must be treated as if the required status was not achieved
return false;
}
}

async isTransactionAtLeastCompleted(tx_id) {
try {
const txnDetails = await this.getTransactionInfo({
Expand Down

0 comments on commit 96d24c6

Please sign in to comment.