From 4a8bdabb2ff596d356508f53e2f04c6610e7e252 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Tue, 1 Mar 2022 08:30:51 +0800 Subject: [PATCH 1/4] wallet_sendmany_any_taddr.py: Test sending from a change taddr. --- qa/rpc-tests/wallet_sendmany_any_taddr.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/qa/rpc-tests/wallet_sendmany_any_taddr.py b/qa/rpc-tests/wallet_sendmany_any_taddr.py index 9e223ea56..c189fc593 100755 --- a/qa/rpc-tests/wallet_sendmany_any_taddr.py +++ b/qa/rpc-tests/wallet_sendmany_any_taddr.py @@ -67,5 +67,22 @@ class WalletSendManyAnyTaddr(BitcoinTestFramework): assert_equal(self.nodes[3].z_getbalance(node3taddr1), 0) assert_equal(self.nodes[3].z_getbalance(node3taddr2), 0) + # Send from a change t-address. + wait_and_assert_operationid_status( + self.nodes[3], + self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 20}]), + ) + + self.sync_all() + self.nodes[0].generate(1) + self.sync_all() + + # The recipient has their funds! + assert_equal(self.nodes[1].z_getbalance(recipient), 120) + + # Check that ANY_TADDR note selection doesn't attempt a double-spend + myopid = self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 20}]) + wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient funds: have 14.99998, need 20.00001") + if __name__ == '__main__': WalletSendManyAnyTaddr().main() From 98cd4bab0b3fc88d4b9ce48900179e9302a98366 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 2 Mar 2022 14:28:11 +0800 Subject: [PATCH 2/4] wallet_sendmany_any_taddr.py: Test sending output from expired tx. --- qa/rpc-tests/wallet_sendmany_any_taddr.py | 40 +++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/qa/rpc-tests/wallet_sendmany_any_taddr.py b/qa/rpc-tests/wallet_sendmany_any_taddr.py index c189fc593..7ee55d97a 100755 --- a/qa/rpc-tests/wallet_sendmany_any_taddr.py +++ b/qa/rpc-tests/wallet_sendmany_any_taddr.py @@ -6,17 +6,31 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, + connect_nodes_bi, + start_nodes, + sync_blocks, wait_and_assert_operationid_status, ) +TX_EXPIRY_DELTA = 10 +TX_EXPIRING_SOON_THRESHOLD = 3 + # Test ANY_TADDR special string in z_sendmany class WalletSendManyAnyTaddr(BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(self.num_nodes, self.options.tmpdir, + [[ + "-txexpirydelta=%d" % TX_EXPIRY_DELTA, + ]] * self.num_nodes) + def run_test(self): # Sanity-check the test harness assert_equal(self.nodes[0].getblockcount(), 200) # Create the addresses we will be using. recipient = self.nodes[1].z_getnewaddress() + node2zaddr = self.nodes[2].z_getnewaddress() + node2taddr1 = self.nodes[2].getnewaddress() node3zaddr = self.nodes[3].z_getnewaddress() node3taddr1 = self.nodes[3].getnewaddress() node3taddr2 = self.nodes[3].getnewaddress() @@ -84,5 +98,31 @@ class WalletSendManyAnyTaddr(BitcoinTestFramework): myopid = self.nodes[3].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 20}]) wait_and_assert_operationid_status(self.nodes[3], myopid, "failed", "Insufficient funds: have 14.99998, need 20.00001") + # Create an expired transaction on node 3. + self.split_network() + expire_transparent = self.nodes[3].sendtoaddress(node2taddr1, 14) + assert(expire_transparent in self.nodes[3].getrawmempool()) + self.sync_all() + assert_equal('waiting', self.nodes[2].gettransaction(expire_transparent)['status']) + + self.nodes[0].generate(TX_EXPIRY_DELTA + TX_EXPIRING_SOON_THRESHOLD) + self.sync_all() + connect_nodes_bi(self.nodes, 1, 2) + sync_blocks(self.nodes[1:3]) + assert_equal('expired', self.nodes[2].gettransaction(expire_transparent)['status']) + + # Ensure that node 2 has no transparent funds. + self.nodes[2].generate(100) # To ensure node 2's pending coinbase is spendable + self.sync_all() + wait_and_assert_operationid_status( + self.nodes[2], + self.nodes[2].z_shieldcoinbase("*", node2zaddr, 0)['opid'], + ) + self.sync_all() + assert_equal(0, self.nodes[2].getbalance()) + + # Check that ANY_TADDR doesn't select an expired output. + wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 13}]), "failed", "SendTransaction: CommitTransaction failed") + if __name__ == '__main__': WalletSendManyAnyTaddr().main() From 454c1eed46f6f14ecbf297c2d45a6b211918c7c1 Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 2 Mar 2022 22:38:13 +0800 Subject: [PATCH 3/4] FindSpendableInputs: Add nDepth < 0 check. Co-authored-by: Jack Grigg --- src/wallet/wallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index f9be3a9d5..6a8a79a25 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1749,7 +1749,7 @@ SpendableInputs CWallet::FindSpendableInputs( // Filter the transactions before checking for coins if (!CheckFinalTx(wtx)) continue; - if (nDepth < minDepth) continue; + if (nDepth < 0 || nDepth < minDepth) continue; if (selectTransparent && // skip transparent utxo selection if coinbase spend restrictions are not met From cedf2b5ecb393aaab45f4f99827f387a5553b03c Mon Sep 17 00:00:00 2001 From: therealyingtong Date: Wed, 2 Mar 2022 19:35:15 +0800 Subject: [PATCH 4/4] wallet_sendmany_any_taddr.py: Expect expired tx to be ignored. --- qa/rpc-tests/wallet_sendmany_any_taddr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/rpc-tests/wallet_sendmany_any_taddr.py b/qa/rpc-tests/wallet_sendmany_any_taddr.py index 7ee55d97a..0b44c3877 100755 --- a/qa/rpc-tests/wallet_sendmany_any_taddr.py +++ b/qa/rpc-tests/wallet_sendmany_any_taddr.py @@ -122,7 +122,7 @@ class WalletSendManyAnyTaddr(BitcoinTestFramework): assert_equal(0, self.nodes[2].getbalance()) # Check that ANY_TADDR doesn't select an expired output. - wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 13}]), "failed", "SendTransaction: CommitTransaction failed") + wait_and_assert_operationid_status(self.nodes[2], self.nodes[2].z_sendmany('ANY_TADDR', [{'address': recipient, 'amount': 13}]), "failed", "Insufficient funds: have 0.00, need 13.00001") if __name__ == '__main__': WalletSendManyAnyTaddr().main()