-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
feat: Retroactive prune very old blocks from store #11064
Conversation
is this still WIP? If it is, please turn this into a draft PR, thanks. |
@chillyvee could we first open against master then can back port it here |
Yes, exactly. You'll find them all throughout the SDK. |
Let me try and if I get stuck, I'll let you know. Might have time next week. Thanks! |
…e heights from pruneHist
Okay some progress, and an opportunity for feedback: Added a few tests (They pass) Didn't do it table driven since it's really hard to understand in a table format. But Increase and Decrease as a hard test case is more obvious. Adjusted TestMultiStore_PruningRestart - historical prune can duplicate heights to prune that are normally added to pruneHeights. If deleting a height twice is a really bad performance hit on the db layer, we can check for duplicates ahead of time before adding heights to the pruneHeights array. There is a local function variable "debuginfo" that you can set to true to print debug to understand what is going on (kind of). I noticed there is no logging infra and wasn't sure if that was intentional. In any case, happy to remove all prints in the final commit after we agree function is okay. Not sure if the variable Store.histPruneAmount needs to be configurable. It defines the number of historical heights to "additionally prune" in the backwards direction each "Interval". |
Checking in to see if there's any additional feedback to make this PR even better :) |
@p0mvn did some excellent work in refactoring the abstractions of pruning and state sync recently. I would love his input here too with what you're trying to do. Are you looking for feedback on the PR as it is right now? |
Yes @alexanderbez would be great to get feedback as PR stands now. If @p0mvn has more suggestions based on his work I’m open to it. |
Hi everyone, @alexanderbez, thank you, hope I can help @chillyvee, nice to e-meet you First of all, I can see that a lot of thought has been put into this, great work! I looked at the implementation and skimmed the discussion. I have the following question about the current design:
Also, I would like to note that the abstractions have changed in #11496. Now, there is a Although you've put some excellent work into this PR, I'm concerned about doing the additional historical pruning on top of the regular one. As I mentioned above, the pruning state seems to be undefined if a node crashes with a historical state in progress. Also, I think it introduces a level of complexity that makes it more brittle and difficult to maintain. I see the following suggestion above by Marko :
What do you think about this approach? I feel like this could be a safer way without the weirdness after a node crash and extra complexity to maintain. I understand that this approach is required to be done during start-up, and I think that's where it should be done. Implementing the retroactive pruning during |
@p0mvn nice to meet you and thank you for the comments. Adopting the prune manager should be fine. Regarding a crash during prune - doesn’t seem like a new problem since a daemon could crash during prune “right now” in the current branch and just leave garbage behind anyways. A crash pruning now-100 vs pruning (now-100 and now-10000) does not seem any different in risk. Also we are pruning heights that we would pruned anyway with another config, so it doesn’t seem like a radical thing to do. Is it more risky to prune height 12345 tomorrow than today? Feel free to tell me why I am wrong since I absolutely have no idea about what kind of risks old block pruning has :) I figure if a block is safe to prune now, it's safe to prune tomorrow as well. We could keep a key/value bookmark, but again my intent is not to be fast, but rather be done “some day”. So restarting at the new height and working backwards is acceptable in this “eventual” approach. Pruning heights that don’t exist more than once is merely inefficient as far as I can tell. I could make the prune more aggressive and time based (as much as possible in 500ms) but that makes it even harder to test. Would be better to know when the process is least busy, but again finishing the complete prune quickly is not a goal. If you like this idea, can you give feedback on what triggers should cause a stop of additional prune heights such as a prevote starting or a certain amount of gas used by cosmwasm? Might need to hook in other modules, and maybe it’s better to leave for a future revision. To discuss the snapshot and restart approach 1) the reason for this approach is to avoid downtime 2) seeing that Juno takes about 40 minutes to start from genesis skipping invariant checks or 6-10 hours with invariant checks, I hesitate against an approach requiring a rebuild. Is a snapshot and db swap much faster than I fear? Let me know what you think. |
@chillyvee I just wanna cheer you on re: this PR! I think it will be tremendously useful for:
thank you! |
Thanks @faddat ! We really hope this will be a help to everyone on the validator / relayer / rpc infrastructure level. It's not a breakthrough thing, but it's an incremental "quality of life" improvement we think everyone will benefit from. @p0mvn - When you have a chance, would love to know what you think :) |
Checking in to see if @p0mvn or @alexanderbez has any comment |
Hello! Checking in again for comment :) |
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.
Hi @chillyvee Thanks for your patience and sorry for the delay. You've done an incredible job, and I think that retroactive pruning is a useful feature. However, I still have some thoughts in favor of doing it during start-up / not during runtime. I'll try to address this and our previous discussions. Please let me know what you think.
Currently, there is a flush and restore mechanism that prevents the heights from being lost even on a crash: Lines 130 to 131 in f470d40
With the proposed design, if there is a crash, how is the following information restored? cosmos-sdk/store/rootmulti/store.go Lines 57 to 59 in b54cfde
Additionally, what if you are on a pruning configuration A, you switch to a configuration B and start retroactively pruning the changes during runtime. Then, in the process of doing that, you restart the node and decide to switch from configuration B to C while the system is still reconciling the changes between A and B. How is it going to work next? Is the "in-process" retroactive pruning just lost? This is another concern. If you rebase / merge main into this branch, you will see that the codebase looks very different. There are also several goroutines involved now that manage the pruning logic. That's another reason why I think that adding the retroactive pruning during runtime would make it hard to test thoroughly. Additionally, if a bug occurs, I don't know how one would go about debugging.
We also want to make sure that we are designing for soundness, readability, and ease of debugging. I don't know how we would achieve all these when doing retroactive pruning during runtime. Additionally, it is important to think about the cases such as swapping out configurations during retroactive pruning. If any edge case in terms of usage is possible, it will most certainly happen. Users are unpredictable.
Between less downtime and more safety, I would prefer safety. Especially, in an environment where multiple chains will use this codebase and developers might not have the best knowledge about how to debug this logic. That's why I'm advocating for doing the retroactive pruning during start-up. If you prefer to go with the current approach, I would like to ask you to rebase/merge the main into this branch and we can go from there. However, I'm concerned about whether it is possible to get this change in an acceptable state due to the reasons outlined above. |
That's fantastic feedback. Let me check if there are any points that can have a new strategy to address. Otherwise, I'll target pruning on startup. |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
@chillyvee sorry for not coming back to this pr sooner. Do you still have interest in completing it? |
Hi @marbar3778 hope you're doing well. I would like to continue working on this, but it won't be for another month or so. We can leave it open, or if it helps we can close it and reopen later. Appreciate you checking in! :) |
gonna close this but keep the branch around |
Attempting to take the snapshot approach. Was able to make some small changes to cosmos-sdk and tendermint to enable local snapshot restores for Juno's uni tesnet. Would you folks give me some comments/guidance on the code? :) |
Description
Validators using the default pruning config may end up with many old blocks due to pruning-keep-every = "500"
This is a proof of concept showing how a gradual pruning of much older state can be removed without needing to unsafe-reset-all
Questions
Is there any danger to pruning older blocks that are no longer necessary for a "pure" validator? (no API role)
Is extending PruningOptions to include new options from app.toml desirable?
What is the right way to log from store/rootmulti/store.go?
Are we able to somehow see the [state-sync] snapshot-interval / snapshot-keep-recent variables from store/rootmulti/store.go to avoid removing required blocks?
Is there any extensive testing that is desired when implementing this change? At the core it only adds additional heights to be pruned which is not a very special operation.
Since each chain uses a different cosmos-sdk version, is there a proper release/v0.##.x branch(es) to target first/later?
Author Checklist
I have...
!
to the type prefix if API or client breaking change - N/ACHANGELOG.md
- TODO after branch selectionReviewers Checklist
I have...
!
in the type prefix if API or client breaking change