Skip to content

go/oasis-node/cmd/storage: Add create and import checkpoint cmd#6454

Open
martintomazic wants to merge 3 commits intomasterfrom
martin/feature/create-checkpoint-cmd
Open

go/oasis-node/cmd/storage: Add create and import checkpoint cmd#6454
martintomazic wants to merge 3 commits intomasterfrom
martin/feature/create-checkpoint-cmd

Conversation

@martintomazic
Copy link
Contributor

@martintomazic martintomazic commented Feb 7, 2026

Closes #6423

  • Write our own version of BootstrapState
    • The node creating checkpoint can dump untrusted metadata, that will be used for initializing cometbft stores after importing the checkpoint.
    • We could also make it trustless, if we want to get rid of the snapshots entirely and only store checkpoints + storage diffs and blocks. :)
  • Fix TODOs depending on the review feedback.

@martintomazic martintomazic force-pushed the martin/feature/storage-inspect-cmd branch from ea89ecc to c5e2f2a Compare February 9, 2026 10:33
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from 9761a3c to 0bba8dd Compare February 9, 2026 23:08
@martintomazic martintomazic force-pushed the martin/feature/storage-inspect-cmd branch 2 times, most recently from fe09fe6 to f833d73 Compare February 10, 2026 00:00
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from 0bba8dd to 41b49b4 Compare February 10, 2026 00:05
@martintomazic martintomazic force-pushed the martin/feature/storage-inspect-cmd branch from f833d73 to b47eb6c Compare February 10, 2026 14:35
Base automatically changed from martin/feature/storage-inspect-cmd to master February 10, 2026 21:53
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from 41b49b4 to b31dfff Compare February 11, 2026 09:00
@netlify
Copy link

netlify bot commented Feb 11, 2026

Deploy Preview for oasisprotocol-oasis-core canceled.

Name Link
🔨 Latest commit f082fcd
🔍 Latest deploy log https://app.netlify.com/projects/oasisprotocol-oasis-core/deploys/69a95948f21a130008af6a91

@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from b31dfff to 744884b Compare February 11, 2026 09:04
@martintomazic
Copy link
Contributor Author

Works! :)

The only thing that is impractical is finding corresponding runtime rounds to given consensus height and the fact that bootstrap "eats" one height as described.

Finally, one should be very careful with creation/import height/rounds so that you have all relevant light history for the runtime checkpoints you are importing.

@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch 3 times, most recently from ef92148 to a41d394 Compare February 11, 2026 14:12
Comment on lines +112 to +114
if height != 0 { // TODO handle zero value vs not set correctly.
if err := createConsensusCp(); err != nil {
return fmt.Errorf("failed to create consensus checkpoint (height: %d): %w", height, err)
Copy link
Contributor Author

@martintomazic martintomazic Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use default undefined round (aka max uint64), alternative is cmd.Flags().Changed("height").

Update: Alternative is explicit --consensus flag or possible consensus/runtime sub-commands. No height/round could also mean latest height. -all flag with --height would be also interesting if it would find corresponding runtime rounds for the given height.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently things are not fine, as you can do consensus and runtime checkpoints at the same time. Furthermore, this might be confusing for users, e.g.., do they need to set height, round, both?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I left it intentional for now. I can easily allow only one at the time. The question is would using sub-commands make things even clearer? Also any preference for what should omitting height/round do?

Observe also that if you want to be able to create checkpoints for multiple heights/versions (same NodeDB) the import command also grows in complexity.

Finally, one should be very careful for which height to specific runtime round combinations you are creating as you can easily get left missing missing runtime light blocks, and therefore stuck runtime state restore.

We could also make import command use consensus/runtime/height/round and import the actual directories created one by one to make it symmetric to create.

Any pref?

@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from a41d394 to 206c70e Compare February 11, 2026 14:25
@martintomazic
Copy link
Contributor Author

martintomazic commented Feb 11, 2026

Creating checkpoints from the penultimate snapshot, is dominated by the Sapphire checkpoint creation.

With 6 chunker threads current projection is 5-7 hours (will update). Import is a matter of minutes.

@martintomazic martintomazic marked this pull request as ready for review February 11, 2026 14:33
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch 3 times, most recently from 817bc76 to 2be35e9 Compare February 22, 2026 22:38
@martintomazic
Copy link
Contributor Author

martintomazic commented Feb 22, 2026

Added unit and e2e tests, fixed empty state corner case and improved code quality.

Two minor things left to discuss:

@codecov
Copy link

codecov bot commented Feb 22, 2026

Codecov Report

❌ Patch coverage is 59.29204% with 138 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.56%. Comparing base (c9a4b8e) to head (06b5cc4).

Files with missing lines Patch % Lines
go/oasis-node/cmd/storage/checkpoint.go 58.43% 73 Missing and 65 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6454      +/-   ##
==========================================
- Coverage   64.73%   64.56%   -0.18%     
==========================================
  Files         699      700       +1     
  Lines       68246    68581     +335     
==========================================
+ Hits        44179    44279     +100     
- Misses      19060    19183     +123     
- Partials     5007     5119     +112     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Collaborator

@peternose peternose left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I import a consensus checkpoint, I get few lines of the following error. Afterwards, blocks execute normally.

{"caller":"grpc.go:194","err":"failed to get consensus status: failed to fetch current block: cometbft: block query failed: height 28800866 must be less than or equal to the current blockchain height 0","level":"error","method":"/oasis-core.NodeController/GetStatus","module":"grpc/internal","msg":"request failed","req_seq":15,"ts":"2026-02-24T13:00:28.934344662Z"}

return cmd
}

func createCheckpoints(ctx context.Context, ndb api.NodeDB, ns common.Namespace, version uint64, outputDir string) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe creating a struct checkpointer would be better, as you could create multiple checkpoints with the same struct, e.g.

cp.Create(ctx, 1, "/checkpoints/1")
cp.Create(ctx, 2, "/checkpoints/2")
...

or even without outputDir if accepted in the constructor. The new struct might also be easier to test and could be decoupled from the commands.

Copy link
Contributor Author

@martintomazic martintomazic Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update:

The new struct might also be easier to test and could be decoupled from the commands.

newCheckpointer + cp.create (proposed) = createCheckpoints (current) so this is only a matter of style.

As usual I prefer an explicit function over abstractions until multiple methods share same parameter set.


The question is do we want to allow multiple checkpoint heights/rounds for the same NodeDB.

If you want to make this generic helper I think this would fit inside checkpoint package.
See ( #6467):

// Consider using functional optional arguments to shorten args list.
CreateCheckpoint(ctx context.Context, ndb db.NodeDB, store Store, root node.Root, chunkSize uint64, chunkerThreads uint16) (*Metadata, error)

// Maybe add CreateAllCheckpoints as well and avoid passing root there.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is a matter of style by the quality/complexity of the code. And more parameters you have, the harder is to follow. And as suggested, compare code if you need to create multiple checkpoints for different versions with a function or with a method call.

Comment on lines +112 to +114
if height != 0 { // TODO handle zero value vs not set correctly.
if err := createConsensusCp(); err != nil {
return fmt.Errorf("failed to create consensus checkpoint (height: %d): %w", height, err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently things are not fine, as you can do consensus and runtime checkpoints at the same time. Furthermore, this might be confusing for users, e.g.., do they need to set height, round, both?

@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from 2be35e9 to 06b5cc4 Compare February 24, 2026 15:32
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch 5 times, most recently from e9c6485 to 9633a30 Compare March 4, 2026 22:47
@martintomazic
Copy link
Contributor Author

When I import a consensus checkpoint, I get few lines of the following error. Afterwards, blocks execute normally.

Nice catch. Yes this is also how CometBFT checkpoint import works, but found a fixup regardless :).

The more annoying thing that I find is that you technically cannot import a checkpoint for the latest height, so probably adding extra validation + documenting this in the command would be beneficial, instead of unexpected error.

@martintomazic
Copy link
Contributor Author

Ready for a second review.

As you spotted I am "abusing" checkpoint.FileStore abstraction (#6467) bound to one concrete NodeDB, that should be able to create and import checkpoints for different versions.

However, this command is technically not create/import checkpoint but rather create/import state/snapshot. Indeed 99% is creating and importing checkpoints and using checkpoint.FileStore for encoding the snapshot structure. Nevertheless, CometBFT bootstrap metadata has nothing to do with the checkpoints alone.

For this reason I have created my helpers (stateless), so that they can also be easily refactored, possibly moved to checkpoint package one day. Until this command is the only client I am not sure it makes sense. Improving checkpoint package abstractions probably does. :)

Let's align on the user facing API and sanity checking the inputs:

  1. go/oasis-node/cmd/storage: Add create and import checkpoint cmd #6454 (comment)
    • The simpler the better given we will the only user of this command:
  2. Should we find a better name for this command given that is not just creating/importing checkpoints? Not sure.

@martintomazic martintomazic requested a review from peternose March 4, 2026 23:20
@peternose
Copy link
Collaborator

Ready for a second review.

Will have a look. Merge after we release 26.0.

The test should be ideally hardened by also making sure the
target node also syncs up to the tip of the runtime chain
and not just consensus.

Furthermore, given that e2e tests are expensive and meant to
test complex scenarios, my suggestions would be to also run
prune, compact, and inspect command on the source node prior
to creating a checkpoint. This way we would "smoke test"
remaining storage commands, and the scenario could be called
storaged_cmds instead.
@martintomazic martintomazic force-pushed the martin/feature/create-checkpoint-cmd branch from 9633a30 to f082fcd Compare March 5, 2026 10:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

go/oasis-node: Enable snapshot creation with exact start version

2 participants