Skip to content

Commit 31c0006

Browse files
committed
Merge #17264: rpc: set default bip32derivs to true for psbt methods
5bad792 [test] PSBT RPC: check that bip32_derivs are present by default (Sjors Provoost) 29a21c9 [rpc] set default bip32derivs to true for psbt methods (Sjors Provoost) Pull request description: In bitcoin/bitcoin#13557 (review) I recommended not including bip32 deriviation by default in PSBTs: > _Bit of a privacy issue_: let's say person A and B are about to spend from a multisig address, sending everything to person A. Person A gives their address to person B, their wallet wallet creates a PSBT, but doesn't sign it. Wallet A then calls `walletprocesspsbt` which signs it and _spontaneously adds the master_fingerprint and bip32 path_. Same issue with `walletcreatefundedpsbt`. > > Adding `bip32_derivs` should probably be opt-in. In practice I find this default quite annoying because I forget it and end up with a confused hardware wallet. More importantly, in the multisig example I provided, it's actually essential for the other side to know the derivation details (in addition to an xpub). This allows them to check that change is going to an address you can still co-sign for (because the spending policy is unchanged except for an index). ACKs for top commit: instagibbs: utACK bitcoin/bitcoin@5bad792 jonatack: ACK 5bad792 code review, built, ran tests, inspected/messed around with/pprinted values from the new tests. Thanks for adding the tests. meshcollider: utACK 5bad792 Tree-SHA512: 22ad71dda96856060a96758c4ae7aafa22d5e9efba30e0c8287c711e7579849bd72593cbc0f41a2e9e8821315d78bda04e848dbb006283b841b2795e2faebcfd
2 parents 03f98b1 + 5bad792 commit 31c0006

File tree

4 files changed

+23
-9
lines changed

4 files changed

+23
-9
lines changed

doc/release-notes-17264.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Updated RPCs
2+
------------
3+
4+
- `walletprocesspsbt` and `walletcreatefundedpsbt` now include BIP 32 derivation paths by default for public keys if we know them. This can be disabled by setting `bip32derivs` to `false`.

src/wallet/psbtwallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@ NODISCARD TransactionError FillPSBT(const CWallet* pwallet,
2727
bool& complete,
2828
int sighash_type = 1 /* SIGHASH_ALL */,
2929
bool sign = true,
30-
bool bip32derivs = false);
30+
bool bip32derivs = true);
3131

3232
#endif // BITCOIN_WALLET_PSBTWALLET_H

src/wallet/rpcwallet.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4066,7 +4066,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
40664066
" \"ALL|ANYONECANPAY\"\n"
40674067
" \"NONE|ANYONECANPAY\"\n"
40684068
" \"SINGLE|ANYONECANPAY\""},
4069-
{"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
4069+
{"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
40704070
},
40714071
RPCResult{
40724072
"{ (json object)\n"
@@ -4093,7 +4093,7 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request)
40934093

40944094
// Fill transaction with our data and also sign
40954095
bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
4096-
bool bip32derivs = request.params[3].isNull() ? false : request.params[3].get_bool();
4096+
bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
40974097
bool complete = true;
40984098
const TransactionError err = FillPSBT(pwallet, psbtx, complete, nHashType, sign, bip32derivs);
40994099
if (err != TransactionError::OK) {
@@ -4176,7 +4176,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
41764176
" \"CONSERVATIVE\""},
41774177
},
41784178
"options"},
4179-
{"bip32derivs", RPCArg::Type::BOOL, /* default */ "false", "If true, includes the BIP 32 derivation paths for public keys if we know them"},
4179+
{"bip32derivs", RPCArg::Type::BOOL, /* default */ "true", "Include BIP 32 derivation paths for public keys if we know them"},
41804180
},
41814181
RPCResult{
41824182
"{\n"
@@ -4215,7 +4215,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request)
42154215
PartiallySignedTransaction psbtx(rawTx);
42164216

42174217
// Fill transaction with out data but don't sign
4218-
bool bip32derivs = request.params[4].isNull() ? false : request.params[4].get_bool();
4218+
bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
42194219
bool complete = true;
42204220
const TransactionError err = FillPSBT(pwallet, psbtx, complete, 1, false, bip32derivs);
42214221
if (err != TransactionError::OK) {

test/functional/rpc_psbt.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,20 @@ def run_test(self):
193193
psbt_orig = self.nodes[0].createpsbt([{"txid":txid1, "vout":vout1}, {"txid":txid2, "vout":vout2}], {self.nodes[0].getnewaddress():25.999})
194194

195195
# Update psbts, should only have data for one input and not the other
196-
psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
196+
psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig, False, "ALL")['psbt']
197197
psbt1_decoded = self.nodes[0].decodepsbt(psbt1)
198198
assert psbt1_decoded['inputs'][0] and not psbt1_decoded['inputs'][1]
199-
psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']
199+
# Check that BIP32 path was added
200+
assert "bip32_derivs" in psbt1_decoded['inputs'][0]
201+
psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig, False, "ALL", False)['psbt']
200202
psbt2_decoded = self.nodes[0].decodepsbt(psbt2)
201203
assert not psbt2_decoded['inputs'][0] and psbt2_decoded['inputs'][1]
204+
# Check that BIP32 paths were not added
205+
assert "bip32_derivs" not in psbt2_decoded['inputs'][1]
206+
207+
# Sign PSBTs (workaround issue #18039)
208+
psbt1 = self.nodes[1].walletprocesspsbt(psbt_orig)['psbt']
209+
psbt2 = self.nodes[2].walletprocesspsbt(psbt_orig)['psbt']
202210

203211
# Combine, finalize, and send the psbts
204212
combined = self.nodes[0].combinepsbt([psbt1, psbt2])
@@ -231,16 +239,18 @@ def run_test(self):
231239
# Same construction without optional arguments
232240
psbtx_info = self.nodes[0].walletcreatefundedpsbt([{"txid":unspent["txid"], "vout":unspent["vout"]}], [{self.nodes[2].getnewaddress():unspent["amount"]+1}])
233241
decoded_psbt = self.nodes[0].decodepsbt(psbtx_info["psbt"])
234-
for tx_in in decoded_psbt["tx"]["vin"]:
242+
for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
235243
assert_equal(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
244+
assert "bip32_derivs" in psbt_in
236245
assert_equal(decoded_psbt["tx"]["locktime"], 0)
237246

238247
# Same construction without optional arguments, for a node with -walletrbf=0
239248
unspent1 = self.nodes[1].listunspent()[0]
240249
psbtx_info = self.nodes[1].walletcreatefundedpsbt([{"txid":unspent1["txid"], "vout":unspent1["vout"]}], [{self.nodes[2].getnewaddress():unspent1["amount"]+1}], block_height)
241250
decoded_psbt = self.nodes[1].decodepsbt(psbtx_info["psbt"])
242-
for tx_in in decoded_psbt["tx"]["vin"]:
251+
for tx_in, psbt_in in zip(decoded_psbt["tx"]["vin"], decoded_psbt["inputs"]):
243252
assert_greater_than(tx_in["sequence"], MAX_BIP125_RBF_SEQUENCE)
253+
assert "bip32_derivs" in psbt_in
244254

245255
# Make sure change address wallet does not have P2SH innerscript access to results in success
246256
# when attempting BnB coin selection

0 commit comments

Comments
 (0)