Skip to content
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(store/v2): gaskv store #18240

Merged
merged 29 commits into from
Oct 26, 2023
Merged

feat(store/v2): gaskv store #18240

merged 29 commits into from
Oct 26, 2023

Conversation

alexanderbez
Copy link
Contributor

@alexanderbez alexanderbez commented Oct 24, 2023

Description

closes: #18225

NOTE: This increases fixed gas cost for deletes from 1000 to 1500


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

  • included the correct type prefix in the PR title
  • added ! to the type prefix if API or client breaking change
  • targeted the correct branch (see PR Targeting)
  • provided a link to the relevant issue or specification
  • followed the guidelines for building modules
  • included the necessary unit and integration tests
  • added a changelog entry to CHANGELOG.md
  • included comments for documenting Go code
  • updated the relevant documentation or specification
  • reviewed "Files changed" and left comments if necessary
  • run make lint and make test
  • confirmed all CI checks have passed

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

  • confirmed the correct type prefix in the PR title
  • confirmed ! in the type prefix if API or client breaking change
  • confirmed all author checklist items have been addressed
  • reviewed state machine logic
  • reviewed API design and naming
  • reviewed documentation is accurate
  • reviewed tests and test coverage
  • manually tested (if applicable)

Summary by CodeRabbit

  • New Feature: Introduced a new gas metering system to track resource consumption during store operations. This will enhance the system's efficiency and transparency, allowing users to monitor and manage their resource usage more effectively.
  • New Feature: Added an iterator implementation for the key-value store, which includes gas consumption logic. This will improve the performance of data retrieval operations.
  • Test: Implemented a comprehensive test suite for the new gas metering system, ensuring its reliability and robustness.
  • Refactor: Improved error messaging in the Store struct methods for better debugging and user experience.
  • Style: Minor code style adjustments for better readability and maintenance.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 24, 2023

Walkthrough

This pull request introduces a comprehensive gas metering system for store operations. It includes the creation of a new store package, the implementation of gas meter interfaces, and the addition of gas consumption logic to key-value store operations. The changes also include a robust test suite to ensure the correct behavior of the new functionality.

Changes

File(s) Summary
store/gas.go Introduced a store package for gas metering, including gas-related types, meter interfaces, and gas consumption functions.
store/kv/gas/iterator.go Added an iterator implementation for a key-value store with gas consumption logic.
store/kv/gas/store.go Implemented the store.BranchedKVStore interface for gas metering.
store/kv/gas/store_test.go Added a test suite for the gas package, verifying the behavior of the gasKVStore implementation.
store/kv/mem/store.go Minor change: moved the const declaration for the degree variable to a comment.
store/kv/trace/store.go Updated the Branch and BranchWithTrace methods to panic with a formatted error message.
store/storage/storage_bench_test.go Imported the "github.com/stretchr/testify/require" package.

"In the land of code, where logic is king, 🐇
A new gas meter, this PR does bring. 🎉
With each store operation, it keeps a tally, ⛽
Ensuring the system runs smoothly, not dally. 🚀
Tests ensure it works as expected, 🧪
So any bugs can be detected. 🐞
Celebrate this change, for it's no small feat, 🎊
Making our codebase more complete!" 🥳


Tips

Chat with CodeRabbit Bot (@coderabbitai)

  • If you reply to a review comment from CodeRabbit, the bot will automatically respond.
  • To engage with CodeRabbit bot directly around the specific lines of code in the PR, mention @coderabbitai in your review comment
  • Note: Review comments are made on code diffs or files, not on the PR overview.
  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger a review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai help to get help.

Note: For conversation with the bot, please use the review comments on code diffs or files.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • The JSON schema for the configuration file is available here.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/coderabbit-overrides.json

@tac0turtle
Copy link
Member

applicable issue: #13961

@alexanderbez
Copy link
Contributor Author

applicable issue: #13961

@tac0turtle thanks for raising that to my attention. I recall seeing that issue a while ago. I'm trying to understand what should really come out of that. It seems there are two core ideas:

  1. Upfront fixed cost (ReadFlat) for iterator creation (pretty straightforward)
  2. Refactor/cleanup (I'd like more clarification on what could be cleaned up given that we no longer have CacheKV)

cc @ValarDragon

@alexanderbez alexanderbez marked this pull request as ready for review October 25, 2023 17:23
@alexanderbez alexanderbez requested a review from a team as a code owner October 25, 2023 17:23
@github-actions
Copy link
Contributor

@alexanderbez your pull request is missing a changelog!

@github-prbot github-prbot requested review from a team and removed request for a team October 25, 2023 17:23
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 3

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 86eaeed and 2238f44.
Files selected for processing (6)
  • store/gas.go (1 hunks)
  • store/kv/gas/iterator.go (1 hunks)
  • store/kv/gas/store.go (1 hunks)
  • store/kv/gas/store_test.go (1 hunks)
  • store/kv/mem/store.go (1 hunks)
  • store/kv/trace/store.go (2 hunks)
Files skipped from review due to trivial changes (2)
  • store/kv/gas/store_test.go
  • store/kv/mem/store.go
Additional comments: 24
store/kv/trace/store.go (3)
  • 6-6: The fmt package has been added to the import list. Ensure that it is being used in the code and is not an unnecessary import.

  • 94-95: The panic message in the Branch() method has been updated to use the type of the Store struct. This change provides more specific information in the panic message, which can be helpful for debugging.

- panic("cannot call Branch() on tracekv.Store")
+ panic(fmt.Sprintf("cannot call Branch() on %T", s))
  • 97-98: The panic message in the BranchWithTrace() method has been updated in the same way as the Branch() method.
- panic("cannot call BranchWithTrace() on tracekv.Store")
+ panic(fmt.Sprintf("cannot call BranchWithTrace() on %T", s))
store/kv/gas/iterator.go (5)
  • 7-11: The iterator struct is well defined with all necessary fields for gas metering and parent store operations. It's good to see that the parent store's Iterator is being used, which ensures that the underlying store's functionality is not being altered, only extended with gas metering.

  • 13-19: The newIterator function is correctly initializing the iterator struct. It's good to see that the function is not exported, which means it's only intended for use within the gas package. This is a good practice for encapsulation.

  • 21-48: The methods Domain, Valid, Key, Value, Next, Close, and Error are correctly delegating their operations to the parent iterator. This ensures that the underlying store's functionality is preserved.

  • 37-40: The Next method correctly calls consumeGasSeek before delegating to the parent iterator's Next method. This ensures that gas is consumed for each iteration step.

  • 50-63: The consumeGasSeek method correctly consumes gas based on the length of the current key and value if the iterator is valid. It also consumes a fixed amount of gas for each iteration step. This is a good implementation of gas metering for store operations.

store/gas.go (8)
  • 1-6: The import section looks clean and only includes necessary packages.

  • 8-24: The Gas type and constants for gas consumption descriptors are well defined.

  • 45-70: The GasMeter interface is well defined and covers all necessary methods for gas consumption tracking.

  • 72-81: The GasConfig struct is well defined and covers all necessary fields for gas cost configuration.

  • 83-98: The DefaultGasConfig function returns a default configuration for gas costs. The comment explains that these values are arbitrary and mainly reflect relative costs.

  • 100-171: The defaultGasMeter struct and its methods are well implemented. The ConsumeGas and RefundGas methods correctly handle gas consumption and refunding, including error handling for overflow and negative gas consumption.

  • 173-228: The infiniteGasMeter struct and its methods are well implemented. The ConsumeGas and RefundGas methods correctly handle gas consumption and refunding, including error handling for overflow and negative gas consumption.

  • 230-238: The addGasOverflow function correctly handles the addition of two Gas values and returns a boolean indicating whether an overflow occurred.

store/kv/gas/store.go (8)
  • 12-16: The Store struct is well defined with all necessary fields for a gas metered KVStore. It embeds the parent KVStore, a gas meter, and a gas configuration. This is a good example of composition in Go, where the Store struct "has a" KVStore, GasMeter, and GasConfig, rather than "is a" KVStore, GasMeter, or GasConfig.

  • 18-24: The New function is a constructor for the Store struct. It takes a KVStore, GasMeter, and GasConfig as arguments and returns a BranchedKVStore. This is a good use of dependency injection, as it allows the caller to provide the specific implementations of KVStore, GasMeter, and GasConfig that should be used.

  • 34-42: The Get method consumes gas for the read operation. It consumes a flat cost for the read operation and additional costs per byte for the key and value. This is a good way to account for the computational resources used by the operation.

  • 44-47: The Has method consumes a flat cost for the operation. This is a good way to account for the computational resources used by the operation.

  • 49-54: The Set method consumes gas for the write operation. It consumes a flat cost for the write operation and additional costs per byte for the key and value. This is a good way to account for the computational resources used by the operation.

  • 56-59: The Delete method consumes a flat cost for the operation. This is a good way to account for the computational resources used by the operation.

  • 83-85: The Iterator method returns a new iterator that consumes gas for each iteration step. This is a good way to account for the computational resources used by the operation.

  • 87-89: The ReverseIterator method returns a new reverse iterator that consumes gas for each iteration step. This is a good way to account for the computational resources used by the operation.

store/kv/gas/store.go Show resolved Hide resolved
store/kv/gas/store.go Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 2238f44 and 78bf4e6.
Files selected for processing (2)
  • store/gas.go (1 hunks)
  • store/kv/gas/store_test.go (1 hunks)
Additional comments: 15
store/kv/gas/store_test.go (13)
  • 1-12: The import statements are well organized and only necessary packages are imported. The constants defined are also appropriate for the test suite.

  • 19-25: The StoreTestSuite struct is well defined with all necessary fields for the test suite.

  • 27-29: The TestStorageTestSuite function correctly runs the test suite.

  • 31-35: The SetupTest function correctly initializes the parent store, gas meter, and gasKVStore for each test.

  • 37-40: The TearDownTest function correctly resets the gasKVStore after each test and checks for errors.

  • 42-44: The TestGetStoreKey function correctly tests the GetStoreKey method of the gasKVStore.

  • 46-48: The TestGetStoreType function correctly tests the GetStoreType method of the gasKVStore.

  • 50-56: The TestGet function correctly tests the Get method of the gasKVStore and checks the gas consumed.

  • 58-64: The TestHas function correctly tests the Has method of the gasKVStore and checks the gas consumed.

  • 66-69: The TestSet function correctly tests the Set method of the gasKVStore and checks the gas consumed.

  • 71-77: The TestDelete function correctly tests the Delete method of the gasKVStore and checks the gas consumed.

  • 79-94: The TestIterator function correctly tests the Iterator method of the gasKVStore and checks the gas consumed.

  • 96-111: The TestReverseIterator function correctly tests the ReverseIterator method of the gasKVStore and checks the gas consumed.

store/gas.go (2)
  • 202-208: The ConsumeGas method of infiniteGasMeter also checks for overflow and sets the consumed gas to the new value only if there is no overflow. This is a good practice as it prevents incorrect gas consumption values in case of overflow.

  • 230-238: The addGasOverflow function correctly checks for overflow before performing the addition operation. This is a good practice as it prevents integer overflow errors.

store/gas.go Show resolved Hide resolved
store/gas.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 78bf4e6 and 0c4f0bd.
Files selected for processing (1)
  • store/gas.go (1 hunks)
Additional comments: 4
store/gas.go (4)
  • 26-43: The error types ErrorNegativeGasConsumed, ErrorOutOfGas, and ErrorGasOverflow now have the Error method implementation, making them compliant with the error interface. This allows these types to be used wherever error is expected. Good job on addressing the previous comment.

  • 112-183: The defaultGasMeter struct and its methods provide a good implementation of the GasMeter interface. The methods are well-defined and handle edge cases such as gas overflow and exceeding the gas limit. The use of custom error types improves the readability of the code and allows for better error handling.

  • 185-240: The infiniteGasMeter struct and its methods provide an implementation of the GasMeter interface where the gas limit is infinite. This could be useful in scenarios where gas consumption is not a concern. The methods are well-defined and handle edge cases such as gas overflow.

  • 242-250: The addGasOverflow function is a utility function that adds two Gas values and checks for overflow. This is a good practice as it prevents potential integer overflow bugs.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 2

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 0c4f0bd and a9be8ea.
Files selected for processing (2)
  • store/gas.go (1 hunks)
  • store/storage/storage_bench_test.go (1 hunks)
Files skipped from review due to trivial changes (1)
  • store/storage/storage_bench_test.go
Additional comments: 2
store/gas.go (2)
  • 26-43: The error types ErrorNegativeGasConsumed, ErrorOutOfGas, and ErrorGasOverflow now have the Error method implementation, making them compliant with the error interface. This allows these types to be used wherever error is expected. Good job on addressing the previous comment.

  • 112-250: The defaultGasMeter and infiniteGasMeter implementations of the GasMeter interface are well-structured and follow the interface's contract. The panic behavior in case of gas overflow or out-of-gas situations is appropriate, as these are critical errors that should halt execution. The addGasOverflow helper function is a good way to handle potential overflow situations.

store/gas.go Outdated Show resolved Hide resolved
store/gas.go Show resolved Hide resolved
Copy link
Collaborator

@odeke-em odeke-em left a comment

Choose a reason for hiding this comment

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

LGTM code wise, and thank you @alexanderbez! Also nice and simple test for overflow: one day we should centralize that check in the cosmos-sdk helper libraries.

@alexanderbez alexanderbez disabled auto-merge October 26, 2023 15:20
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Review Status

Actionable comments generated: 1

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between a9be8ea and 88d7d0a.
Files selected for processing (1)
  • store/gas.go (1} hunks)
Additional comments: 4
store/gas.go (4)
  • 26-55: The error types ErrorNegativeGasConsumed, ErrorOutOfGas, and ErrorGasOverflow now implement the Error method, making them compliant with the error interface. This allows these types to be used wherever error is expected. Good job on addressing the previous comment.

  • 57-82: The GasMeter interface is well defined with clear method signatures and comments explaining their purpose. This makes it easy for other developers to implement their own versions of GasMeter if needed.

  • 84-104: The GasConfig struct provides a clear and flexible way to configure the gas cost for each operation on a KVStore. This allows for easy adjustments of gas costs in the future.

  • 123-261: The defaultGasMeter and infiniteGasMeter structs provide concrete implementations of the GasMeter interface. The methods are well implemented with clear error handling and panic conditions. The addGasOverflow function is a good utility function to handle potential overflow conditions when adding gas amounts.

store/gas.go Show resolved Hide resolved
@alexanderbez alexanderbez added this pull request to the merge queue Oct 26, 2023
Merged via the queue into main with commit bb05bf0 Oct 26, 2023
58 of 59 checks passed
@alexanderbez alexanderbez deleted the bez/18225-store-v2-gaskv-store branch October 26, 2023 16:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

GasKV Store
5 participants