Skip to content

Commit 9e8d6a3

Browse files
committed
Merge #10784: Do not allow users to get keys from keypool without reserving them
cf82a9e Do not allow users to get keys from keypool without reserving them (Matt Corallo) Pull request description: fundrawtransaction allows users to add a change output and then not have it removed from keypool. While it would be nice to have users follow the normal CreateTransaction/CommitTransaction process we use internally, there isnt much benefit in exposing this option, especially with HD wallets, while there is ample room for users to misunderstand or misuse this option. This partially reverts #9377. Would be nice to get this for 15 since its kinda crazy we have this option to begin with IMO, will need release notes as an RPC option is now ignored. Tree-SHA512: 72b5ee9c4a229b84d799dfb00c56fe80d8bba914ce81a433c3f5ab325bf9bf2b839ee658c261734f0ee183ab19435039481014d09c41dbe155e6323e63beb01d
2 parents bde4f93 + cf82a9e commit 9e8d6a3

File tree

4 files changed

+13
-27
lines changed

4 files changed

+13
-27
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2705,7 +2705,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
27052705
" \"changePosition\" (numeric, optional, default random) The index of the change output\n"
27062706
" \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n"
27072707
" \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n"
2708-
" \"reserveChangeKey\" (boolean, optional, default true) Reserves the change output key from the keypool\n"
27092708
" \"feeRate\" (numeric, optional, default not set: makes wallet determine the fee) Set a specific feerate (" + CURRENCY_UNIT + " per KB)\n"
27102709
" \"subtractFeeFromOutputs\" (array, optional) A json array of integers.\n"
27112710
" The fee will be equally deducted from the amount of each specified output.\n"
@@ -2744,7 +2743,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
27442743
CCoinControl coinControl;
27452744
int changePosition = -1;
27462745
bool lockUnspents = false;
2747-
bool reserveChangeKey = true;
27482746
UniValue subtractFeeFromOutputs;
27492747
std::set<int> setSubtractFeeFromOutputs;
27502748

@@ -2764,7 +2762,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
27642762
{"changePosition", UniValueType(UniValue::VNUM)},
27652763
{"includeWatching", UniValueType(UniValue::VBOOL)},
27662764
{"lockUnspents", UniValueType(UniValue::VBOOL)},
2767-
{"reserveChangeKey", UniValueType(UniValue::VBOOL)},
2765+
{"reserveChangeKey", UniValueType(UniValue::VBOOL)}, // DEPRECATED (and ignored), should be removed in 0.16 or so.
27682766
{"feeRate", UniValueType()}, // will be checked below
27692767
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
27702768
{"replaceable", UniValueType(UniValue::VBOOL)},
@@ -2791,9 +2789,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
27912789
if (options.exists("lockUnspents"))
27922790
lockUnspents = options["lockUnspents"].get_bool();
27932791

2794-
if (options.exists("reserveChangeKey"))
2795-
reserveChangeKey = options["reserveChangeKey"].get_bool();
2796-
27972792
if (options.exists("feeRate"))
27982793
{
27992794
coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
@@ -2842,7 +2837,7 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
28422837
CAmount nFeeOut;
28432838
std::string strFailReason;
28442839

2845-
if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl, reserveChangeKey)) {
2840+
if (!pwallet->FundTransaction(tx, nFeeOut, changePosition, strFailReason, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
28462841
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
28472842
}
28482843

src/wallet/wallet.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2471,7 +2471,7 @@ bool CWallet::SignTransaction(CMutableTransaction &tx)
24712471
return true;
24722472
}
24732473

2474-
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl, bool keepReserveKey)
2474+
bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
24752475
{
24762476
std::vector<CRecipient> vecSend;
24772477

@@ -2493,8 +2493,13 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
24932493
if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) {
24942494
return false;
24952495
}
2496-
if (nChangePosInOut != -1)
2496+
2497+
if (nChangePosInOut != -1) {
24972498
tx.vout.insert(tx.vout.begin() + nChangePosInOut, wtx.tx->vout[nChangePosInOut]);
2499+
// we dont have the normal Create/Commit cycle, and dont want to risk reusing change,
2500+
// so just remove the key from the keypool here.
2501+
reservekey.KeepKey();
2502+
}
24982503

24992504
// Copy output sizes from new transaction; they may have had the fee subtracted from them
25002505
for (unsigned int idx = 0; idx < tx.vout.size(); idx++)
@@ -2515,9 +2520,6 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC
25152520
}
25162521
}
25172522

2518-
// optionally keep the change output key
2519-
if (keepReserveKey)
2520-
reservekey.KeepKey();
25212523

25222524
return true;
25232525
}

src/wallet/wallet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
949949
* Insert additional inputs into the transaction by
950950
* calling CreateTransaction();
951951
*/
952-
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl, bool keepReserveKey = true);
952+
bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl);
953953
bool SignTransaction(CMutableTransaction& tx);
954954

955955
/**

test/functional/fundrawtransaction.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -636,20 +636,9 @@ def run_test(self):
636636
assert_fee_amount(result2['fee'], count_bytes(result2['hex']), 2 * result_fee_rate)
637637
assert_fee_amount(result3['fee'], count_bytes(result3['hex']), 10 * result_fee_rate)
638638

639-
#############################
640-
# Test address reuse option #
641-
#############################
642-
643-
result3 = self.nodes[3].fundrawtransaction(rawtx, {"reserveChangeKey": False})
644-
res_dec = self.nodes[0].decoderawtransaction(result3["hex"])
645-
changeaddress = ""
646-
for out in res_dec['vout']:
647-
if out['value'] > 1.0:
648-
changeaddress += out['scriptPubKey']['addresses'][0]
649-
assert(changeaddress != "")
650-
nextaddr = self.nodes[3].getrawchangeaddress()
651-
# frt should not have removed the key from the keypool
652-
assert(changeaddress == nextaddr)
639+
################################
640+
# Test no address reuse occurs #
641+
################################
653642

654643
result3 = self.nodes[3].fundrawtransaction(rawtx)
655644
res_dec = self.nodes[0].decoderawtransaction(result3["hex"])

0 commit comments

Comments
 (0)