Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
More economical fee estimates for RBF and RPC options to control #10589
Conversation
|
Concept ACK, this is really great and something that's been needed for a long time. It'll simplify some of the locking and But it'd be nice if it used an But I guess that's something that can be done in a different commit, with |
|
@RHavar I had the same exact reaction fwiw. |
|
I thought the whole point of named arguments is we didn't have to worry about that any more. I think I made sure these work correctly with holes so we can use them with named arguments. |
|
Oh yeah, you're right. Guess I should learn how to use named arguments. |
fanquake
added RPC/REST/ZMQ Wallet
labels
Jun 15, 2017
|
Needs rebase. |
|
Rebased due to conflict with #10422 |
| - "\nResult:\n" | ||
| + "6. opt_in_rbf (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees\n" | ||
| + "7. conf_target (numeric, optional) Confirmation target (in blocks)\n" | ||
| + "8. conservative_estimate (boolean, optional) Use conservative (potentially higher) fee estimation\n" |
laanwj
Jun 22, 2017
•
Owner
I'd prefer to use a string here (which maps to FeeEstimateMode) instead of a boolean. This would also allow adding additional fee estimation strategies in the future without changing the interface.
(if we keep it this way, it should be documented that this is really a tri-value boolean, where null/unset is auto)
|
Concept ACK |
morcos
referenced
this pull request
Jun 27, 2017
Closed
More economical fee estimates for opt-in-RBF transactions #10586
morcos
changed the title from
Add RPC options for RBF, confirmation target and conservative fee estimates to More economical fee estimates for RBF and RPC options to control
Jun 27, 2017
|
Switched to an estimate_mode string and squashed |
|
Changed argument name from opt_in_rbf to replaceable for conformance with bumpfee |
This was referenced Jun 28, 2017
laanwj
added
to Blockers in High-priority for review
Jun 29, 2017
| @@ -4145,3 +4148,14 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& | ||
| { | ||
| return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee); | ||
| } | ||
| + | ||
| +bool CalculateEstimateType(FeeEstimateMode mode) { |
instagibbs
Jul 3, 2017
Member
Not sure this is the best possible name. ConservativeEstimateRequested ?
TheBlueMatt
Jul 6, 2017
Contributor
I think it makes more sense to let it be generic and ideally estimatesmartfee would take a FeeEstimateMode and this functions purpose would be to take any requested mode and other wallet parameters and use wallet logic to determine a final mode. Rather than make all those changes now while not yet needed though, I think I'll just change the RPC interface to conservative estimates to take a string as per #10589 (review)
I stand entirely unconvinced that you shouldn't just do this now - just add more args (or add a struct arg) to GetMinimumFee instead of adding some new function that returns some magic value that you then immediately go and pass into GetMinimumFee everywhere?
morcos
Jul 6, 2017
Contributor
Please see #10706
CalculateEstimateType is now only used one place, in GetMinimumFee.
TheBlueMatt
reviewed
Jul 6, 2017
I still dont really feel comfortable ACKing the Qt changes until I get a chance to test, but this is generally a very welcome improvement.
| @@ -4145,3 +4148,14 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& | ||
| { | ||
| return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee); | ||
| } | ||
| + | ||
| +bool CalculateEstimateType(FeeEstimateMode mode) { |
TheBlueMatt
Jul 6, 2017
Contributor
I think it makes more sense to let it be generic and ideally estimatesmartfee would take a FeeEstimateMode and this functions purpose would be to take any requested mode and other wallet parameters and use wallet logic to determine a final mode. Rather than make all those changes now while not yet needed though, I think I'll just change the RPC interface to conservative estimates to take a string as per #10589 (review)
I stand entirely unconvinced that you shouldn't just do this now - just add more args (or add a struct arg) to GetMinimumFee instead of adding some new function that returns some magic value that you then immediately go and pass into GetMinimumFee everywhere?
| + if (boost::optional<FeeEstimateMode> fee_mode = FeeModeForString(request.params[7].get_str())) { | ||
| + coin_control.m_fee_mode = *fee_mode; | ||
| + } | ||
| + else { |
TheBlueMatt
Jul 6, 2017
Contributor
Nit: no need for the \n here (and a few other similar lines in this file.).
jonasschnelli
added this to the
0.15.0
milestone
Jul 6, 2017
| @@ -166,6 +166,8 @@ void SendCoinsDialog::setModel(WalletModel *_model) | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); | ||
| + connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel())); | ||
| + connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); |
TheBlueMatt
Jul 9, 2017
Contributor
Cant comment there, but I believe you also need to move the default setting of optInRBF up a bunch here (about 10 lines below this (set default rbf checkbox state, or does that setting automagically result in calling these registrations?).
morcos
Jul 10, 2017
Contributor
Not sure if I understand your question (or how QT works) but I'm pretty sure it's correct as is. Calling setCheckState below will trigger the signal if the checkbox changed from its initial value.
promag
Jul 10, 2017
Contributor
Either way, what about make an explicit call to coinControlUpdateLabels()?
morcos
Jul 10, 2017
Contributor
I don't think this is necessary. It's analogous to setting the default sliderSmartFee done in the same section of code.
promag
reviewed
Jul 10, 2017
IMO this would be a cleaner implementation
bool FeeEstimateModeFromString(const std::string& string, FeeEstimateMode& fee_estimate_mode)
{
// lookup string
return false;
}
...
if (!FeeEstimateModeFromString(request.params[7].get_str(), coin_control.m_fee_mode)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, ...);
}| @@ -401,7 +401,7 @@ UniValue sendtoaddress(const JSONRPCRequest& request) | ||
| return NullUniValue; | ||
| } | ||
| - if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) | ||
| + if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) | ||
| throw std::runtime_error( | ||
| "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount )\n" |
| @@ -416,6 +416,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request) | ||
| " transaction, just kept in your wallet.\n" | ||
| "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" | ||
| " The recipient will receive less bitcoins than you enter in the amount field.\n" | ||
| + "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n" |
promag
Jul 11, 2017
Contributor
I understand, but for those that use indexed arguments, they have to pass the middle arguments.
| @@ -416,6 +416,12 @@ UniValue sendtoaddress(const JSONRPCRequest& request) | ||
| " transaction, just kept in your wallet.\n" | ||
| "5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent.\n" | ||
| " The recipient will receive less bitcoins than you enter in the amount field.\n" | ||
| + "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n" | ||
| + "7. conf_target (numeric, optional) Confirmation target (in blocks)\n" | ||
| + "8. \"estimate_mode\" (string, optional, default=UNSET) The fee estimate mode, must be one of:\n" |
morcos
Jul 10, 2017
Contributor
Hmm.. Yes, I think it might make sense to change this to fee_mode, but leave it estimate_mode for estimateSmartFee (done in another PR). Even though they take the same values now, I could imagine they would differ in the future. Any other thoughts?
promag
Jul 10, 2017
Contributor
I just wanted to point out the inconsistencies between arguments, variable names and types.
morcos
Jul 10, 2017
Contributor
I decided leaving it as estimate_mode in both RPC's is preferable.
The inconsistency between variable and parameter name is not worth the churn imo.
| @@ -910,7 +935,13 @@ UniValue sendmany(const JSONRPCRequest& request) | ||
| " \"address\" (string) Subtract fee from this address\n" | ||
| " ,...\n" | ||
| " ]\n" | ||
| - "\nResult:\n" | ||
| + "6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125\n" |
promag
Jul 10, 2017
Contributor
I saw the above comment about named arguments. IMO from the client side feels better as an option.
| @@ -166,6 +166,8 @@ void SendCoinsDialog::setModel(WalletModel *_model) | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateGlobalFeeVariables())); | ||
| connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); | ||
| + connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(updateSmartFeeLabel())); | ||
| + connect(ui->optInRBF, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); |
promag
Jul 10, 2017
Contributor
Either way, what about make an explicit call to coinControlUpdateLabels()?
| @@ -26,6 +27,8 @@ class CCoinControl | ||
| int nConfirmTarget; | ||
| //! Signal BIP-125 replace by fee. | ||
| bool signalRbf; | ||
| + //! Fee estimation mode to control arguments to estimateSmartFee | ||
| + FeeEstimateMode m_fee_mode; |
| @@ -4154,3 +4157,15 @@ bool CMerkleTx::AcceptToMemoryPool(const CAmount& nAbsurdFee, CValidationState& | ||
| { | ||
| return ::AcceptToMemoryPool(mempool, state, tx, true, NULL, NULL, false, nAbsurdFee); | ||
| } | ||
| + | ||
| +bool CalculateEstimateType(FeeEstimateMode mode, bool opt_in_rbf) { |
morcos
Jul 10, 2017
Contributor
yeah but who cares, its going away completely in a couple of commits
|
Took some of the nits |
|
As suggested in another PR, the first condition can be removed since |
|
utACK f135923 |
laanwj
merged commit f135923
into
bitcoin:master
Jul 11, 2017
1 check passed
laanwj
added a commit
that referenced
this pull request
Jul 11, 2017
|
|
laanwj |
104f5f2
|
laanwj
removed
from Blockers in High-priority for review
Jul 11, 2017
This was referenced Jul 11, 2017
laanwj
added a commit
that referenced
this pull request
Jul 17, 2017
|
|
laanwj |
6859ad2
|
morcos commentedJun 14, 2017
•
edited
This PR takes advantage of the new fee estimation feature that will potentially give lower estimates if recent market conditions warrant it. The logic used here is that any time a transaction signals opt-in-RBF and uses automatic fee estimation then it will use the non-conservative estimate. Transactions which do not signal opt-in-RBF will still use the default conservative estimate.
In a nutshell conservative estimates require that your fee rate would meet the necessary confirmation threshold for double your target at longer time horizons as well. This reduces the likelihood that you place a transaction just as the market is starting to get busy again that ends up being stuck for a very long time.
This PR also allows the specification of transaction confirmation target and whether the estimate should be conservative or not on a per-RPC call basis for sendtoaddress, sendmany, bumpfee, and fundrawtransaction using optional named arguments.
Left as an exercise to the reader is adding this to GUI functions to send transactions and bump fee.