diff options
author | Samuel Dobson <dobsonsa68@gmail.com> | 2020-08-17 15:56:49 +1200 |
---|---|---|
committer | Samuel Dobson <dobsonsa68@gmail.com> | 2020-08-17 16:18:28 +1200 |
commit | c831e105c567420aa4d3f60c6675a229daaf5fe6 (patch) | |
tree | 2bf957b7e91c6e30767c4eb8a4c2053d26a1f429 /src/wallet/wallet.cpp | |
parent | ffad34816722cdf27a0a7c16539ddd1d655602e0 (diff) | |
parent | 7f13dfb587dd6a7a5b7dfbfe689ae0ce818fe5c9 (diff) |
Merge #14582: wallet: always do avoid partial spends if fees are within a specified range
7f13dfb587dd6a7a5b7dfbfe689ae0ce818fe5c9 test: test the implicit avoid partial spends functionality (Karl-Johan Alm)
b82067bf696c53f22536f9ca2e51949c164f6b06 wallet: try -avoidpartialspends mode and use its result if fees are below threshold (Karl-Johan Alm)
Pull request description:
The `-avoidpartialspends` feature is normally disabled, as it may affect the optimal fee for payments. This PR introduces a new parameter `-maxapsfee` (max avoid partial spends fee) which acts on the following values:
* -1: disable partial spend avoidance completely (do not even try it)
* 0: only do partial spend avoidance if fees are the same or better as the regular coin selection
* 1..∞: use APS variant if the absolute fee difference is less than or equal to the max APS fee
For values other than -1, the code will now try partial spend avoidance once, and if that gives a value within the accepted range, it will use that.
Example: -maxapsfee=0.00001000 means the wallet will do regular coin select, APS coin select, and then pick AKS iff the absolute fee difference is <= 1000 satoshi.
Edit: updated this to reflect the fact we are now using a max fee.
ACKs for top commit:
fjahr:
tested ACK 7f13dfb587dd6a7a5b7dfbfe689ae0ce818fe5c9
achow101:
ACK 7f13dfb587dd6a7a5b7dfbfe689ae0ce818fe5c9
jonatack:
ACK 7f13dfb58, code review, debug build, verified the test fails with `AssertionError: not(2 == 1)` for the number of vouts when `-maxapsfee=0.0001` is changed to 0, and verified the new logging with an added assertion.
meshcollider:
Code review ACK 7f13dfb587dd6a7a5b7dfbfe689ae0ce818fe5c9
Tree-SHA512: 475929df57f6191bb4e36bfbcad5a280a64bb0ecd8767b76cb2e44e2301235d0eb294a3f2fac5bbf15d35d7ecfba47acb2285feadb883c9ce31c08377e3afb3c
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r-- | src/wallet/wallet.cpp | 57 |
1 files changed, 56 insertions, 1 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 9c7b446c23..ac03b3ca9c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2677,7 +2677,14 @@ OutputType CWallet::TransactionChangeType(const Optional<OutputType>& change_typ return m_default_address_type; } -bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, bool sign) +bool CWallet::CreateTransactionInternal( + const std::vector<CRecipient>& vecSend, + CTransactionRef& tx, + CAmount& nFeeRet, + int& nChangePosInOut, + bilingual_str& error, + const CCoinControl& coin_control, + bool sign) { CAmount nValue = 0; const OutputType change_type = TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : m_default_change_type, vecSend); @@ -3032,6 +3039,39 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CTransac return true; } +bool CWallet::CreateTransaction( + const std::vector<CRecipient>& vecSend, + CTransactionRef& tx, + CAmount& nFeeRet, + int& nChangePosInOut, + bilingual_str& error, + const CCoinControl& coin_control, + bool sign) +{ + int nChangePosIn = nChangePosInOut; + CTransactionRef tx2 = tx; + bool res = CreateTransactionInternal(vecSend, tx, nFeeRet, nChangePosInOut, error, coin_control, sign); + // try with avoidpartialspends unless it's enabled already + if (res && nFeeRet > 0 /* 0 means non-functional fee rate estimation */ && m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) { + CCoinControl tmp_cc = coin_control; + tmp_cc.m_avoid_partial_spends = true; + CAmount nFeeRet2; + int nChangePosInOut2 = nChangePosIn; + bilingual_str error2; // fired and forgotten; if an error occurs, we discard the results + if (CreateTransactionInternal(vecSend, tx2, nFeeRet2, nChangePosInOut2, error2, tmp_cc, sign)) { + // if fee of this alternative one is within the range of the max fee, we use this one + const bool use_aps = nFeeRet2 <= nFeeRet + m_max_aps_fee; + WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n", nFeeRet, nFeeRet2, use_aps ? "grouped" : "non-grouped"); + if (use_aps) { + tx = tx2; + nFeeRet = nFeeRet2; + nChangePosInOut = nChangePosInOut2; + } + } + } + return res; +} + void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm) { LOCK(cs_wallet); @@ -3849,6 +3889,21 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, walletInstance->m_min_fee = CFeeRate(n); } + if (gArgs.IsArgSet("-maxapsfee")) { + CAmount n = 0; + if (gArgs.GetArg("-maxapsfee", "") == "-1") { + n = -1; + } else if (!ParseMoney(gArgs.GetArg("-maxapsfee", ""), n)) { + error = AmountErrMsg("maxapsfee", gArgs.GetArg("-maxapsfee", "")); + return nullptr; + } + if (n > HIGH_APS_FEE) { + warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") + + _("This is the maximum transaction fee you pay to prioritize partial spend avoidance over regular coin selection.")); + } + walletInstance->m_max_aps_fee = n; + } + if (gArgs.IsArgSet("-fallbackfee")) { CAmount nFeePerK = 0; if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) { |