Skip to content

Conversation

@cloudgray
Copy link
Contributor

Description

Summary

  • Applying the stack-based snapshot mechanism achieves the same effect as a deep copy of the original store.
  • Benchmark results show that the stack-based snapshot mechanism uses about 1.4× more memory than CacheMultiStore, but far less than a deep copy—and the gap grows larger as the load increases.

Stack-based Snapshot Mechanism

  • When executing a precompile, a new store layer is added to the top of the stack, and state writes are performed on this new layer.
  • If a revert occurs during execution, the invalid store layers are popped off the stack to ensure that a valid store layer remains at the top.
  • When committing changes, the writes are propagated sequentially from the top of the stack down to the bottom and applied to the initialStore.
  • The Snapshot() method of the new store uses approximately 1.4 times more memory than the previously used CacheMultiStore(), but it provides a more robust structure that avoids edge cases.

Benchmark

memory_usage_full_stack_based_updated

The benchmark results show that the new Snapshot() method uses significantly less memory than a deep copy, and the gap widens as the number of iterations increases.

cms_vs_snapshot_stack_based_updated

Like CacheMultiStore(), the new Snapshot() method exhibits linear memory growth with increasing iterations, using approximately 1.4× more memory than CacheMultiStore()

Closes: #225


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • tackled an existing issue or discussed with a team member
  • left instructions on how to review the changes
  • targeted the main branch

Reviewers Checklist

All items are required.
Please add a note if the item is not applicable
and please add your handle next to the items reviewed
if you only reviewed selected items.

I have...

  • added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • confirmed all author checklist items have been addressed
  • confirmed that this PR does not change production code
  • reviewed content
  • tested instructions (if applicable)
  • confirmed all CI checks have passed

@cloudgray cloudgray changed the title Poc/apply cache stack feat(x/vm): apply stack-based StateDB snapshot mechamism for precompile call Jun 24, 2025
@cloudgray cloudgray self-assigned this Jun 24, 2025
@cloudgray cloudgray marked this pull request as ready for review June 25, 2025 14:09
Copy link
Contributor

@zsystm zsystm left a comment

Choose a reason for hiding this comment

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

@cloudgray
Since the actual type of s.cacheCtx.MultiStore() at this point is *snapshotmulti.Store, I think it's clearer to cast it explicitly rather than going through the storetypes.CacheMultiStore interface.

While *snapshotmulti.Store does implement CacheMultiStore, making that implicit assumption here could lead to confusion for future maintainers who aren’t aware of the underlying implementation. Being explicit improves readability and reduces ambiguity in understanding what store we’re operating on.

I checked that there are no errors after the suggested change.

@zsystm
Copy link
Contributor

zsystm commented Jun 26, 2025

@cloudgray
Left a couple of nits, but overall LGTM — nice work!

s.Require().NoError(err, "expected no error when running the precompile")
s.Require().NotNil(resp.Ret, "expected returned bytes not to be nil")
testutil.ValidateWrites(s.T(), cms, 2)
// NOTES: After stack-based snapshot mechanism is added for precopile call,
Copy link
Member

Choose a reason for hiding this comment

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

typo in precopile

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed in 264a8fe

s.Require().ErrorContains(err, tc.errContains)
// Writes once because of gas usage
testutil.ValidateWrites(s.T(), cms, 1)
// NOTES: After stack-based snapshot mechanism is added for precopile call,
Copy link
Member

Choose a reason for hiding this comment

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

same as above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed in 264a8fe

}

delegateCheck := passCheck.WithExpEvents(staking.EventTypeDelegate, staking.EventTypeDelegate)
// Tx should be successful, but no state changes happened
Copy link
Member

Choose a reason for hiding this comment

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

What do you mean by no state changes? Isn't there a delegation being tested here?

Copy link
Member

Choose a reason for hiding this comment

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

After running through the tests, I'm going to assume you mean no unintended state changes from the reversions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That comment was left unchanged during the process of copying and modifying an existing test case. 😅
Fixed in a881f29

Copy link
Member

@vladjdk vladjdk left a comment

Choose a reason for hiding this comment

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

Approving this. Great work! I have a much better understanding of how the entire snapshotting system works because of your testing and the cleanliness of your code. We should work with Cordt to turn this into some solid docs!

return s.CacheMultiStore().(storetypes.CacheWrap)
}

// CacheWrapWithTrace implements the CacheWrapper interface.
Copy link
Member

Choose a reason for hiding this comment

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

Let's add in the docs that this doesn't do anything

Copy link
Contributor Author

Choose a reason for hiding this comment

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

applied! ae1c9fc

snapshotStore.GetKVStore(key).Set([]byte("c"), []byte("3"))

snapshotStore.RevertToSnapshot(idx1)
require.Nil(t, snapshotStore.GetKVStore(key).Get([]byte("c")))
Copy link
Member

Choose a reason for hiding this comment

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

Could we test this using the same key for the KVs (i.e. use "a" each time with a different value)? It would simulate someone overwriting the same address store for something like a delegation over multiple different snapshots.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe as an added test case - I do like this one as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

applied! 33f939a

func TestSnapshotMultiCacheWrapWithTrace(t *testing.T) {
snapshotStore, _ := setupStore()

wrap := snapshotStore.CacheWrapWithTrace(nil, nil)
Copy link
Member

Choose a reason for hiding this comment

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

Document that this is just a regular cache wrap

Copy link
Contributor Author

Choose a reason for hiding this comment

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

applied! 33f939a

@cloudgray cloudgray merged commit e6fe094 into cosmos:main Jul 1, 2025
15 checks passed
Eric-Warehime pushed a commit that referenced this pull request Jul 17, 2025
commit 3b20e2b727685443693838ffcbd5851b2e4c26b8
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 14:56:44 2025 +0900

    feat(x/vm): apply stack-based StateDB snapshot mechanism for precompile call

    This commit is backport of cosmos/evm [PR#244](#244)

commit 3dbee41fca3beda2778ed7e2431800086fe3ea04
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 09:56:24 2025 +0900

    chore: reset consensusVersion of modules to 1

commit 25eb3afa5ff4b96dcb1f8a69d9eb7a326695dc89
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 09:41:48 2025 +0900

    chore(precompiles/common): fix comment

commit a7cdcc537e0a33f36e8de36f0247bfe3a2a1d9dc
Author: Kyuhyeon Choi <[email protected]>
Date:   Thu Jul 10 19:45:25 2025 +0900

    fix(precompiles/common): hex address parsing method

commit 5a937ecd545703515993e6af47def0574a398897
Author: Kyuhyeon Choi <[email protected]>
Date:   Tue Jul 8 09:49:35 2025 +0900

    chore: fix lint

commit c32a6e5128c592d5fc791fc13733fc52e18553bc
Author: Kyuhyeon Choi <[email protected]>
Date:   Mon Jul 7 23:09:24 2025 +0900

    feat(precompiles): add BalanceHandler to handle native balance change (#201)

    * feat(precompiles): add BalanceHandler to handle native balance change

    * refactor: remove parts of calling SetBalanceChangeEntries

    * chore: fix lint

    * chore(precompiles/distribution): remove unused helper function

    * chore(precompiles): modify comments

    * chore: restore modification to be applied later

    * chore: fix typo

    * chore: resolve conflict

    * chore: fix lint

    * test(precompiles/common) add unit test cases

    * chore: fix lint

    * fix(test): precompile test case that intermittently fails

    * refactor: move mock evm keeper to x/vm/types/mocks

    * chore: add KVStoreKeys() method to mock evmKeeper

    * refactoring balance handling

    * test(precompile/common): improve unit test for balance handler

    * refactor(precompiles): separate common logic

    * Revert "refactor(precompiles): separate common logic"

    This reverts commit 25b89f3.

    * Revert "Merge pull request #1 from zsystm/poc/precompiles-balance-handler"

    This reverts commit 46cd527, reversing
    changes made to b532fd5.

    ---------

    Co-Authored-By: zsystm <[email protected]>
    Co-Authored-By: Vlad J <[email protected]>

commit 37e0f9a8cdd362c78d411bc4291e61b64bbc3dbc
Author: Haber <[email protected]>
Date:   Mon Jul 7 10:28:01 2025 +0900

    feat(precompiles): add BalanceHandler to handle native balance change (#201)

    * feat(precompiles): add BalanceHandler to handle native balance change

    * refactor: remove parts of calling SetBalanceChangeEntries

    * chore: fix lint

    * chore(precompiles/distribution): remove unused helper function

    * chore(precompiles): modify comments

    * chore: restore modification to be applied later

    * chore: fix typo

    * chore: resolve conflict

    * chore: fix lint

    * test(precompiles/common) add unit test cases

    * chore: fix lint

    * fix(test): precompile test case that intermittently fails

    * refactor: move mock evm keeper to x/vm/types/mocks

    * chore: add KVStoreKeys() method to mock evmKeeper

    * refactoring balance handling

    * test(precompile/common): improve unit test for balance handler

    * refactor(precompiles): separate common logic

    * Revert "refactor(precompiles): separate common logic"

    This reverts commit 25b89f3.

    * Revert "Merge pull request #1 from zsystm/poc/precompiles-balance-handler"

    This reverts commit 46cd527, reversing
    changes made to b532fd5.

    ---------

    Co-authored-by: zsystm <[email protected]>
    Co-authored-by: Vlad J <[email protected]>

commit a5bf7d1f255ab43a28ac19d3348d56f20d3dbe29
Author: Haber <[email protected]>
Date:   Thu Jun 12 11:17:44 2025 +0900

    refactor(precompiles): apply journal-based revert approach (#205)

    * refactor(precompiles): apply journal-based revert approach

    * refactor: remove unused Snapshot type

    * chore: fix lint
Eric-Warehime added a commit that referenced this pull request Jul 17, 2025
commit 3b20e2b727685443693838ffcbd5851b2e4c26b8
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 14:56:44 2025 +0900

    feat(x/vm): apply stack-based StateDB snapshot mechanism for precompile call

    This commit is backport of cosmos/evm [PR#244](#244)

commit 3dbee41fca3beda2778ed7e2431800086fe3ea04
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 09:56:24 2025 +0900

    chore: reset consensusVersion of modules to 1

commit 25eb3afa5ff4b96dcb1f8a69d9eb7a326695dc89
Author: Kyuhyeon Choi <[email protected]>
Date:   Fri Jul 11 09:41:48 2025 +0900

    chore(precompiles/common): fix comment

commit a7cdcc537e0a33f36e8de36f0247bfe3a2a1d9dc
Author: Kyuhyeon Choi <[email protected]>
Date:   Thu Jul 10 19:45:25 2025 +0900

    fix(precompiles/common): hex address parsing method

commit 5a937ecd545703515993e6af47def0574a398897
Author: Kyuhyeon Choi <[email protected]>
Date:   Tue Jul 8 09:49:35 2025 +0900

    chore: fix lint

commit c32a6e5128c592d5fc791fc13733fc52e18553bc
Author: Kyuhyeon Choi <[email protected]>
Date:   Mon Jul 7 23:09:24 2025 +0900

    feat(precompiles): add BalanceHandler to handle native balance change (#201)

    * feat(precompiles): add BalanceHandler to handle native balance change

    * refactor: remove parts of calling SetBalanceChangeEntries

    * chore: fix lint

    * chore(precompiles/distribution): remove unused helper function

    * chore(precompiles): modify comments

    * chore: restore modification to be applied later

    * chore: fix typo

    * chore: resolve conflict

    * chore: fix lint

    * test(precompiles/common) add unit test cases

    * chore: fix lint

    * fix(test): precompile test case that intermittently fails

    * refactor: move mock evm keeper to x/vm/types/mocks

    * chore: add KVStoreKeys() method to mock evmKeeper

    * refactoring balance handling

    * test(precompile/common): improve unit test for balance handler

    * refactor(precompiles): separate common logic

    * Revert "refactor(precompiles): separate common logic"

    This reverts commit 25b89f3.

    * Revert "Merge pull request #1 from zsystm/poc/precompiles-balance-handler"

    This reverts commit 46cd527, reversing
    changes made to b532fd5.

    ---------

    Co-Authored-By: zsystm <[email protected]>
    Co-Authored-By: Vlad J <[email protected]>

commit 37e0f9a8cdd362c78d411bc4291e61b64bbc3dbc
Author: Haber <[email protected]>
Date:   Mon Jul 7 10:28:01 2025 +0900

    feat(precompiles): add BalanceHandler to handle native balance change (#201)

    * feat(precompiles): add BalanceHandler to handle native balance change

    * refactor: remove parts of calling SetBalanceChangeEntries

    * chore: fix lint

    * chore(precompiles/distribution): remove unused helper function

    * chore(precompiles): modify comments

    * chore: restore modification to be applied later

    * chore: fix typo

    * chore: resolve conflict

    * chore: fix lint

    * test(precompiles/common) add unit test cases

    * chore: fix lint

    * fix(test): precompile test case that intermittently fails

    * refactor: move mock evm keeper to x/vm/types/mocks

    * chore: add KVStoreKeys() method to mock evmKeeper

    * refactoring balance handling

    * test(precompile/common): improve unit test for balance handler

    * refactor(precompiles): separate common logic

    * Revert "refactor(precompiles): separate common logic"

    This reverts commit 25b89f3.

    * Revert "Merge pull request #1 from zsystm/poc/precompiles-balance-handler"

    This reverts commit 46cd527, reversing
    changes made to b532fd5.

    ---------

    Co-authored-by: zsystm <[email protected]>
    Co-authored-by: Vlad J <[email protected]>

commit a5bf7d1f255ab43a28ac19d3348d56f20d3dbe29
Author: Haber <[email protected]>
Date:   Thu Jun 12 11:17:44 2025 +0900

    refactor(precompiles): apply journal-based revert approach (#205)

    * refactor(precompiles): apply journal-based revert approach

    * refactor: remove unused Snapshot type

    * chore: fix lint
@Pitasi Pitasi mentioned this pull request Jul 30, 2025
9 tasks
zsystm pushed a commit to zsystm/evm that referenced this pull request Nov 2, 2025
…le call (cosmos#244)

* feat(x/vm): add cacheStack for CacheMultiStore snapshot

* fix(x/vm): StateDB.snapshotter

* feat(x/vm): add keys field to x/vm keeper and use keys for snapshot

* deps: remove cosmossdk.io/store fork

* refactor(x/vm): refactor snapshot multi store and add comments

* test(x/vm): add benchmark test for snapshotmulti.Store

* test(precompiles): add edge case test for precompile

* refactor(x/vm): modify snapshot stores

dep(evmd): go mod tidy

refactor: change package name of stack based store

refactor(x/vm/store): modify type casting

refactor(x/vm): rename store packages

* fix(x/vm): order store keys for snapshot store

* chore(x/vm/store): modify comments

* chore(x/vm/store): add comments

* test(x/vm/store): add unit tests

* chore(x/vm): fix lint

* chore: fix lint

* chore: fix lint

* chore(x/vm/store): remove unnecessary function call

* test: modify TestCMS

* fix(tests): precompile test case that intermittently fails

* chore(x/vm/store): rename variable cms into snapshotStore in test code

* chore: resolve merge conflict

* chore(x/vm) fix lint

* chore: fix typo

* chore: modify comment

* chore(x/vm/store): add comments

* test(x/vm/store): add test case for overwrite to same key
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.

Research Possibility of Keeping CMS instead of Copy()

3 participants