New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
estimatefee / estimatepriority RPC methods #3959
Conversation
return i | ||
return -1 | ||
|
||
def gather_inputs(from_node, amount_needed): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of this stuff looks like it should be in a utility library (the main function too), otherwise it's getting copy/pasted everywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving useful functions to util.py, but am going to hold off on moving main; there's another pull request that bundles everything up into a framework...
Rebased on master, and tweaked to address Mike's comments (thanks for the review!). |
Pull-tester errors were with the regression test: pull-tester is running python 2.6 (fixed by using subprocess.check_call instead of python2.7 subprocess.check_output). |
What's the status of this work? Does it need more review or testing or what? |
It's queued to be merged for 0.10, so after the 0.9.2 branch split-off. |
@@ -610,19 +595,19 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) | |||
|
|||
// tool tips | |||
QString toolTip1 = tr("This label turns red, if the transaction size is greater than 1000 bytes.") + "<br /><br />"; | |||
toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::nMinTxFee)) + "<br /><br />"; | |||
toolTip1 += tr("This means a fee of at least %1 per kB is required.").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, CTransaction::minTxFee.GetFee(1000))) + "<br /><br />"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: There are a lot of getFee(1000)'s. I don't have an objection to them, although on first reading I was confused ('what is this magic 1000 number'). But instead of suggesting defining a constant BYTES_PER_KB :p I think it would be nicer to have a function getFeePerKB() that's simply an inline for getFee(1000).
Nit-picked : replace GetFee(1000) with inline GetFeePerK() method. |
Rebased on master. I'm very happy with how quickly this generates good estimates; after just three or four blocks it has a good idea of what priority or fee is needed to get into the next couple of blocks. |
Save/restore of the mempool seems quite dangerous in making some unconfirmed transactions potentially live forever in the network... |
Nod -- you only want to save/restore once we have transactions expiring from the mempool (janitor etc.) after X blocks. |
@sipa Yup. Even with expiration it makes many DoS attacks and similar vulnerabilities much more effective. For instance OOM crashes are hard to exploit right now because the txs are hard to propagate; not true with save restore. |
In general, lacking other tools, clearing the mempool [implicitly] at startup is a valuable tool. |
Consensus is saving/restoring memory pool is dangerous, so I've removed that functionality. Fee estimates ARE saved/restored, to datadir fee_estimates.dat file. |
Use CFeeRate instead of an int64_t for quantities that are fee-per-size. Helps prevent unit-conversion mismatches between the wallet, relaying, and mining code.
Choose ports at startup based on PID, so multiple regression tests can run on the same system at the same time.
New RPC methods: return an estimate of the fee (or priority) a transaction needs to be likely to confirm in a given number of blocks. Mike Hearn created the first version of this method for estimating fees. It works as follows: For transactions that took 1 to N (I picked N=25) blocks to confirm, keep N buckets with at most 100 entries in each recording the fees-per-kilobyte paid by those transactions. (separate buckets are kept for transactions that confirmed because they are high-priority) The buckets are filled as blocks are found, and are saved/restored in a new fee_estiamtes.dat file in the data directory. A few variations on Mike's initial scheme: To estimate the fee needed for a transaction to confirm in X buckets, all of the samples in all of the buckets are used and a median of all of the data is used to make the estimate. For example, imagine 25 buckets each containing the full 100 entries. Those 2,500 samples are sorted, and the estimate of the fee needed to confirm in the very next block is the 50'th-highest-fee-entry in that sorted list; the estimate of the fee needed to confirm in the next two blocks is the 150'th-highest-fee-entry, etc. That algorithm has the nice property that estimates of how much fee you need to pay to get confirmed in block N will always be greater than or equal to the estimate for block N+1. It would clearly be wrong to say "pay 11 uBTC and you'll get confirmed in 3 blocks, but pay 12 uBTC and it will take LONGER". A single block will not contribute more than 10 entries to any one bucket, so a single miner and a large block cannot overwhelm the estimates.
ACK. Speaking conservatively, appears to be low impact as implemented at first glance. The largest impact is to existing operations is the hook that is executed when a block appears, necessitating the removal of TXs from the mempool. At a quick glance, it was difficult to discern the big-O() of this operation, but at least it is all in CPU/RAM, and only executed once per incoming new block. One nit (perhaps for post merge): I don't like the mempool itself doing the reading. Would prefer a helper function outside the mempool class that perform the necessary I/O. Our normal pattern is a pure implement-serialize chain until actual file I/O is needed. This seems to mix metaphors a bit more than usual. |
@@ -536,26 +536,11 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) | |||
{ | |||
nChange = nAmount - nPayFee - nPayAmount; | |||
|
|||
// if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't we want to keep this block, but do it to prevent dust change rather than subcent change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dust change is handled at line 543.
Automatic sanity-testing: FAILED BUILD/TEST, see http://jenkins.bluematt.me/pull-tester/171ca7745e77c9f78f26556457fe64e5b2004a75 for binaries and test log. This could happen for one of several reasons:
If you believe this to be in error, please ping BlueMatt on freenode or TheBlueMatt here. This test script verifies pulls every time they are updated. It, however, dies sometimes and fails to test properly. If you are waiting on a test, please check timestamps to verify that the test.log is moving at http://jenkins.bluematt.me/pull-tester/current/ |
If mempool saving ever comes back as a proposal we should keep in mind that doing so presents a pretty strong watermarking attack. (... not that we don't have many other watermarking attacks.) |
New RPC methods: return an estimate of the fee (or priority) a transaction needs to be likely to confirm in a given number of blocks.
Fee-per-kilobyte estimates for 1..10 confirmations from this code:
Mike Hearn created the first version of this method for estimating fees.
It works as follows:
For transactions that took 1 to N (I picked N=25) blocks to confirm, keep N buckets with at most 100 entries in each recording the fees-per-kilobyte paid by those transactions.
(separate buckets are kept for transactions that confirmed because they are high-priority)
The buckets are filled as blocks are found, and are saved/restored as part of the mempool.dat file.
A few variations on Mike's initial scheme:
To estimate the fee needed for a transaction to confirm in X buckets, all of the samples in all of the buckets are used and a median of all of the data is used to make the estimate. For example, imagine
25 buckets each containing the full 100 entries. Those 2,500 samples are sorted, and the estimate of the fee needed to confirm in the very next block is the 50'th-highest-fee-entry in that sorted list; the estimate of the fee needed to confirm in the next two blocks is the 150'th-highest-fee-entry, etc.
That algorithm has the nice property that estimates of how much fee you need to pay to get confirmed in block N will always be greater than or equal to the estimate for block N+1. It would clearly be wrong
to say "pay 11 uBTC and you'll get confirmed in 3 blocks, but pay 12 uBTC and it will take LONGER".
A single block will not contribute more than 10 entries to any one bucket, so a single miner and a large block cannot overwhelm the estimates.