Skip to content

fix(store)!: charge gaskv iterator elements exactly once - #26739

Open
SnowingFox wants to merge 2 commits into
cosmos:mainfrom
SnowingFox:fix/15854-gaskv-iterator-gas
Open

fix(store)!: charge gaskv iterator elements exactly once#26739
SnowingFox wants to merge 2 commits into
cosmos:mainfrom
SnowingFox:fix/15854-gaskv-iterator-gas

Conversation

@SnowingFox

Copy link
Copy Markdown

Summary

Fixes the gaskv iterator gas-accounting inaccuracy from #15854.

On current main, GStore.iterator meters the first key/value pair when the iterator is created (seek to first), and gasIterator.Next meters the current pair again before advancing:

func (gi *gasIterator[V]) Next() {
	gi.consumeSeekGas() // meters the pair the caller has already read
	gi.parent.Next()
}

Iterating over N elements therefore consumes (N+1) per-byte charges: the first element is charged twice and the accounting for the last element is shifted by one Next() step.

Fix

Advance the underlying iterator before metering, so consumeSeekGas meters the pair the iterator has just moved to, and meters nothing per-byte when it advances past the last element:

func (gi *gasIterator[V]) Next() {
	gi.parent.Next()
	gi.consumeSeekGas()
}

Each key/value pair is now charged exactly once: the first when the iterator is created, and every subsequent pair by the Next() call that lands on it.

Testing

  • Added TestGasKVStoreIteratorChargesEachElementOnce, which iterates N keys and asserts the total gas equals N * ReadCostPerByte * len(key+value) + (N+1) * IterNextCostFlat. It fails on main (off by one per-byte charge) and passes with this change.
  • Updated the hard-coded gas expectations in TestGasKVStoreIterator for the corrected accounting.

Closes #15854

@swift1337

Copy link
Copy Markdown
Member

@greptile review

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The pull request corrects gaskv iterator accounting by advancing before metering, so each visited key/value pair is charged once.

  • Moves per-byte charging to the element reached by Next().
  • Adds regression coverage for complete forward iteration and updates existing gas expectations.
  • Documents the correction in the store changelog.

Confidence Score: 4/5

The implementation appears safe to merge after the non-blocking changelog attribution is brought into the repository's required format.

The iterator change and regression test consistently implement one per-byte charge per visited element; the only accepted concern is the changelog entry's missing component tag and incorrect link target.

Files Needing Attention: store/CHANGELOG.md

Important Files Changed

Filename Overview
store/gaskv/store.go Reorders iterator advancement and gas consumption to charge each valid destination element exactly once.
store/gaskv/store_test.go Updates expected gas totals and adds focused regression coverage for per-element and flat iteration costs.
store/CHANGELOG.md Adds an Unreleased bug-fix entry, but its attribution does not follow the required component-tag and pull-request-link format.

Reviews (1): Last reviewed commit: "fix(store): charge gaskv iterator elemen..." | Re-trigger Greptile

Comment thread store/CHANGELOG.md

### Bug Fixes

* [#15854](https://github.com/cosmos/cosmos-sdk/issues/15854) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Use the required changelog attribution

This entry omits the required (store) tag and links issue #15854 instead of this pull request, making its attribution inconsistent with the repository's changelog format.

Suggested change
* [#15854](https://github.com/cosmos/cosmos-sdk/issues/15854) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.
* (store) [#26739](https://github.com/cosmos/cosmos-sdk/pull/26739) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@swift1337 swift1337 Sep 4, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should be * [#26739](https://github.com/cosmos/cosmos-sdk/pull/26739) Fix... under state-breaking section

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're right. This changes externally observable gas consumption, so it belongs under API Breaking, and the entry should reference this PR rather than the issue. My previous (store)-tag requirement was incorrect for this changelog.

Suggested change
* [#15854](https://github.com/cosmos/cosmos-sdk/issues/15854) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.
* [#26739](https://github.com/cosmos/cosmos-sdk/pull/26739) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're right that this should reference PR #26739 rather than issue #15854, and the gas-accounting change belongs in the state-breaking/API-breaking category. store/CHANGELOG.md currently names that stanza API Breaking and does not have a separate State Breaking section, so the corrected entry there is:

* [#26739](https://github.com/cosmos/cosmos-sdk/pull/26739) Fix `gaskv` iterator metering the first iterated element's gas twice, so each key/value pair is charged exactly once.

I’ll withdraw the (store)-tag requirement from my earlier comment.

@swift1337 swift1337 changed the title fix(store): charge gaskv iterator elements exactly once fix(store)!: charge gaskv iterator elements exactly once Sep 4, 2026
@codecov

codecov Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.26%. Comparing base (a9f2a4e) to head (2118e0f).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main   #26739      +/-   ##
==========================================
+ Coverage   64.99%   65.26%   +0.27%     
==========================================
  Files         785      830      +45     
  Lines       55399    58580    +3181     
==========================================
+ Hits        36006    38235    +2229     
- Misses      19393    20345     +952     
Files with missing lines Coverage Δ
store/gaskv/store.go 93.97% <100.00%> (ø)

... and 55 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.

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.

[Bug]: gas consumption inaccuracy of gaskv's iterator

2 participants