Skip to content

Conversation

@Cordtus
Copy link
Contributor

@Cordtus Cordtus commented Dec 5, 2025

Description

Closes: #15463

Add EarliestVersion() to the CommitMultiStore interface to enable querying the earliest available state height.
This addresses the longstanding TODO in the Status gRPC endpoint that was returning 0 for EarliestStoreHeight.

Problem

Indexers and tooling need to know which heights a pruned node can serve queries for. Currently:

  • earliest_block_height in CometBFT's STATUS RPC returns the earliest block, not the earliest state
  • The EarliestStoreHeight field in cosmos.base.node.v1beta1.Status was hardcoded to 0

Solution

  • Add EarliestVersion() int64 to the CommitMultiStore interface (not MultiStore, since CacheMultiStore lacks root DB access)
  • Implement persistent tracking in rootmulti.Store:
  • Stores earliest version at s/earliest key
  • Defaults to 1 for unpruned chains
  • Updates after successful pruning in PruneStores()
  • Pass CommitMultiStore to the node gRPC service to populate EarliestStoreHeight

Changes

File Change
store/types/store.go Add EarliestVersion() to `
client/grpc/node/service.go Accept CommitMultiStore, use EarliestVersion() in Status response
store/rootmulti/store.go Implement EarliestVersion(), GetEarliestVersion(), flushEarliestVersion(), update PruneStores()
store/rootmulti/store_test.go Add 3 unit tests
runtime/app.go Pass CommitMultiStore to service registration
simapp/app.go Pass CommitMultiStore to service registration

Testing

  • TestEarliestVersion - basic functionality, default value
  • TestEarliestVersionWithPruning - tracks updates after pruning
  • TestEarliestVersionPersistence - persists across restarts
  • System test: TestNodeStatus - gRPC endpoint returns valid heights

API Changes

Breaking change for any code implementing CommitMultiStore — must now implement EarliestVersion() int64.
No impact on MultiStore or CacheMultiStore implementations.

@fmorency
Copy link
Contributor

fmorency commented Dec 5, 2025

Would love to get this backported to 0.50.x. It would enable fixing manifest-network/yaci#28

@aljo242
Copy link
Contributor

aljo242 commented Dec 8, 2025

This seems like a nice feature but will need more extensive testing such as using systemtest if we are going to include

@Cordtus Cordtus force-pushed the fix/earliest-store-height-upstream branch from e7384c5 to eaa696a Compare December 10, 2025 20:22
@Cordtus
Copy link
Contributor Author

Cordtus commented Dec 10, 2025

Added systemtest for the node.Status gRPC endpoint:

  • Basic test confirms valid heights are returned
  • Pruning test configures aggressive state pruning and confirms earliest_store_height increases afterward

Also updated the service to use CommitMultiStore directly since query context provides a CacheMultiStore which doesn't support version queries.

Run locally:

make build && cp build/simd tests/systemtests/binaries/
cd tests/systemtests && go test -tags system_test -v -run TestNodeStatus

@Cordtus Cordtus changed the title feat(store): implement EarliestVersion for MultiStore fix(grpc): return actual earliest_store_height in node.Status endpoint Dec 10, 2025
@fmorency
Copy link
Contributor

@aljo242 is there anything blocking this PR?

@Cordtus
Copy link
Contributor Author

Cordtus commented Jan 7, 2026

Bump. Would like to be sure there is nothing else needed from my end here.

@Cordtus
Copy link
Contributor Author

Cordtus commented Jan 11, 2026

@aljo242 is there anything I can do to help this one along?

@Cordtus Cordtus force-pushed the fix/earliest-store-height-upstream branch from 995a18e to 1172c68 Compare January 22, 2026 06:00
@aljo242 aljo242 requested a review from technicallyty January 23, 2026 17:56
@aljo242
Copy link
Contributor

aljo242 commented Jan 23, 2026

@technicallyty to review this

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 72.22222% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.70%. Comparing base (0deda3b) to head (3a3c034).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
client/grpc/node/service.go 44.44% 5 Missing ⚠️
store/rootmulti/store.go 80.76% 5 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #25647      +/-   ##
==========================================
+ Coverage   68.23%   70.70%   +2.46%     
==========================================
  Files         894      895       +1     
  Lines       58150    58217      +67     
==========================================
+ Hits        39680    41161    +1481     
+ Misses      18470    17056    -1414     
Files with missing lines Coverage Δ
runtime/app.go 65.34% <100.00%> (ø)
store/types/store.go 75.00% <ø> (+45.00%) ⬆️
client/grpc/node/service.go 62.96% <44.44%> (-1.04%) ⬇️
store/rootmulti/store.go 82.93% <80.76%> (+34.17%) ⬆️

... and 33 files with indirect coverage changes

Impacted file tree graph

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

@technicallyty
Copy link
Contributor

This seems like a nice feature but will need more extensive testing such as using systemtest if we are going to include

i'm fine with merging this with systemtests, but i would like to use systemtest more sparingly in the future. systest runs a local 4 node network, which is not necessary for queries like this. an e2e integration test is more than enough for these types of PRs

Comment on lines -56 to -59
// TODO: Get earliest version from store.
//
// Ref: ...
// EarliestStoreHeight: sdkCtx.MultiStore(),
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason why we can't use the sdkCtx.MultiStore() to achieve this functionality?

Copy link
Contributor Author

@Cordtus Cordtus Jan 24, 2026

Choose a reason for hiding this comment

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

Not that I know -- I can change it if that seems like a better way to go.

Edit: we would have to add a ctx.EarliestHeight() to it first, which is more consistent but I guess more code as well. Which do you think is the better path?

Copy link
Contributor

Choose a reason for hiding this comment

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

can you explain why it would have to be a method on ctx?

Copy link
Contributor Author

@Cordtus Cordtus Jan 26, 2026

Choose a reason for hiding this comment

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

It doesn't — my bad. I moved EarliestVersion() from MultiStore to CommitMultiStore instead.

The query context's MultiStore() is an in-memory CacheMultiStore — created in CreateQueryContext via CacheMultiStoreWithVersion(height) with no reference to the root DB or its metadata.

Placing it on CommitMultiStore means CacheMultiStore doesn't need to implement it at all and avoids a stub that just panics (like LatestVersion() currently does on CacheMultiStore, which is the bad example I was following originally). This way the query/service receives CommitMultiStore at registration.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok so if we go that route, we could just get EarliestHeight from ctx and then we don't have to pass around the cms? i'd prefer that

@Cordtus Cordtus force-pushed the fix/earliest-store-height-upstream branch 3 times, most recently from 4f40612 to 5c4a042 Compare January 26, 2026 22:25
Add EarliestVersion() to the CommitMultiStore interface to enable
querying the earliest available state height. Placed on CommitMultiStore
rather than MultiStore since it requires root DB access that
CacheMultiStore does not have.

- Implement in rootmulti.Store with persistent DB storage
- Track earliest version after pruning in PruneStores
- Add unit tests for EarliestVersion functionality

Ref: cosmos#15463
Pass CommitMultiStore to the node query service to populate
EarliestStoreHeight in the Status response.
@Cordtus
Copy link
Contributor Author

Cordtus commented Jan 26, 2026

I edited the original description and cleaned it up a bit. This makes more sense for sure. Sorry for the mess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make query to find what states a given node exposes

4 participants