From 6d1f51343cf11b07cd401fbd0c5bc3603e185a0e Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Fri, 7 Aug 2020 13:53:51 +0200 Subject: [rpc] fundrawtransaction, walletcreatefundedpsbt lock manually selected coins Previously only automatically selected coins were locked when lockUnspents is set. It now also locks selected coins. --- doc/release-notes-18244.md | 7 +++++++ src/wallet/rpcwallet.cpp | 1 + src/wallet/wallet.cpp | 7 ++++--- test/functional/rpc_psbt.py | 11 ++++++++++- test/functional/wallet_basic.py | 12 ++++++++++-- 5 files changed, 32 insertions(+), 6 deletions(-) create mode 100644 doc/release-notes-18244.md diff --git a/doc/release-notes-18244.md b/doc/release-notes-18244.md new file mode 100644 index 0000000000..625fbaf7a1 --- /dev/null +++ b/doc/release-notes-18244.md @@ -0,0 +1,7 @@ +Updated RPCs +------------ + +- `fundrawtransaction` and `walletcreatefundedpsbt` when used with the `lockUnspents` + argument now lock manually selected coins, in addition to automatically selected + coins. Note that locked coins are never used in automatic coin selection, but + can still be manually selected. diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 39d1f49e9e..cc7d6cbaf5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2047,6 +2047,7 @@ static UniValue lockunspent(const JSONRPCRequest& request) "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" + "Manually selected coins are automatically unlocked.\n" "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" "is always cleared (by virtue of process exit) when a node stops or fails.\n" "Also see the listunspent call\n", diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index cee2f2214c..2166373a72 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2609,10 +2609,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC if (!coinControl.IsSelected(txin.prevout)) { tx.vin.push_back(txin); - if (lockUnspents) { - LockCoin(txin.prevout); - } } + if (lockUnspents) { + LockCoin(txin.prevout); + } + } return true; diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py index 4d985dd1b1..5d724e7cc7 100755 --- a/test/functional/rpc_psbt.py +++ b/test/functional/rpc_psbt.py @@ -103,7 +103,16 @@ class PSBTTest(BitcoinTestFramework): final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex'] self.nodes[0].sendrawtransaction(final_tx) - # Get pubkeys + # Manually selected inputs can be locked: + assert_equal(len(self.nodes[0].listlockunspent()), 0) + utxo1 = self.nodes[0].listunspent()[0] + psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0,{"lockUnspents": True})["psbt"] + assert_equal(len(self.nodes[0].listlockunspent()), 1) + + # Locks are ignored for manually selected inputs + self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0) + + # Create p2sh, p2wpkh, and p2wsh addresses pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey'] pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey'] pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey'] diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 81382d94ad..7f891deabf 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -136,11 +136,19 @@ class WalletTest(BitcoinTestFramework): self.nodes[2].lockunspent, False, [{"txid": unspent_0["txid"], "vout": 999}]) - # An output should be unlocked when spent + # The lock on a manually selected output is ignored unspent_0 = self.nodes[1].listunspent()[0] self.nodes[1].lockunspent(False, [unspent_0]) tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) - tx = self.nodes[1].fundrawtransaction(tx)['hex'] + self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True}) + + # fundrawtransaction can lock an input + self.nodes[1].lockunspent(True, [unspent_0]) + assert_equal(len(self.nodes[1].listlockunspent()), 0) + tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex'] + assert_equal(len(self.nodes[1].listlockunspent()), 1) + + # Send transaction tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] self.nodes[1].sendrawtransaction(tx) assert_equal(len(self.nodes[1].listlockunspent()), 0) -- cgit v1.2.3