wallet: Only fail rescan when blocks have actually been pruned#15870
wallet: Only fail rescan when blocks have actually been pruned#15870maflcko merged 3 commits intobitcoin:masterfrom
Conversation
fa00f6e to
fa12b93
Compare
|
Concept ACK. There is an argument against doing things like this: that it's better to fail deterministically rather than fail randomly at some point in the future and have created incorrect expectations of functionality. But setting prune to some large "future" amount is a perfectly reasonable configuration. And this doesn't cause it to fail randomly, but rather work until it doesn't. So I don't believe the general argument against this sort of thing offsets the benefit. |
|
This seems to affect importaddress, importpubkey, importprivkey, and importwallet but not importmulti. I wonder how the new behavior compares to importmulti behavior, and if there's a difference, whether that's justified. |
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsNo conflicts as of last run. |
|
@ryanofsky The only difference between importmulti and the other calls is that in importmulti you can "opt-out" of scanning early blocks by setting a later timestamp. Otherwise, my change makes all calls behave in the same way. Edit: I believe the only difference is that importmulti will import the keys and then fail the rescan, whereas the other calls will exit early and not attempt to import anything. |
1ceacd8 to
fad8451
Compare
Why a different behavior? It's already possible to call |
I don't know. I didn't write the importmulti RPC and I don't plan to change it in this pull request. |
promag
left a comment
There was a problem hiding this comment.
@MarcoFalke I wasn't suggesting changing that behavior.
Concept ACK. Correct me if I'm wrong, but it doesn't have to fail if all required blocks are available right?
src/interfaces/chain.cpp
Outdated
There was a problem hiding this comment.
Sorry for the brief reply, but see here:
The chain lock is deprecated and will be removed in the future.
src/wallet/rpcdump.cpp
Outdated
There was a problem hiding this comment.
A block can be pruned before RescanWallet (L202). What would be the error then?
There was a problem hiding this comment.
It will throw an error "Rescan was unable to fully rescan the blockchain. Some transactions may be missing."
importmulti does not fail the rescan when all blocks after the timestamp are available, but it fails after the import if a block is missing. |
fad8451 to
faa7e29
Compare
faa7e29 to
fa6838e
Compare
|
Let's use prune height instead, so |
|
I am not touching |
|
I mean it would make sense to use a common interface with |
|
Oh, the RPCs I touch are already deprecated in favor of importmulti, so I'd rather not add features to them. |
|
I'm commenting on the src/interfaces changes specifically. |
|
Ah. Yeah, since we don't store the prune height, this would complicate my changes slightly. I think the additional code can be added later (when needed in rescanblockchain). |
|
I'm a little concerned about this change. Anywhere that The four call sites in rpcdump do not hold |
|
@jnewbery The check is only there to provide a nice error message. As you correctly observe it is not needed for correctness. Should I clarify that with a comment? The error message otherwise would be #15870 (comment) |
Yes, that sounds good. Thanks! |
jnewbery
left a comment
There was a problem hiding this comment.
utACK fa9fa5d647092710aa03dadf92433584e9fe26a3
Will happily reACK a squashed branch.
fa9fa5d to
fa9f3cc
Compare
|
utACK fa9f3cc89442e9b332a27b81b04201bb4a0caf28 |
jonatack
left a comment
There was a problem hiding this comment.
A few code comments. More documentation and tests might make this change and the expected behavior before/after clearer, at least to me.
src/wallet/rpcdump.cpp
Outdated
There was a problem hiding this comment.
Does the code doc in 588 correspond correctly with the error message in 589?
There was a problem hiding this comment.
Yes, "importing wallet" means "importing key(s)", I believe.
src/wallet/rpcdump.cpp
Outdated
There was a problem hiding this comment.
Would it be worth extracting this code block repeated in importprivkey, importaddress, importpubkey, and importwallet (the latter with a different error message).
if (fRescan && pwallet->chain().havePruned()) {
// Exit early and print an error.
// If a block is pruned after this check, we will import the key(s),
// but fail the rescan with a generic error.
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
}Edit: I understand it may be a premature or unnecessary optimisation. Just an observation.
There was a problem hiding this comment.
Yeah, could make sense. Will do if I have to touch for other reasons.
There was a problem hiding this comment.
Yeah, in a follow up is fine.
-BEGIN VERIFY SCRIPT- ./contrib/devtools/copyright_header.py update ./src/wallet/ -END VERIFY SCRIPT-
fa9f3cc to
aaaa57c
Compare
|
Concept ACK. My first read of this was that it'd permit rescanning pruned chains, as long as the to-be-rescanned blocks are not pruned, but it seems to just be about whether or not any blocks are actually pruned (independent of the ones to be rescanned), right? |
|
The legacy calls would always rescan the whole chain. As soon as one block is pruned, it fails. |
|
Out of scope for this PR but somewhat related -- would there be any reason to not attempt to fetch the pruned blocks from the P2P network to allow the rescan to happen? |
|
Jup, but that might be something to do only after #15946 |
|
|
||
| def try_rpc(self, func, *args, **kwargs): | ||
| if self.expect_disabled: | ||
| assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs) |
There was a problem hiding this comment.
Now there is no longer any test coverage for the "rescan is disabled" cases, but I'm not sure if there's an easy way to add it back. Maybe a pruneblockchain RPC call could be added.
There was a problem hiding this comment.
If a test was added, it should also (or more importantly) test importmulti, so I am not actually decreasing test coverage here.
There was a problem hiding this comment.
I agree that a test would be nice for that case, but can be done in a follow up pull request.
There was a problem hiding this comment.
it should also (or more importantly) test importmulti
In case it helps, there is currently a unit test for importmulti behavior with pruning:
bitcoin/src/wallet/test/wallet_tests.cpp
Line 158 in 2d16fb7
|
utACK aaaa57c Makes a lot of sense to allow rescanning for as long as we can as @gmaxwell notes above - and indeed it might even be prudent for most users to set a future-proofing prune value that reflects their disk limitations at startup time. Better that your node start pruning vs. run out of disk space and exit. Maybe in the future we could even default to such a thing based on the datadir device if pruning-enabled-but-not-done-yet behavior is equivalent to a non-pruning node. Or introduce an "adaptive" pruning mode, which periodically polls for available disk space and adjusts the prune target accordingly. But of course this is all out of scope for this change. |
|
@jamesob you mean an option to ensure a minimum free space? |
| // Exit early and print an error. | ||
| // If a block is pruned after this check, we will import the key(s), | ||
| // but fail the rescan with a generic error. | ||
| throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned"); |
There was a problem hiding this comment.
This should be in 1s commit.
src/wallet/rpcdump.cpp
Outdated
There was a problem hiding this comment.
Yeah, in a follow up is fine.
| }.ToString()); | ||
|
|
||
| if (pwallet->chain().getPruneMode()) { | ||
| if (pwallet->chain().havePruned()) { |
There was a problem hiding this comment.
The dump file contains timestamps so, correct me if I'm wrong, it could only throw this error if earliest is pruned - the same for importmulti if timestamps are given.
Edit: especially when manual pruning.
There was a problem hiding this comment.
Sounds like a nice follow up pull request
If you mean "prune as little as possible and only until necessitated by lack of space," yes. Some kind of adaptive prune would just be a measure to avoid hitting an out-of-disk error for as long as possible. But this is out of scope in terms of this PR so maybe I'll file an issue later or something. |
| bool getPruneMode() override { return ::fPruneMode; } | ||
| bool havePruned() override | ||
| { | ||
| LOCK(cs_main); |
There was a problem hiding this comment.
I'm not suggesting you change this PR, but for future reference we now have a handy WITH_LOCK macro:
Line 209 in fd61b9f
There was a problem hiding this comment.
I fail to see how this makes the code any easier to read
…ly been pruned fa7e311 [doc] rpcwallet: Only fail rescan when blocks have been pruned (MarcoFalke) aaaa57c scripted-diff: Bump copyright headers in wallet (MarcoFalke) faf3729 wallet: Only fail rescan when blocks have actually been pruned (MarcoFalke) Pull request description: This brings the behaviour of the import* calls closer to importmulti. After this change, the difference between importmulti and the other import* calls is * that in importmulti you can "opt-out" of scanning early blocks by setting a later timestamp. * that in importmulti the wallet will successfully import the data, but fail to rescan. Whereas in the other calls, the wallet will abort before importing the data. ACKs for commit fa7e31: promag: utACK fa7e311. jnewbery: utACK fa7e311 Tree-SHA512: a57d52ffea94b64e0eb9b5d3a7a63031325833908297dd14eb0c5251ffea3b2113b131003f1db4e9599e014369165a57f107a7150bb65e4c791e5fe742f33cb8
|
post-merge utACK |
…ly been pruned fa7e311 [doc] rpcwallet: Only fail rescan when blocks have been pruned (MarcoFalke) aaaa57c scripted-diff: Bump copyright headers in wallet (MarcoFalke) faf3729 wallet: Only fail rescan when blocks have actually been pruned (MarcoFalke) Pull request description: This brings the behaviour of the import* calls closer to importmulti. After this change, the difference between importmulti and the other import* calls is * that in importmulti you can "opt-out" of scanning early blocks by setting a later timestamp. * that in importmulti the wallet will successfully import the data, but fail to rescan. Whereas in the other calls, the wallet will abort before importing the data. ACKs for commit fa7e31: promag: utACK fa7e311. jnewbery: utACK fa7e311 Tree-SHA512: a57d52ffea94b64e0eb9b5d3a7a63031325833908297dd14eb0c5251ffea3b2113b131003f1db4e9599e014369165a57f107a7150bb65e4c791e5fe742f33cb8
This brings the behaviour of the import* calls closer to importmulti. After this change, the difference between importmulti and the other import* calls is