-
Notifications
You must be signed in to change notification settings - Fork 37.7k
wallet: improve IBD sync time by skipping block scanning prior birth time #27469
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
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
concept ACK, seems like a great idea. |
src/interfaces/chain.h
Outdated
@@ -83,6 +83,7 @@ struct BlockInfo { | |||
const uint256& hash; | |||
const uint256* prev_hash = nullptr; | |||
int height = -1; | |||
int64_t time = 0; |
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.
Any reason to use int64_t
, when the block time is denoted in a type-safe NodeSeconds
?
Edit: I guess all you need to do is switch from ...::GetBlockTime()
to ...::Time()
?
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.
Mainly to be consistent with the chain interface, wallet and spkm sources. Timestamps are represented as int64_t
there. E.g. the FoundBlock
class, findFirstBlockWithTimeAndHeight
method, the CWallet::m_best_block_time
member, first key time, descriptor creation time etc.
I think that is clear that block times are always in seconds, so the use of an arithmetic type shouldn't be much of a worry but we could switch all of them to NodeSeconds
too (probably in another PR that does it all at once?).
e07dd5f test: fix bumpfee 'spend_one_input' occasional failure (furszy) Pull request description: CI test failure, in master: https://cirrus-ci.com/task/5975232842825728. In #27469 https://cirrus-ci.com/task/6452468402356224 Most of the subtests in `wallet_bumpfee.py` expect to find spendable UTXOs of 0.001 btc in the rbf wallet. They use the `spend_one_input()` method which fails if none of them exist. The sporadic failure comes from the recently added `test_feerate_checks_replaced_outputs` subtest that can spend all them. Leaving the next subtests with no 0.001 UTXOs to spend. To solve it, this PR moves the recently added case into a "context independent subtests" section. Which is placed at the end to not affect other cases. ACKs for top commit: achow101: ACK e07dd5f pablomartin4btc: ACK e07dd5f. Tree-SHA512: c150ed6fcfbb6f1502eaf6370a57aae0da991c0fc48e8bb3d446805f4336abba5d80ff0de26094914da95432dd0255030fe527001af4510dfdcefbc7230f14d6
…ailure e07dd5f test: fix bumpfee 'spend_one_input' occasional failure (furszy) Pull request description: CI test failure, in master: https://cirrus-ci.com/task/5975232842825728. In bitcoin#27469 https://cirrus-ci.com/task/6452468402356224 Most of the subtests in `wallet_bumpfee.py` expect to find spendable UTXOs of 0.001 btc in the rbf wallet. They use the `spend_one_input()` method which fails if none of them exist. The sporadic failure comes from the recently added `test_feerate_checks_replaced_outputs` subtest that can spend all them. Leaving the next subtests with no 0.001 UTXOs to spend. To solve it, this PR moves the recently added case into a "context independent subtests" section. Which is placed at the end to not affect other cases. ACKs for top commit: achow101: ACK e07dd5f pablomartin4btc: ACK bitcoin@e07dd5f. Tree-SHA512: c150ed6fcfbb6f1502eaf6370a57aae0da991c0fc48e8bb3d446805f4336abba5d80ff0de26094914da95432dd0255030fe527001af4510dfdcefbc7230f14d6
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.
Did some general code review. I see we already have nCreateTime
for descriptors and part of this PR seems to be just bringing that up to the wallet level, so that's not a redundancy.
Also I don't know if this is a problematic edge case or it could just be a good way to test but you could create a key and send BTC to it in a block, then a few blocks later import into a new descriptor and rescan. The wallet should miss the first transaction.
4698614
to
9785754
Compare
Thanks for the review pinheadmz.
This PR is not modifying the rescan process. Only IBD. |
9785754
to
a2d3902
Compare
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.
Concept ACK. Light code review, I'd to spend more time with it, which I'll do soon. Good stuff!
3914f4f
to
1a9a349
Compare
7bfe7b4
to
7be71a2
Compare
Updated per feedback, thanks achow. Changes:
|
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.
Approach ACK, this looks good so far but I haven't reviewed the first commit yet.
7be71a2
to
76396ca
Compare
7cf50fb
to
82bb783
Compare
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.
Concept ACK. Haven't reviewed the code.
sanity check: because we already skip old blocks during rescan? |
Yes. Different entry points. #26679 addressed the scanning of the existing chain during load time. |
To review this PR I wrote a simple functional test: pinheadmz@1f0f945 which surprised me by failing. I added logging and comments to the test to share it because I don't entirely understand what's happening but it looks to me like, the wallet generates a test output:
and then in bitcoin |
The issue is on your test setup. The The framework, after creating the default wallet, imports one of the hardcoded private keys (link) used to receive the coinbases coins (link). This means calling the test framework
The simplest solution for the test is to create the wallet by yourself, by calling Thanks for testing :). |
@furszy awwwwwesome thank you for catching that. Ok, passing test is now at pinheadmz@f123870 |
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.
ACK 82bb783
Reviewed code and tested locally, wrote a test. I am running this branch side-by-side with master on a VPS and will report who wins the race in a day or so ;-)
Show Signature
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
ACK 82bb7831fa6052620998c7eef47e48ed594248a8
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEE5hdzzW4BBA4vG9eM5+KYS2KJyToFAmRwxNIACgkQ5+KYS2KJ
yTq5nhAA3dJDzRO4VmDUA8n9YO4RtpcQBHT/t9NOsoyNFszTZOQb47JqCTDSGBeZ
mwgdfTIMWDkIesi5lG81ATdGTvxeJjx/7OjN90x46Lj3bJuyVTJxrnrVtLuv/2tg
G9fnfXO2Ngod/daq9psvNhLfQLhW3CQNtsJ3x4NOJafKLOyxmd+dKxnXzJaKAicp
ZlnIyUtArxLiDFXRmJRpmKAX2TRj49HooiY6gKlyyTtiOitB48AQdsh6hzaQ2O3q
wyYzIwM8jEC3/hIbemPaoLphc6esevgXRCcEo3zv+VvnDdrtNBwXEKFtThkPniEq
5hF2zaVCB6cqlvjcFMnkZOVafxE9GWe7fJR7OPa0W2vS3YaSZD7zdhwTpK2KV0Cj
HG21b2x5VFep6cQDl1Xqlktu21ExAWg2zOwESCnrJ7riRXtb3+Xe/eny90aeYhyX
0+ORbVy8AVyBYC1+nBjqpJA8JAoncm3xgNTpbgvX8XrflSaLcbhod5UAh0R+NE4c
QGvGDa6ITO0+Cu/Yba4TwgOxzBmA/oXSxUecGR5eQi3KuKobVlfdLbKgjt1tfscs
t414zb/cjcgpxVMXrrLZMMttg06I9YvSVUEcPCeU2YgiLgigTqunwsZ7KsOJM5ih
HB4+y7/lIg+7kme6ZheZ221r7nWY6atR5piFe09AqLmKPBEviio=
=VjDW
-----END PGP SIGNATURE-----
pinheadmz's public key is on keybase
re-ACK 82bb783 |
re-ACK 82bb783 |
…scanning prior birth time 82bb783 wallet: skip block scan if block was created before wallet birthday (furszy) a082434 refactor: single method to append new spkm to the wallet (furszy) Pull request description: During initial block download, the node's wallet(s) scans every arriving block looking for data that it owns. This process can be resource-intensive, as it involves sequentially scanning all transactions within each arriving block. To avoid wasting processing power, we can skip blocks that occurred before the wallet's creation time, since these blocks are guaranteed not to contain any relevant wallet data. This has direct implications (an speed improvement) on the underlying blockchain synchronization process as well. The reason is that the validation interface queue is limited to 10 tasks per time. This means that no more than 10 blocks can be waiting for the wallet(s) to be processed while we are synchronizing the chain (activating the best chain to be more precise). Which can be a bottleneck if blocks arrive and are processed faster from the network than what they are processed by the wallet(s). So, by skipping not relevant blocks in the wallet's IBD scanning process, we will also improve the chain synchronization time. ACKs for top commit: ishaanam: re-ACK 82bb783 achow101: re-ACK 82bb783 pinheadmz: ACK 82bb783 Tree-SHA512: 70158c9657f1fcc396badad2c4410b7b7f439466142640b31a9b1a8cea4555e45ea254e48043c9b27f783d5e4d24d91855f0d79d42f0484b8aa83cdbf3d6c50b
Looks like the fuzz test needs an update?
|
Thanks Marco. Fixed in #27786. |
Yes, but the fuzz target is too slow right now, so the fuzz input directory is empty. |
a10f032 fuzz: fix wallet notifications.cpp (furszy) Pull request description: Fixing bitcoin/bitcoin#27469 (comment). As the fuzzing test requires all blocks to be scanned by the wallet (because it is asserting the wallet balance at the end), we need to ensure that no blocks are skipped by the recently added wallet birth time functionality. This just means setting the chain accumulated time to the maximum value, so the wallet birth time is always below it, and the block is always processed by the wallet. ACKs for top commit: MarcoFalke: lgtm ACK a10f032, thanks Tree-SHA512: c9b38c52917cc36674415470752625b8161fc6b878b0b87d6926b462ba9666be3c225d396604c7e944a4c268fc35fc624807777aa0ed94bddbe18d8f8436de3c
a10f032 fuzz: fix wallet notifications.cpp (furszy) Pull request description: Fixing bitcoin#27469 (comment). As the fuzzing test requires all blocks to be scanned by the wallet (because it is asserting the wallet balance at the end), we need to ensure that no blocks are skipped by the recently added wallet birth time functionality. This just means setting the chain accumulated time to the maximum value, so the wallet birth time is always below it, and the block is always processed by the wallet. ACKs for top commit: MarcoFalke: lgtm ACK a10f032, thanks Tree-SHA512: c9b38c52917cc36674415470752625b8161fc6b878b0b87d6926b462ba9666be3c225d396604c7e944a4c268fc35fc624807777aa0ed94bddbe18d8f8436de3c
…gging 8a553c9 wallet: Add TxStateString function for debugging and logging (Ryan Ofsky) Pull request description: I found this useful while debugging silent conflict between #10102 and #27469 recently ACKs for top commit: ishaanam: utACK 8a553c9 achow101: ACK 8a553c9 furszy: Code ACK 8a553c9 Tree-SHA512: 87965c66bcb59a21e7639878bb567e583a0e624735721ff7ad1104eed6bb9fba60607d0e3de7be3304232b3a55f48bab7039ea9c26b0e81963e59f9acd94f666
… and logging 8a553c9 wallet: Add TxStateString function for debugging and logging (Ryan Ofsky) Pull request description: I found this useful while debugging silent conflict between bitcoin#10102 and bitcoin#27469 recently ACKs for top commit: ishaanam: utACK 8a553c9 achow101: ACK 8a553c9 furszy: Code ACK 8a553c9 Tree-SHA512: 87965c66bcb59a21e7639878bb567e583a0e624735721ff7ad1104eed6bb9fba60607d0e3de7be3304232b3a55f48bab7039ea9c26b0e81963e59f9acd94f666
During initial block download, the node's wallet(s) scans every arriving block looking for data that it owns.
This process can be resource-intensive, as it involves sequentially scanning all transactions within each
arriving block.
To avoid wasting processing power, we can skip blocks that occurred before the wallet's creation time,
since these blocks are guaranteed not to contain any relevant wallet data.
This has direct implications (an speed improvement) on the underlying blockchain synchronization process
as well. The reason is that the validation interface queue is limited to 10 tasks per time. This means that no
more than 10 blocks can be waiting for the wallet(s) to be processed while we are synchronizing the chain
(activating the best chain to be more precise).
Which can be a bottleneck if blocks arrive and are processed faster from the network than what they are
processed by the wallet(s).
So, by skipping not relevant blocks in the wallet's IBD scanning process, we will also improve the chain
synchronization time.