Skip to content

Commit 6d1f513

Browse files
committed
[rpc] fundrawtransaction, walletcreatefundedpsbt lock manually selected coins
Previously only automatically selected coins were locked when lockUnspents is set. It now also locks selected coins.
1 parent 4b705b1 commit 6d1f513

File tree

5 files changed

+32
-6
lines changed

5 files changed

+32
-6
lines changed

doc/release-notes-18244.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Updated RPCs
2+
------------
3+
4+
- `fundrawtransaction` and `walletcreatefundedpsbt` when used with the `lockUnspents`
5+
argument now lock manually selected coins, in addition to automatically selected
6+
coins. Note that locked coins are never used in automatic coin selection, but
7+
can still be manually selected.

src/wallet/rpcwallet.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,6 +2047,7 @@ static UniValue lockunspent(const JSONRPCRequest& request)
20472047
"Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
20482048
"If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
20492049
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
2050+
"Manually selected coins are automatically unlocked.\n"
20502051
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
20512052
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
20522053
"Also see the listunspent call\n",

src/wallet/wallet.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2609,10 +2609,11 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
26092609
if (!coinControl.IsSelected(txin.prevout)) {
26102610
tx.vin.push_back(txin);
26112611

2612-
if (lockUnspents) {
2613-
LockCoin(txin.prevout);
2614-
}
26152612
}
2613+
if (lockUnspents) {
2614+
LockCoin(txin.prevout);
2615+
}
2616+
26162617
}
26172618

26182619
return true;

test/functional/rpc_psbt.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,16 @@ def run_test(self):
103103
final_tx = self.nodes[0].finalizepsbt(signed_tx)['hex']
104104
self.nodes[0].sendrawtransaction(final_tx)
105105

106-
# Get pubkeys
106+
# Manually selected inputs can be locked:
107+
assert_equal(len(self.nodes[0].listlockunspent()), 0)
108+
utxo1 = self.nodes[0].listunspent()[0]
109+
psbtx1 = self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0,{"lockUnspents": True})["psbt"]
110+
assert_equal(len(self.nodes[0].listlockunspent()), 1)
111+
112+
# Locks are ignored for manually selected inputs
113+
self.nodes[0].walletcreatefundedpsbt([{"txid": utxo1['txid'], "vout": utxo1['vout']}], {self.nodes[2].getnewaddress():1}, 0)
114+
115+
# Create p2sh, p2wpkh, and p2wsh addresses
107116
pubkey0 = self.nodes[0].getaddressinfo(self.nodes[0].getnewaddress())['pubkey']
108117
pubkey1 = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())['pubkey']
109118
pubkey2 = self.nodes[2].getaddressinfo(self.nodes[2].getnewaddress())['pubkey']

test/functional/wallet_basic.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,19 @@ def run_test(self):
136136
self.nodes[2].lockunspent, False,
137137
[{"txid": unspent_0["txid"], "vout": 999}])
138138

139-
# An output should be unlocked when spent
139+
# The lock on a manually selected output is ignored
140140
unspent_0 = self.nodes[1].listunspent()[0]
141141
self.nodes[1].lockunspent(False, [unspent_0])
142142
tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 })
143-
tx = self.nodes[1].fundrawtransaction(tx)['hex']
143+
self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})
144+
145+
# fundrawtransaction can lock an input
146+
self.nodes[1].lockunspent(True, [unspent_0])
147+
assert_equal(len(self.nodes[1].listlockunspent()), 0)
148+
tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex']
149+
assert_equal(len(self.nodes[1].listlockunspent()), 1)
150+
151+
# Send transaction
144152
tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"]
145153
self.nodes[1].sendrawtransaction(tx)
146154
assert_equal(len(self.nodes[1].listlockunspent()), 0)

0 commit comments

Comments
 (0)