From 3b35e4896b5b8be9ffd6dacddb081f69a5b77903 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Thu, 28 Apr 2016 22:04:07 +0200 Subject: [RPC] add feerate option to fundrawtransaction --- qa/rpc-tests/fundrawtransaction.py | 8 ++++++++ src/coincontrol.h | 3 +++ src/wallet/rpcwallet.cpp | 13 +++++++++---- src/wallet/wallet.cpp | 6 +++++- src/wallet/wallet.h | 2 +- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/qa/rpc-tests/fundrawtransaction.py b/qa/rpc-tests/fundrawtransaction.py index 496c7fe8b0..f76fe90ef4 100755 --- a/qa/rpc-tests/fundrawtransaction.py +++ b/qa/rpc-tests/fundrawtransaction.py @@ -677,6 +677,14 @@ class RawTransactionsTest(BitcoinTestFramework): assert(signedtx["complete"]) self.nodes[0].sendrawtransaction(signedtx["hex"]) + inputs = [] + outputs = {self.nodes[2].getnewaddress() : 1} + rawtx = self.nodes[3].createrawtransaction(inputs, outputs) + result = self.nodes[3].fundrawtransaction(rawtx, ) + result2 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 2000}) + result3 = self.nodes[3].fundrawtransaction(rawtx, {"feeRate": 10000}) + assert_equal(result['fee']*2, result2['fee']) + assert_equal(result['fee']*10, result3['fee']) if __name__ == '__main__': RawTransactionsTest().main() diff --git a/src/coincontrol.h b/src/coincontrol.h index 12fe9ce219..6129397bc8 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -18,6 +18,8 @@ public: bool fAllowWatchOnly; //! Minimum absolute fee (not per kilobyte) CAmount nMinimumTotalFee; + //! Feerate to use (0 = estimate fee with payTxFee fallback) + CFeeRate nFeeRate; CCoinControl() { @@ -31,6 +33,7 @@ public: fAllowWatchOnly = false; setSelected.clear(); nMinimumTotalFee = 0; + nFeeRate = CFeeRate(0); } bool HasSelected() const diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 623037e766..b14d748b39 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2458,6 +2458,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) " \"changePosition\" (numeric, optional, default random) The index of the change output\n" " \"includeWatching\" (boolean, optional, default false) Also select inputs which are watch only\n" " \"lockUnspents\" (boolean, optional, default false) Lock selected unspent outputs\n" + " \"feeRate\" (numeric, optional, default 0=estimate) Set a specific feerate (fee per KB)\n" " }\n" " for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}\n" "\nResult:\n" @@ -2484,6 +2485,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) int changePosition = -1; bool includeWatching = false; bool lockUnspents = false; + CFeeRate feeRate = CFeeRate(0); if (params.size() > 1) { if (params[1].type() == UniValue::VBOOL) { @@ -2495,7 +2497,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) UniValue options = params[1]; - RPCTypeCheckObj(options, boost::assign::map_list_of("changeAddress", UniValue::VSTR)("changePosition", UniValue::VNUM)("includeWatching", UniValue::VBOOL)("lockUnspents", UniValue::VBOOL), true, true); + RPCTypeCheckObj(options, boost::assign::map_list_of("changeAddress", UniValue::VSTR)("changePosition", UniValue::VNUM)("includeWatching", UniValue::VBOOL)("lockUnspents", UniValue::VBOOL)("feeRate", UniValue::VNUM), true, true); if (options.exists("changeAddress")) { CBitcoinAddress address(options["changeAddress"].get_str()); @@ -2514,6 +2516,9 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) if (options.exists("lockUnspents")) lockUnspents = options["lockUnspents"].get_bool(); + + if (options.exists("feeRate")) + feeRate = CFeeRate(options["feeRate"].get_real()); } } @@ -2529,16 +2534,16 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds"); CMutableTransaction tx(origTx); - CAmount nFee; + CAmount nFeeOut; string strFailReason; - if(!pwalletMain->FundTransaction(tx, nFee, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress)) + if(!pwalletMain->FundTransaction(tx, nFeeOut, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress)) throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); UniValue result(UniValue::VOBJ); result.push_back(Pair("hex", EncodeHexTx(tx))); result.push_back(Pair("changepos", changePosition)); - result.push_back(Pair("fee", ValueFromAmount(nFee))); + result.push_back(Pair("fee", ValueFromAmount(nFeeOut))); return result; } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 29d7138547..6b5e3ca7f5 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1918,7 +1918,7 @@ bool CWallet::SelectCoins(const vector& vAvailableCoins, const CAmount& return res; } -bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange) +bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange) { vector vecSend; @@ -1933,6 +1933,8 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC coinControl.destChange = destChange; coinControl.fAllowOtherInputs = true; coinControl.fAllowWatchOnly = includeWatching; + coinControl.nFeeRate = specificFeeRate; + BOOST_FOREACH(const CTxIn& txin, tx.vin) coinControl.Select(txin.prevout); @@ -2242,6 +2244,8 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { nFeeNeeded = coinControl->nMinimumTotalFee; } + if (coinControl && coinControl->nFeeRate > CFeeRate(0)) + nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); // If we made it here and we aren't even able to meet the relay fee on the next pass, give up // because we must be at the maximum allowed fee. diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index c3bd343edd..7b5168975c 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -740,7 +740,7 @@ public: * Insert additional inputs into the transaction by * calling CreateTransaction(); */ - bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange = CNoDestination()); + bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange = CNoDestination()); /** * Create a new transaction paying the recipients with a set of coins -- cgit v1.2.3 From 04eaa9095813b854c4299027c595fb9ebaf6f934 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Fri, 6 May 2016 11:01:50 +0200 Subject: Add more clear interface for CoinControl.h regarding individual feerate --- src/coincontrol.h | 5 ++++- src/wallet/rpcwallet.cpp | 6 +++++- src/wallet/wallet.cpp | 5 +++-- src/wallet/wallet.h | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/coincontrol.h b/src/coincontrol.h index 6129397bc8..e33adc4d2b 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -18,7 +18,9 @@ public: bool fAllowWatchOnly; //! Minimum absolute fee (not per kilobyte) CAmount nMinimumTotalFee; - //! Feerate to use (0 = estimate fee with payTxFee fallback) + //! Override estimated feerate + bool fOverrideFeeRate; + //! Feerate to use if overrideFeeRate is true CFeeRate nFeeRate; CCoinControl() @@ -34,6 +36,7 @@ public: setSelected.clear(); nMinimumTotalFee = 0; nFeeRate = CFeeRate(0); + fOverrideFeeRate = false; } bool HasSelected() const diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b14d748b39..933cd1e807 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2486,6 +2486,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) bool includeWatching = false; bool lockUnspents = false; CFeeRate feeRate = CFeeRate(0); + bool overrideEstimatedFeerate = false; if (params.size() > 1) { if (params[1].type() == UniValue::VBOOL) { @@ -2518,7 +2519,10 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) lockUnspents = options["lockUnspents"].get_bool(); if (options.exists("feeRate")) + { feeRate = CFeeRate(options["feeRate"].get_real()); + overrideEstimatedFeerate = true; + } } } @@ -2537,7 +2541,7 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp) CAmount nFeeOut; string strFailReason; - if(!pwalletMain->FundTransaction(tx, nFeeOut, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress)) + if(!pwalletMain->FundTransaction(tx, nFeeOut, overrideEstimatedFeerate, feeRate, changePosition, strFailReason, includeWatching, lockUnspents, changeAddress)) throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason); UniValue result(UniValue::VOBJ); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 6b5e3ca7f5..96c5c416aa 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1918,7 +1918,7 @@ bool CWallet::SelectCoins(const vector& vAvailableCoins, const CAmount& return res; } -bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange) +bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange) { vector vecSend; @@ -1933,6 +1933,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, const C coinControl.destChange = destChange; coinControl.fAllowOtherInputs = true; coinControl.fAllowWatchOnly = includeWatching; + coinControl.fOverrideFeeRate = overrideEstimatedFeeRate; coinControl.nFeeRate = specificFeeRate; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -2244,7 +2245,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, CWalletTx& wt if (coinControl && nFeeNeeded > 0 && coinControl->nMinimumTotalFee > nFeeNeeded) { nFeeNeeded = coinControl->nMinimumTotalFee; } - if (coinControl && coinControl->nFeeRate > CFeeRate(0)) + if (coinControl && coinControl->fOverrideFeeRate) nFeeNeeded = coinControl->nFeeRate.GetFee(nBytes); // If we made it here and we aren't even able to meet the relay fee on the next pass, give up diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 7b5168975c..7a9e306f6f 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -740,7 +740,7 @@ public: * Insert additional inputs into the transaction by * calling CreateTransaction(); */ - bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange = CNoDestination()); + bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, bool overrideEstimatedFeeRate, const CFeeRate& specificFeeRate, int& nChangePosInOut, std::string& strFailReason, bool includeWatching, bool lockUnspents, const CTxDestination& destChange = CNoDestination()); /** * Create a new transaction paying the recipients with a set of coins -- cgit v1.2.3