Store Module
Module-level store integration helpers for key formatting, iterators, and codec utilities.
paxeer-network/modules/store/Overview
The store module provides utilities for Cosmos SDK module state management. It standardizes key formatting, iteration patterns, and marshaling/unmarshaling operations that other Paxeer modules use to interact with PaxDB storage.
Key Formatting
Modules store state in key-value pairs. The store module provides helpers for consistent key prefixing:
- Prefix constants: Each module defines unique byte prefixes for its keys
- Key builders: Functions to construct keys from module prefix + identifier
- Collision avoidance: Ensures different modules and different state types within a module never overlap
Example pattern:
const (
AccountPrefix = byte(0x01)
CodePrefix = byte(0x02)
StoragePrefix = byte(0x03)
)
func AccountKey(address common.Address) []byte {
return append([]byte{AccountPrefix}, address.Bytes()...)
}Iterator Utilities
The store module provides helpers for range queries:
- Prefix iteration: Iterate all keys sharing a prefix
- Range bounds: Start and end keys for bounded iteration
- Reverse iteration: Iterate keys in descending order
These utilities wrap the underlying PaxDB iterators and handle edge cases like prefix overflow and empty ranges.
Codec Helpers
The store module standardizes state marshaling:
- Protobuf encoding: Marshal/unmarshal state structs to/from bytes
- JSON encoding: For human-readable export/import
- Legacy amino support: For backwards compatibility with older state formats
Modules call these helpers instead of directly invoking codec methods, ensuring consistent encoding across the codebase.
Common Patterns
Get/Set State
func (k Keeper) GetAccount(ctx sdk.Context, addr common.Address) (Account, error) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(AccountKey(addr))
if bz == nil {
return Account{}, errors.New("account not found")
}
var acc Account
k.cdc.MustUnmarshal(bz, &acc)
return acc, nil
}
func (k Keeper) SetAccount(ctx sdk.Context, addr common.Address, acc Account) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&acc)
store.Set(AccountKey(addr), bz)
}Iterate All Accounts
func (k Keeper) IterateAccounts(ctx sdk.Context, cb func(addr common.Address, acc Account) bool) {
store := ctx.KVStore(k.storeKey)
iter := store.Iterator(PrefixRange(AccountPrefix))
defer iter.Close()
for ; iter.Valid(); iter.Next() {
var acc Account
k.cdc.MustUnmarshal(iter.Value(), &acc)
addr := common.BytesToAddress(iter.Key()[1:]) // skip prefix byte
if cb(addr, acc) {
break
}
}
}State Migration
The store module includes utilities for state migration during chain upgrades:
- Key remapping: Move state from old keys to new keys
- Schema changes: Transform state from old format to new format
- Batching: Migrate large state in chunks to avoid running out of gas
Integration with PaxDB
The store module sits above PaxDB. It provides a module-friendly API while PaxDB handles the low-level storage engine details (state commitment, state store, WAL).
Modules call store helpers → store helpers call SDK KVStore → SDK KVStore calls PaxDB.
Testing Utilities
The store module provides test helpers:
- In-memory stores: Fast, isolated storage for unit tests
- Mock contexts: Simulate SDK context with controlled block height, time
- State snapshots: Capture and restore state for test isolation