-
Notifications
You must be signed in to change notification settings - Fork 37.7k
Store mempool and prioritization data to disk #8448
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
Conversation
We'll need to add |
Why not behind a command line flag? |
Concept ACK.
Agreed. It can be enabled by default. |
@@ -6794,6 +6793,107 @@ ThresholdState VersionBitsTipState(const Consensus::Params& params, Consensus::D | |||
return VersionBitsState(chainActive.Tip(), params, pos, versionbitscache); | |||
} | |||
|
|||
bool LoadMempool(void) | |||
{ | |||
FILE* filestr = fopen((GetDataDir() / "mempool.dat").c_str(), "r"); |
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.
.string().c_str()
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.
Seems to work fine?
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.
Nono, travis failed because of this (https://travis-ci.org/bitcoin/bitcoin/jobs/149377465#L2149).
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.
IIRC the fopen
parameters are restrict
(or often are in the impl), and assumed to be there for the lifetime of the file pointer... I don't think this temporary holds those variants and might cause UB?
I could be wrong.
edit: that may only be in the C standard, not C++
I suspect it is completely irrelevant, seeing how prevalent this pattern is throughout the code.
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.
restrict means the argument is assumed not to alias any other parameter, I think?
Concept ACK
As we dump raw txes from the mempool, this will conflict with current status of "antivirus-compliant" storage and dumping |
2016-08-03 07:29:00 Dumped mempool: 1.9e-05s to copy, 0.005925s to dump |
A fair point. Though a missing, or corrupted mempool.dat should never cause bitcoind to stop running. At most this will lose the mempool contents (at next start) due to the file being quarantined. |
More XOR? |
Indeed this probably should be XOR'd with a random key. |
AV can be configured to stop |
Concept ACK and the code size is surprisingly small! The only thing that I miss (not directly related to this PR) is an opportunity to keep a history of some major mempool data (feerate, size, tx rate, etc.). Another option would be keeping ~24*6 dumps per day that would could be stored in file-diff-deltas to allow generating any types of statistics. |
I don't really see a huge benefit in doing this. It seems like unless you are immediately restarting, you'll be wasting a lot of time trying to load already confirmed transactions or low fee spam. That said I don't object to making it a command line argument, but I would suggest it default to off. What's the rationale for running it every 10 minutes? You can copy it from one running node to start another or to handle crashes? |
I think it should be off by default. And when it is, we can even skip XORing it, I think as it is expert level feature anyway. Or the other way: create a RPC to dump mempool and that's all. But this way we loose the save-on-restart feature which is nice (which can be worked around by |
@morcos The reason for dumping every 10 minutes is so that prioritization data is not lost in case of a crash. But perhaps we should have separate files for that. prioritization.dat which is continuously dumped (maybe only after mapDeltas changed?), and mempool.dat which is only saved at shutdown? |
Could it help to save the current block height to the mempool.dat and then discard mempool.dat on start when current height > 3 + height when mempool was saved? |
This has split into two threads, really:
Persisting bits of state like prio deltas is useful, and seems applicable to a continuous-log or database solution, that can be restored at startup. As for mempool restore... Standard rhetorical questions: Who will really use mempool restore, and how often?
mempool restore seems likely to be a little used, expert-only feature. |
Somewhat agreed, and as a regular 'power' user of bitcoind, I personally already have my own RPC calls equivalent to |
@jgarzik This is functionality directly requested by miners, the absence of it creates an operational burden because nodes then end up making small blocks after being restarted.
This isn't useful without the transactions themselves-- peers will not re-relay transactions they previously sent. So you could save priorities, but all of them would be almost completely useless.
Indeed, if it takes a long time that is an issue. But this should be writing no more than about 150 MB of data, which should take under a second. If it's taking a long time then that needs to be addressed. One solution if that is an issue is to simply not write it at shutdown, but to only use the regular snapshots.
I don't follow how remote attackers interact here; it wouldn't make sense to have any of this behavior be remotely triggerable.
It takes several hours for a full mempool to lose its utility. I suppose it would be reasonable to not even bother trying to load it if it's more than three days old. Mempool sync is also a bandwidth concern for future mempool sync efforts-- if it's lost on restart, than every quick restart would waste bandwidth. Similarly for block transmission-- latency and bandwidth usage will be adversely effected if mempool is lost on restart. It takes about 12 hours in my tests for a node to recover its compact block reconstruction performance after restart, and it can take several seconds to accept a block due to the empty signature cache. These pressures against restart are an operational burden, because then you're pressured to try to find ways to avoid restarting-- e.g. running extra nodes, or avoiding changing settings. Separately, the cold mempool means that users and developers spend time in a non-representative state after they try changing settings; which makes it much harder to iterate around settings changes. ( Sorry if some of these points are redundant with #8433 ) |
Concept ACK, and a very useful feature! Though I'd suggest making it off by default for now so that nodes that don't need this don't have the risk of a bug creating a restart loop - less risk if we start in a clean state by default. |
@petertodd With the exception of the priority deltas the transactions are going through normal mempool accept logic. I can't see this causing a restart loop unless there's a bug in the priority handling logic or a remotely exploitable DoS issue anyways. |
Which may only be trigger-able under particular circumstance, of which may be captured in the current mempool state? |
@pstratem Hmm, that's a good point. Also, as long as we're only saving the mempool in a normal, user-triggered, shutdown all transactions in the saved mempool should be fine. I'll take back my objection. |
Eloipool does a save/restore state when it restarts, and one thing it does is write a timestamp early on in the dump. This way, when loading from the dump, it can see if the data is irrelevant and ignore the file. Perhaps that would make sense here too? Any reason to write out the entire thing every interval, rather than just having another LevelDB database? |
@gmaxwell Those concerns seem to be met by remote mempool download also, which @morcos suggested elsewhere in the thread -- and indeed was one original purpose of BIP 35 mempool message -- maintaining miner's mempools and not losing lucrative miner fees due to restart. Remote download over LAN is also potentially faster, something Google noticed when seeing increased performance through remote page caches: http://static.googleusercontent.com/media/research.google.com/en//pubs/archive/43886.pdf Remote download also gets you fresh transactions which the db/log will not have - fuller blocks, more miners fees.
The relevant portion that answers your confusion was elided: "Alternatives to dump-on-shutdown [...]" This refers to, e.g. periodic dumps, streaming transactions to a leveldb or WAL log, which occur at runtime not shutdown. |
Preservation of the mempool is a prerequisite for mempool sync. Otherwise you'd have 150 MB of transfer (burning resources of remote nodes) each time someone restarts to twiddle some configure. I think the mempool message is unsuitable for synchronization generally, due to overhead. [and while the latency concerns related to compact blocks would be addressed by a bulk download, the bandwidth savings would be lost]
In Google datacenters not on our P2P network; in any case I believe the load is bottlenecked on any ordinary host. (and were it faster, it wouldn't matter-- resource usage needs to be heavily weighed).
There isn't any leveldb involved here; but regardless-- I still don't see where the "remote attackers" part that I was asking about comes in. |
Notable how remote mempool load on startup could be increase the effects of a DoS attack due to all the extra bandwidth wasted as nodes restart after crashing; it'd be especially harmful if a remote crash exploit could be found if people ever setup nodes to restart automatically. On 3 August 2016 21:56:34 GMT-07:00, Gregory Maxwell notifications@github.com wrote:
|
|
Rebased with the following changes:
XORed dump is not implemented, this can be done later. As the regular dump seemed controversial, I've removed it now (it can always be added back later). |
file.fclose(); | ||
RenameOver(GetDataDir() / "mempool.dat.new", GetDataDir() / "mempool.dat"); | ||
int64_t last = GetTimeMicros(); | ||
LogPrintf("Dumped mempool: %gs to copy, %gs to dump\n", (mid-start)*0.000001, (last-mid)*0.000001); |
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.
This results in
2016-11-01 08:30:08 Dumped mempool: 1.9e-05s to copy, 0.006452s to dump
here on testnet. What about using ms instead?
ACK 582068a XOR dumping nit can be ignored now, because we are dumping mempool on shutdown only. |
@sipa sorry for commenting on this late, but could we have made it a bit more efficient by storing mapDeltas before the transactions, so then we don't have to do 2 loops of prioritiseTransaction? not sure if its worth it to change now.... |
@morcos This is not in released version, so I think if there is a benefit, we can still change it. And of course, we can safely ignore this file every time... |
Github-Pull: bitcoin#8448 Rebased-From: c3efb58
Github-Pull: bitcoin#8448 Rebased-From: ced7c94
Github-Pull: bitcoin#8448 Rebased-From: 3f78562
Github-Pull: bitcoin#8448 Rebased-From: 582068a
9b9c616 Fix missing zapwallettxes mode in wallet_hd.py functional test (furszy) d6d0ad9 [logs] fix zapwallettxes startup logs (John Newbery) 006c503 [wallet] fix zapwallettxes interaction with persistent mempool (John Newbery) c6d45c6 Adapting and connecting mempool_persist.py functional test to the test runner. (furszy) 4f26a4e Control mempool persistence using a command line parameter. (John Newbery) 5d949de [Qt] Do proper shutdown (Jonas Schnelli) e60da98 Allow shutdown during LoadMempool, dump only when necessary (Jonas Schnelli) c0a0e81 Moving TxMempoolInfo tx member to CTransactionRef (furszy) f0c2255 Add mempool.dat to doc/files.md (furszy) 8e52226 Add DumpMempool and LoadMempool (Pieter Wuille) 44c635d Add AcceptToMemoryPoolWithTime function (Pieter Wuille) 6bbc6a9 Add feedelta to TxMempoolInfo (Pieter Wuille) 9979f3d [mempool] move removed and conflicts transaction ref list to vector. (furszy) 4f672c2 Make removed and conflicted arguments optional to remove (Pieter Wuille) e51c4b8 Bypass removeRecursive in removeForReorg (Pieter Wuille) 54cf7c0 Get rid of CTxMempool::lookup() entirely (furszy) 35bc2a9 Finished the switch CTransaction storage in mempool to CTransactionRef and introduced the timeLastMempoolReq coming from btc#8080. (furszy) d10583b An adapted version of btc@b5599147533103efea896a1fc4ff51f2d3ad5808 (furszy) cb4fc6c An adapted version of btc@ed7068302c7490e8061cb3a558a0f83a465beeea (furszy) 9645775 Split up and optimize transaction and block inv queues (furszy) 68bc68f Don't do mempool lookups for "mempool" command without a filter (furszy) 7624823 mapNextTx: use pointer as key, simplify value (furszy) 191c62e Return mempool queries in dependency order (Pieter Wuille) 23c9f3e Eliminate TX trickle bypass, sort TX invs for privacy and priority. (furszy) 6ebfd17 tiny test fix for mempool_tests (Alex Morcos) 8c0016e Check all ancestor state in CTxMemPool::check() (furszy) 91c6096 Add ancestor feerate index to mempool (Suhas Daftuar) 64e84e2 Add ancestor tracking to mempool This implements caching of ancestor state to each mempool entry, similar to descendant tracking, but also including caching sigops-with-ancestors (as that metric will be helpful to future code that implements better transaction selection in CreatenewBlock). (furszy) 8325bb4 Fix mempool limiting for PrioritiseTransaction Redo the feerate index to be based on mining score, rather than fee. (furszy) 1fa40ac Remove work limit in UpdateForDescendants() The work limit served to prevent the descendant walking algorithm from doing too much work by marking the parent transaction as dirty. However to implement ancestor tracking, it's not possible to similarly mark those descendant transactions as dirty without having to calculate them to begin with. This commit removes the work limit altogether. With appropriate chain limits (-limitdescendantcount) the concern about doing too much work inside this function should be mitigated. (furszy) ba32375 Rename CTxMemPool::remove -> removeRecursive remove is no longer called non-recursively, so simplify the logic and eliminate an unnecessary parameter (furszy) c30fa16 CTxMemPool::removeForBlock now uses RemoveStaged (furszy) Pull request description: Ending up 2020 with a large PR :). Included a good number of performance and privacy improvements over the mempool and inv processing/sending areas + added mempool cache dump/load. Almost finishing with #1726 work, getting closer to 9725, and getting closer to be able to decouple the message processing thread <-> wallet and the wallet <-> GUI locks dependencies (which will be another long story.. but well, step by step). The final goal is clear, a much faster syncing process using pivx-qt (a good speed up for pivxd as well), smoother visual navigation when big wallets are syncing, less thread synchronization issues, among all of the improvements that will be coming with the backports adaptations. Adapted the following PRs to our sources: bitcoin#7062 —> only eb30666. bitcoin#7174 —> complete. bitcoin#7562 —> only c5d746a. bitcoin#7594 —> complete. bitcoin#7840 —> complete. bitcoin#7997 —> complete. bitcoin#8080 —> complete bitcoin#8126 —> except e9b4780 (we don't have the mapRelay) and c2a4724 (we don't have the relay expiration vector). bitcoin#8448 —> complete bitcoin#8515 —> complete bitcoin#9408 —> complete bitcoin#9966 —> complete bitcoin#10330 —> complete ACKs for top commit: random-zebra: ACK 9b9c616 Fuzzbawls: ACK 9b9c616 Tree-SHA512: 186bd09bbb19b55ec0d46dc27291663a0df2d60d8238c661a8c9b8cbf3677b6f8a92fa56bd7346a3cb5293712eeccc5d6542ee3c441d35a4f61e7d12e2ce489a
Fixes #8433 and builds upon #8392.
This adds a file
mempool.dat
to the data directory, which is created every 10 minutes, and at shutdown. At startup, it is loaded after loading/reindexing/activation of blocks (in the background).It only grabs a mempool lock while copying and sorting mempool shared pointers (similar to responding to a
mempool
BIP35 message), which takes 50-100ms here for 1 GB mempool. Loading from disk seems to take up to dozens of seconds but happens in the background.