feat!: Add object store (#25470)
Co-authored-by: yihuang <huang@crypto.com> Co-authored-by: mmsqe <mavis@crypto.com> Co-authored-by: mmsqe <tqd0800210105@gmail.com> Co-authored-by: Tyler <48813565+technicallyty@users.noreply.github.com>
This commit is contained in:
parent
5e022baf9b
commit
d790942c42
134
.github/workflows/test.yml
vendored
134
.github/workflows/test.yml
vendored
@ -147,7 +147,7 @@ jobs:
|
||||
|
||||
repo-analysis:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
needs: [tests, test-integration, test-e2e]
|
||||
needs: [tests, test-integration, test-e2e, test-clientv2, test-core, test-depinject, test-errors, test-math, test-schema, test-collections, test-cosmovisor, test-confix, test-store, test-log, test-x-tx, test-tools-benchmark]
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: technote-space/get-diff-action@v6.1.2
|
||||
@ -184,11 +184,76 @@ jobs:
|
||||
with:
|
||||
name: "${{ github.sha }}-e2e-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-clientv2-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-core-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-depinject-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-errors-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-math-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-schema-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-collections-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-cosmovisor-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-confix-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-store-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-log-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-x-tx-coverage"
|
||||
continue-on-error: true
|
||||
- uses: actions/download-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-tools-benchmark-coverage"
|
||||
continue-on-error: true
|
||||
- name: Upload coverage to Codecov
|
||||
if: env.GIT_DIFF
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
files: ./00profile.out,./01profile.out,./02profile.out,./03profile.out,./tests/integration-profile.out,./tests/e2e-profile.out
|
||||
files: ./00profile.out,./01profile.out,./02profile.out,./03profile.out,./integration-profile.out,./e2e-profile.out,./client/v2/coverage.out,./core/coverage.out,./depinject/coverage.out,./errors/coverage.out,./math/coverage.out,./schema/coverage.out,./collections/coverage.out,./tools/cosmovisor/coverage.out,./tools/confix/coverage.out,./store/coverage.out,./log/coverage.out,./x/tx/coverage.out,./tools/benchmark/coverage.out
|
||||
fail_ci_if_error: false
|
||||
verbose: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
@ -248,6 +313,11 @@ jobs:
|
||||
run: |
|
||||
cd client/v2
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-clientv2-coverage"
|
||||
path: ./client/v2/coverage.out
|
||||
|
||||
test-core:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -271,6 +341,11 @@ jobs:
|
||||
run: |
|
||||
cd core
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-core-coverage"
|
||||
path: ./core/coverage.out
|
||||
|
||||
test-depinject:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -294,6 +369,11 @@ jobs:
|
||||
run: |
|
||||
cd depinject
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-depinject-coverage"
|
||||
path: ./depinject/coverage.out
|
||||
|
||||
test-errors:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -317,6 +397,11 @@ jobs:
|
||||
run: |
|
||||
cd errors
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-errors-coverage"
|
||||
path: ./errors/coverage.out
|
||||
|
||||
test-math:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -340,6 +425,11 @@ jobs:
|
||||
run: |
|
||||
cd math
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-math-coverage"
|
||||
path: ./math/coverage.out
|
||||
|
||||
test-schema:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -362,6 +452,11 @@ jobs:
|
||||
run: |
|
||||
cd schema
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-schema-coverage"
|
||||
path: ./schema/coverage.out
|
||||
|
||||
test-collections:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -385,6 +480,11 @@ jobs:
|
||||
run: |
|
||||
cd collections
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-collections-coverage"
|
||||
path: ./collections/coverage.out
|
||||
|
||||
test-cosmovisor:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -408,6 +508,11 @@ jobs:
|
||||
run: |
|
||||
cd tools/cosmovisor
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-cosmovisor-coverage"
|
||||
path: ./tools/cosmovisor/coverage.out
|
||||
|
||||
test-confix:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -431,6 +536,11 @@ jobs:
|
||||
run: |
|
||||
cd tools/confix
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-confix-coverage"
|
||||
path: ./tools/confix/coverage.out
|
||||
|
||||
test-store:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -455,6 +565,11 @@ jobs:
|
||||
cd store
|
||||
(cd streaming/abci/examples/file && go build .)
|
||||
go test -ldflags "-r /usr/local/lib" -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-store-coverage"
|
||||
path: ./store/coverage.out
|
||||
|
||||
test-log:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -478,6 +593,11 @@ jobs:
|
||||
run: |
|
||||
cd log
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-log-coverage"
|
||||
path: ./log/coverage.out
|
||||
|
||||
#############################
|
||||
### Cosmos SDK x/{module} ###
|
||||
@ -508,6 +628,11 @@ jobs:
|
||||
run: |
|
||||
cd x/tx
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace ledger test_ledger_mock' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-x-tx-coverage"
|
||||
path: ./x/tx/coverage.out
|
||||
|
||||
test-tools-benchmark:
|
||||
runs-on: depot-ubuntu-22.04-4
|
||||
@ -531,3 +656,8 @@ jobs:
|
||||
run: |
|
||||
cd tools/benchmark
|
||||
go test -mod=readonly -timeout 30m -coverprofile=coverage.out -covermode=atomic -tags='norace' ./...
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: env.GIT_DIFF
|
||||
with:
|
||||
name: "${{ github.sha }}-tools-benchmark-coverage"
|
||||
path: ./tools/benchmark/coverage.out
|
||||
|
||||
@ -42,10 +42,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
### Breaking Changes
|
||||
|
||||
* [#25090](https://github.com/cosmos/cosmos-sdk/pull/25090) Moved deprecated modules to `./contrib`. These modules are still available but will no longer be actively maintained or supported in the Cosmos SDK Bug Bounty program.
|
||||
* `x/group`
|
||||
* `x/nft`
|
||||
* `x/circuit`
|
||||
* `x/crisis`
|
||||
* `x/group`
|
||||
* `x/nft`
|
||||
* `x/circuit`
|
||||
* `x/crisis`
|
||||
* (crypto) [#24414](https://github.com/cosmos/cosmos-sdk/pull/24414) Remove sr25519 support, since it was removed in CometBFT v1.x (see: CometBFT [#3646](https://github.com/cometbft/cometbft/pull/3646)).
|
||||
|
||||
### Features
|
||||
@ -111,6 +111,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
* (x/mint) [#24436](https://github.com/cosmos/cosmos-sdk/pull/24436) Allow users to set a custom minting function used in the `x/mint` begin blocker.
|
||||
* The `InflationCalculationFn` argument to `mint.NewAppModule()` is now ignored and must be nil. To set a custom `InflationCalculationFn` on the default minter, use `mintkeeper.WithMintFn(mintkeeper.DefaultMintFn(customInflationFn))`.
|
||||
* (api) [#24428](https://github.com/cosmos/cosmos-sdk/pull/24428) Add block height to response headers
|
||||
* (baseapp) [#25470](https://github.com/cosmos/cosmos-sdk/pull/25470) Support mount object store in baseapp, add `ObjectStore` api in context.
|
||||
|
||||
### Improvements
|
||||
|
||||
|
||||
@ -283,6 +283,9 @@ func (app *BaseApp) MountStores(keys ...storetypes.StoreKey) {
|
||||
case *storetypes.MemoryStoreKey:
|
||||
app.MountStore(key, storetypes.StoreTypeMemory)
|
||||
|
||||
case *storetypes.ObjectStoreKey:
|
||||
app.MountStore(key, storetypes.StoreTypeObject)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Unrecognized store key type :%T", key))
|
||||
}
|
||||
@ -321,6 +324,16 @@ func (app *BaseApp) MountMemoryStores(keys map[string]*storetypes.MemoryStoreKey
|
||||
}
|
||||
}
|
||||
|
||||
// MountObjectStores mounts all transient object stores with the BaseApp's internal
|
||||
// commit multi-store.
|
||||
func (app *BaseApp) MountObjectStores(keys map[string]*storetypes.ObjectStoreKey) {
|
||||
skeys := slices.Sorted(maps.Keys(keys))
|
||||
for _, key := range skeys {
|
||||
memKey := keys[key]
|
||||
app.MountStore(memKey, storetypes.StoreTypeObject)
|
||||
}
|
||||
}
|
||||
|
||||
// MountStore mounts a store to the provided key in the BaseApp multistore,
|
||||
// using the default DB.
|
||||
func (app *BaseApp) MountStore(key storetypes.StoreKey, typ storetypes.StoreType) {
|
||||
|
||||
@ -988,6 +988,25 @@ func TestGetEmptyConsensusParams(t *testing.T) {
|
||||
require.Equal(t, uint64(0), suite.baseApp.GetMaximumBlockGas(ctx))
|
||||
}
|
||||
|
||||
func TestMountStores(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
db := dbm.NewMemDB()
|
||||
name := t.Name()
|
||||
app := baseapp.NewBaseApp(name, logger, db, nil)
|
||||
kvKey := storetypes.NewKVStoreKey("kv")
|
||||
transKey := storetypes.NewTransientStoreKey("trans")
|
||||
memKey := storetypes.NewMemoryStoreKey("mem")
|
||||
objKey := storetypes.NewObjectStoreKey("obj")
|
||||
app.MountStores(kvKey, transKey, memKey, objKey)
|
||||
objKey2 := storetypes.NewObjectStoreKey("obj2")
|
||||
app.MountObjectStores(map[string]*storetypes.ObjectStoreKey{"obj2": objKey2})
|
||||
require.NoError(t, app.LoadLatestVersion())
|
||||
for _, keyName := range []storetypes.StoreKey{kvKey, transKey, memKey, objKey} {
|
||||
require.NotNil(t, app.CommitMultiStore().GetStore(keyName))
|
||||
}
|
||||
require.NotNil(t, app.CommitMultiStore().GetStore(objKey2))
|
||||
}
|
||||
|
||||
func TestLoadVersionPruning(t *testing.T) {
|
||||
logger := log.NewNopLogger()
|
||||
pruningOptions := pruningtypes.NewCustomPruningOptions(10, 15)
|
||||
|
||||
@ -14,7 +14,7 @@ Flags:
|
||||
--fees string Fees to pay along with transaction; eg: 10uatom
|
||||
--from string Name or address of private key with which to sign
|
||||
--gas string gas limit to set per-transaction; set to "auto" to calculate sufficient gas automatically. Note: "auto" option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of "fees". (default 200000)
|
||||
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
|
||||
--gas-adjustment float adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored (default 1)
|
||||
--gas-prices string Gas prices in decimal format to determine the transaction fee (e.g. 0.1uatom)
|
||||
--generate-only Build an unsigned transaction and write it to STDOUT (when enabled, the local Keybase only accessed when providing a key name)
|
||||
-h, --help help for send
|
||||
|
||||
@ -32,7 +32,6 @@ require (
|
||||
github.com/99designs/keyring v1.2.1 // indirect
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.2.0 // indirect
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
@ -46,7 +45,7 @@ require (
|
||||
github.com/cockroachdb/pebble v1.1.5 // indirect
|
||||
github.com/cockroachdb/redact v1.1.6 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect
|
||||
github.com/cometbft/cometbft v0.38.19 // indirect
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2 // indirect
|
||||
github.com/cometbft/cometbft-db v0.14.1 // indirect
|
||||
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||
github.com/cosmos/cosmos-db v1.1.3 // indirect
|
||||
@ -107,7 +106,7 @@ require (
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/linxGnu/grocksdb v1.9.8 // indirect
|
||||
github.com/linxGnu/grocksdb v1.10.1 // indirect
|
||||
github.com/manifoldco/promptui v0.9.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
@ -116,7 +115,6 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
@ -136,9 +134,10 @@ require (
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/spf13/viper v1.21.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/supranational/blst v0.3.16 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||
github.com/tidwall/btree v1.7.0 // indirect
|
||||
github.com/tidwall/btree v1.8.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/zondax/golem v0.27.0 // indirect
|
||||
github.com/zondax/hid v0.9.2 // indirect
|
||||
@ -162,9 +161,17 @@ require (
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
nhooyr.io/websocket v1.8.17 // indirect
|
||||
pgregory.net/rapid v1.2.0 // indirect
|
||||
)
|
||||
|
||||
// replace (
|
||||
// <temporary replace>
|
||||
// )
|
||||
replace (
|
||||
cosmossdk.io/store => ../../store
|
||||
github.com/cosmos/cosmos-sdk => ../../.
|
||||
)
|
||||
|
||||
@ -16,8 +16,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
|
||||
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
|
||||
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
|
||||
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
|
||||
cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o=
|
||||
cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A=
|
||||
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
|
||||
cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -44,8 +42,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I=
|
||||
github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg=
|
||||
github.com/adlio/schema v1.3.9 h1:MLYk1VX1dn7xHW7Kdm1ywKKLjh19DRnrc65axS5xQA8=
|
||||
github.com/adlio/schema v1.3.9/go.mod h1:GnxXztHzNh6pIc7qm3sw+jsmHrXgBy/x2RBSkKZ3L4w=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@ -71,8 +69,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E=
|
||||
github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.24.1 h1:hqnfFbjjk3pxGa5E9Ho3hjoU7odtUuNmJ9Ao+Bo8s1c=
|
||||
github.com/bits-and-blooms/bitset v1.24.1/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ=
|
||||
github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
|
||||
@ -135,8 +133,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/cometbft/cometbft v0.38.19 h1:vNdtCkvhuwUlrcLPAyigV7lQpmmo+tAq8CsB8gZjEYw=
|
||||
github.com/cometbft/cometbft v0.38.19/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2 h1:OfP4Qlw2L66xqvrNYSlVufYwXXP9frOPBnwYPyDttOk=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2/go.mod h1:6Lt9liF9HxSth+zDotxtv94SuGMzRfuHmI287USgjlw=
|
||||
github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ=
|
||||
github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ=
|
||||
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
|
||||
@ -151,8 +149,6 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP
|
||||
github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
|
||||
github.com/cosmos/cosmos-sdk v0.53.4 h1:kPF6vY68+/xi1/VebSZGpoxQqA52qkhUzqkrgeBn3Mg=
|
||||
github.com/cosmos/cosmos-sdk v0.53.4/go.mod h1:7U3+WHZtI44dEOnU46+lDzBb2tFh1QlMvi8Z5JugopI=
|
||||
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
|
||||
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
|
||||
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
|
||||
@ -379,8 +375,9 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@ -457,8 +454,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/linxGnu/grocksdb v1.9.8 h1:vOIKv9/+HKiqJAElJIEYv3ZLcihRxyP7Suu/Mu8Dxjs=
|
||||
github.com/linxGnu/grocksdb v1.9.8/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk=
|
||||
github.com/linxGnu/grocksdb v1.10.1 h1:YX6gUcKvSC3d0s9DaqgbU+CRkZHzlELgHu1Z/kmtslg=
|
||||
github.com/linxGnu/grocksdb v1.10.1/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
@ -540,8 +537,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
|
||||
github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@ -685,12 +682,14 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
|
||||
github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
|
||||
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
|
||||
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
|
||||
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
|
||||
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
||||
github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA=
|
||||
github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
@ -938,8 +937,8 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
|
||||
@ -43,6 +43,7 @@ ignore:
|
||||
- "client/docs/**" # Client documentation
|
||||
- "**/*.md" # Markdown files
|
||||
- "**/mock*.go" # Mock files
|
||||
- "**/mock/**" # Mock directories
|
||||
- "**/*.pb.gateway.go" # Gateway files
|
||||
|
||||
# How to handle multiple coverage reports
|
||||
|
||||
@ -26,8 +26,8 @@ func NewMockContext() *MockContext {
|
||||
}
|
||||
|
||||
func (m MockContext) KVStore(key storetypes.StoreKey) storetypes.KVStore {
|
||||
if s := m.store.GetCommitKVStore(key); s != nil {
|
||||
return s
|
||||
if s := m.store.GetCommitStore(key); s != nil {
|
||||
return s.(storetypes.KVStore)
|
||||
}
|
||||
m.store.MountStoreWithDB(key, storetypes.StoreTypeIAVL, m.db)
|
||||
if err := m.store.LoadLatestVersion(); err != nil {
|
||||
|
||||
@ -68,6 +68,7 @@ func init() {
|
||||
ProvideKVStoreKey,
|
||||
ProvideTransientStoreKey,
|
||||
ProvideMemoryStoreKey,
|
||||
ProvideObjectStoreKey,
|
||||
ProvideGenesisTxHandler,
|
||||
ProvideKVStoreService,
|
||||
ProvideMemoryStoreService,
|
||||
@ -238,6 +239,12 @@ func ProvideMemoryStoreKey(config *runtimev1alpha1.Module, key depinject.ModuleK
|
||||
return storeKey
|
||||
}
|
||||
|
||||
func ProvideObjectStoreKey(key depinject.ModuleKey, app *AppBuilder) *storetypes.ObjectStoreKey {
|
||||
storeKey := storetypes.NewObjectStoreKey(fmt.Sprintf("object:%s", key.Name()))
|
||||
registerStoreKey(app, storeKey)
|
||||
return storeKey
|
||||
}
|
||||
|
||||
func ProvideGenesisTxHandler(appBuilder *AppBuilder) genesis.TxHandler {
|
||||
return appBuilder.app
|
||||
}
|
||||
|
||||
@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
"cosmossdk.io/core/store"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
@ -150,7 +148,7 @@ func (s kvStoreAdapter) Set(key, value []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s kvStoreAdapter) Iterator(start, end []byte) dbm.Iterator {
|
||||
func (s kvStoreAdapter) Iterator(start, end []byte) storetypes.Iterator {
|
||||
it, err := s.store.Iterator(start, end)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -158,7 +156,7 @@ func (s kvStoreAdapter) Iterator(start, end []byte) dbm.Iterator {
|
||||
return it
|
||||
}
|
||||
|
||||
func (s kvStoreAdapter) ReverseIterator(start, end []byte) dbm.Iterator {
|
||||
func (s kvStoreAdapter) ReverseIterator(start, end []byte) storetypes.Iterator {
|
||||
it, err := s.store.ReverseIterator(start, end)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@ -114,6 +114,10 @@ func (ms multiStore) GetKVStore(key storetypes.StoreKey) storetypes.KVStore {
|
||||
return ms.kv[key]
|
||||
}
|
||||
|
||||
func (ms multiStore) GetObjKVStore(storetypes.StoreKey) storetypes.ObjKVStore {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (ms multiStore) GetStore(key storetypes.StoreKey) storetypes.Store {
|
||||
panic("not implemented")
|
||||
}
|
||||
@ -182,7 +186,7 @@ func (kv kvStore) CacheWrap() storetypes.CacheWrap {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (kv kvStore) CacheWrapWithTrace(w io.Writer, tc storetypes.TraceContext) storetypes.CacheWrap {
|
||||
func (kv kvStore) CacheWrapWithTrace(_ io.Writer, _ storetypes.TraceContext) storetypes.CacheWrap {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
|
||||
@ -237,6 +237,7 @@ require (
|
||||
// replace (
|
||||
// <temporary replace>
|
||||
// )
|
||||
replace cosmossdk.io/store => ../store
|
||||
|
||||
// Below are the long-lived replace of the SimApp
|
||||
replace (
|
||||
|
||||
@ -40,8 +40,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
|
||||
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
|
||||
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
|
||||
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
|
||||
cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o=
|
||||
cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A=
|
||||
cosmossdk.io/tools/confix v0.1.2 h1:2hoM1oFCNisd0ltSAAZw2i4ponARPmlhuNu3yy0VwI4=
|
||||
cosmossdk.io/tools/confix v0.1.2/go.mod h1:7XfcbK9sC/KNgVGxgLM0BrFbVcR/+6Dg7MFfpx7duYo=
|
||||
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
|
||||
@ -484,8 +482,9 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
|
||||
@ -35,6 +35,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
* [#24090](https://github.com/cosmos/cosmos-sdk/pull/24090) Running the `prune` command now disables async pruning.
|
||||
|
||||
### Features
|
||||
|
||||
* [#25470](https://github.com/cosmos/cosmos-sdk/pull/25470) Adds object KV stores and refactors the base store to be generic across the value parameter.
|
||||
|
||||
## v1.1.1 (September 06, 2024)
|
||||
|
||||
### Improvements
|
||||
|
||||
@ -14,21 +14,24 @@ import (
|
||||
// cache shadows (overrides) the parent.
|
||||
//
|
||||
// TODO: Optimize by memoizing.
|
||||
type cacheMergeIterator struct {
|
||||
parent types.Iterator
|
||||
cache types.Iterator
|
||||
type cacheMergeIterator[V any] struct {
|
||||
parent types.GIterator[V]
|
||||
cache types.GIterator[V]
|
||||
ascending bool
|
||||
|
||||
valid bool
|
||||
|
||||
isZero func(V) bool
|
||||
}
|
||||
|
||||
var _ types.Iterator = (*cacheMergeIterator)(nil)
|
||||
var _ types.Iterator = (*cacheMergeIterator[[]byte])(nil)
|
||||
|
||||
func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) types.Iterator {
|
||||
iter := &cacheMergeIterator{
|
||||
func NewCacheMergeIterator[V any](parent, cache types.GIterator[V], ascending bool, isZero func(V) bool) types.GIterator[V] {
|
||||
iter := &cacheMergeIterator[V]{
|
||||
parent: parent,
|
||||
cache: cache,
|
||||
ascending: ascending,
|
||||
isZero: isZero,
|
||||
}
|
||||
|
||||
iter.valid = iter.skipUntilExistsOrInvalid()
|
||||
@ -37,17 +40,17 @@ func NewCacheMergeIterator(parent, cache types.Iterator, ascending bool) types.I
|
||||
|
||||
// Domain implements Iterator.
|
||||
// Returns parent domain because cache and parent domains are the same.
|
||||
func (iter *cacheMergeIterator) Domain() (start, end []byte) {
|
||||
func (iter *cacheMergeIterator[V]) Domain() (start, end []byte) {
|
||||
return iter.parent.Domain()
|
||||
}
|
||||
|
||||
// Valid implements Iterator.
|
||||
func (iter *cacheMergeIterator) Valid() bool {
|
||||
func (iter *cacheMergeIterator[V]) Valid() bool {
|
||||
return iter.valid
|
||||
}
|
||||
|
||||
// Next implements Iterator
|
||||
func (iter *cacheMergeIterator) Next() {
|
||||
func (iter *cacheMergeIterator[V]) Next() {
|
||||
iter.assertValid()
|
||||
|
||||
switch {
|
||||
@ -74,7 +77,7 @@ func (iter *cacheMergeIterator) Next() {
|
||||
}
|
||||
|
||||
// Key implements Iterator
|
||||
func (iter *cacheMergeIterator) Key() []byte {
|
||||
func (iter *cacheMergeIterator[V]) Key() []byte {
|
||||
iter.assertValid()
|
||||
|
||||
// If parent is invalid, get the cache key.
|
||||
@ -104,7 +107,7 @@ func (iter *cacheMergeIterator) Key() []byte {
|
||||
}
|
||||
|
||||
// Value implements Iterator
|
||||
func (iter *cacheMergeIterator) Value() []byte {
|
||||
func (iter *cacheMergeIterator[V]) Value() V {
|
||||
iter.assertValid()
|
||||
|
||||
// If parent is invalid, get the cache value.
|
||||
@ -134,7 +137,7 @@ func (iter *cacheMergeIterator) Value() []byte {
|
||||
}
|
||||
|
||||
// Close implements Iterator
|
||||
func (iter *cacheMergeIterator) Close() error {
|
||||
func (iter *cacheMergeIterator[V]) Close() error {
|
||||
err1 := iter.cache.Close()
|
||||
if err := iter.parent.Close(); err != nil {
|
||||
return err
|
||||
@ -145,7 +148,7 @@ func (iter *cacheMergeIterator) Close() error {
|
||||
|
||||
// Error returns an error if the cacheMergeIterator is invalid defined by the
|
||||
// Valid method.
|
||||
func (iter *cacheMergeIterator) Error() error {
|
||||
func (iter *cacheMergeIterator[V]) Error() error {
|
||||
if !iter.Valid() {
|
||||
return errors.New("invalid cacheMergeIterator")
|
||||
}
|
||||
@ -155,14 +158,14 @@ func (iter *cacheMergeIterator) Error() error {
|
||||
|
||||
// assertValid checks if not valid, panics.
|
||||
// NOTE: May have side-effect of iterating over cache.
|
||||
func (iter *cacheMergeIterator) assertValid() {
|
||||
func (iter *cacheMergeIterator[V]) assertValid() {
|
||||
if err := iter.Error(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// compare is like bytes.Compare but opposite if not ascending.
|
||||
func (iter *cacheMergeIterator) compare(a, b []byte) int {
|
||||
func (iter *cacheMergeIterator[V]) compare(a, b []byte) int {
|
||||
if iter.ascending {
|
||||
return bytes.Compare(a, b)
|
||||
}
|
||||
@ -175,9 +178,9 @@ func (iter *cacheMergeIterator) compare(a, b []byte) int {
|
||||
// If the current cache item is not a delete item, does nothing.
|
||||
// If `until` is nil, there is no limit, and cache may end up invalid.
|
||||
// CONTRACT: cache is valid.
|
||||
func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
|
||||
func (iter *cacheMergeIterator[V]) skipCacheDeletes(until []byte) {
|
||||
for iter.cache.Valid() &&
|
||||
iter.cache.Value() == nil &&
|
||||
iter.isZero(iter.cache.Value()) &&
|
||||
(until == nil || iter.compare(iter.cache.Key(), until) < 0) {
|
||||
iter.cache.Next()
|
||||
}
|
||||
@ -186,7 +189,7 @@ func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) {
|
||||
// skipUntilExistsOrInvalid fast forwards cache (or parent+cache in case of deleted items) until current
|
||||
// item exists, or until iterator becomes invalid.
|
||||
// Returns whether the iterator is valid.
|
||||
func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
|
||||
func (iter *cacheMergeIterator[V]) skipUntilExistsOrInvalid() bool {
|
||||
for {
|
||||
// If parent is invalid, fast-forward cache.
|
||||
if !iter.parent.Valid() {
|
||||
@ -211,7 +214,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
|
||||
case 0: // parent == cache.
|
||||
// Skip over if cache item is a delete.
|
||||
valueC := iter.cache.Value()
|
||||
if valueC == nil {
|
||||
if iter.isZero(valueC) {
|
||||
iter.parent.Next()
|
||||
iter.cache.Next()
|
||||
|
||||
@ -223,7 +226,7 @@ func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool {
|
||||
case 1: // cache < parent
|
||||
// Skip over if cache item is a delete.
|
||||
valueC := iter.cache.Value()
|
||||
if valueC == nil {
|
||||
if iter.isZero(valueC) {
|
||||
iter.skipCacheDeletes(keyP)
|
||||
continue
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"cosmossdk.io/store/cachekv/internal"
|
||||
"cosmossdk.io/store/internal/btree"
|
||||
)
|
||||
|
||||
func BenchmarkLargeUnsortedMisses(b *testing.B) {
|
||||
@ -22,23 +22,23 @@ func BenchmarkLargeUnsortedMisses(b *testing.B) {
|
||||
}
|
||||
|
||||
func generateStore() *Store {
|
||||
cache := map[string]*cValue{}
|
||||
cache := map[string]*cValue[[]byte]{}
|
||||
unsorted := map[string]struct{}{}
|
||||
for i := 0; i < 5000; i++ {
|
||||
key := "A" + strconv.Itoa(i)
|
||||
unsorted[key] = struct{}{}
|
||||
cache[key] = &cValue{}
|
||||
cache[key] = &cValue[[]byte]{}
|
||||
}
|
||||
|
||||
for i := 0; i < 5000; i++ {
|
||||
key := "Z" + strconv.Itoa(i)
|
||||
unsorted[key] = struct{}{}
|
||||
cache[key] = &cValue{}
|
||||
cache[key] = &cValue[[]byte]{}
|
||||
}
|
||||
|
||||
return &Store{
|
||||
return &GStore[[]byte]{
|
||||
cache: cache,
|
||||
unsortedCache: unsorted,
|
||||
sortedCache: internal.NewBTree(),
|
||||
sortedCache: btree.NewBTree[[]byte](),
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,47 +10,70 @@ import (
|
||||
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/store/cachekv/internal"
|
||||
"cosmossdk.io/store/internal/btree"
|
||||
"cosmossdk.io/store/internal/conv"
|
||||
"cosmossdk.io/store/internal/kv"
|
||||
"cosmossdk.io/store/tracekv"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
// cValue represents a cached value.
|
||||
// If dirty is true, it indicates the cached value is different from the underlying value.
|
||||
type cValue struct {
|
||||
value []byte
|
||||
type cValue[V any] struct {
|
||||
value V
|
||||
dirty bool
|
||||
}
|
||||
|
||||
// Store wraps an in-memory cache around an underlying types.KVStore.
|
||||
type Store struct {
|
||||
mtx sync.Mutex
|
||||
cache map[string]*cValue
|
||||
unsortedCache map[string]struct{}
|
||||
sortedCache internal.BTree // always ascending sorted
|
||||
parent types.KVStore
|
||||
type kvPair[V any] struct {
|
||||
Key []byte
|
||||
Value V
|
||||
}
|
||||
|
||||
type Store = GStore[[]byte]
|
||||
|
||||
var _ types.CacheKVStore = (*Store)(nil)
|
||||
|
||||
// NewStore creates a new Store object
|
||||
func NewStore(parent types.KVStore) *Store {
|
||||
return &Store{
|
||||
cache: make(map[string]*cValue),
|
||||
return NewGStore(
|
||||
parent,
|
||||
types.BytesIsZero,
|
||||
types.BytesValueLen,
|
||||
)
|
||||
}
|
||||
|
||||
// GStore wraps an in-memory cache around an underlying types.KVStore.
|
||||
type GStore[V any] struct {
|
||||
mtx sync.Mutex
|
||||
cache map[string]*cValue[V]
|
||||
unsortedCache map[string]struct{}
|
||||
sortedCache btree.BTree[V] // always ascending sorted
|
||||
parent types.GKVStore[V]
|
||||
|
||||
// isZero is a function that returns true if the value is considered "zero", for []byte and pointers the zero value
|
||||
// is `nil`, the zero value is not allowed to set to a key, and it's returned if the key is not found.
|
||||
isZero func(V) bool
|
||||
// valueLen validates the value before it's set
|
||||
valueLen func(V) int
|
||||
}
|
||||
|
||||
// NewGStore creates a new Store object
|
||||
func NewGStore[V any](parent types.GKVStore[V], isZero func(V) bool, valueLen func(V) int) *GStore[V] {
|
||||
return &GStore[V]{
|
||||
cache: make(map[string]*cValue[V]),
|
||||
unsortedCache: make(map[string]struct{}),
|
||||
sortedCache: internal.NewBTree(),
|
||||
sortedCache: btree.NewBTree[V](),
|
||||
parent: parent,
|
||||
isZero: isZero,
|
||||
valueLen: valueLen,
|
||||
}
|
||||
}
|
||||
|
||||
// GetStoreType implements Store.
|
||||
func (store *Store) GetStoreType() types.StoreType {
|
||||
func (store *GStore[V]) GetStoreType() types.StoreType {
|
||||
return store.parent.GetStoreType()
|
||||
}
|
||||
|
||||
// Get implements types.KVStore.
|
||||
func (store *Store) Get(key []byte) (value []byte) {
|
||||
func (store *GStore[V]) Get(key []byte) (value V) {
|
||||
store.mtx.Lock()
|
||||
defer store.mtx.Unlock()
|
||||
|
||||
@ -68,9 +91,9 @@ func (store *Store) Get(key []byte) (value []byte) {
|
||||
}
|
||||
|
||||
// Set implements types.KVStore.
|
||||
func (store *Store) Set(key, value []byte) {
|
||||
func (store *GStore[V]) Set(key []byte, value V) {
|
||||
types.AssertValidKey(key)
|
||||
types.AssertValidValue(value)
|
||||
types.AssertValidValueGeneric(value, store.isZero, store.valueLen)
|
||||
|
||||
store.mtx.Lock()
|
||||
defer store.mtx.Unlock()
|
||||
@ -78,28 +101,29 @@ func (store *Store) Set(key, value []byte) {
|
||||
}
|
||||
|
||||
// Has implements types.KVStore.
|
||||
func (store *Store) Has(key []byte) bool {
|
||||
func (store *GStore[V]) Has(key []byte) bool {
|
||||
value := store.Get(key)
|
||||
return value != nil
|
||||
return !store.isZero(value)
|
||||
}
|
||||
|
||||
// Delete implements types.KVStore.
|
||||
func (store *Store) Delete(key []byte) {
|
||||
func (store *GStore[V]) Delete(key []byte) {
|
||||
types.AssertValidKey(key)
|
||||
var zeroValue V
|
||||
|
||||
store.mtx.Lock()
|
||||
defer store.mtx.Unlock()
|
||||
|
||||
store.setCacheValue(key, nil, true)
|
||||
store.setCacheValue(key, zeroValue, true)
|
||||
}
|
||||
|
||||
func (store *Store) resetCaches() {
|
||||
func (store *GStore[V]) resetCaches() {
|
||||
if len(store.cache) > 100_000 {
|
||||
// Cache is too large. We likely did something linear time
|
||||
// (e.g. Epoch block, Genesis block, etc). Free the old caches from memory, and let them get re-allocated.
|
||||
// TODO: In a future CacheKV redesign, such linear workloads should get into a different cache instantiation.
|
||||
// 100_000 is arbitrarily chosen as it solved Osmosis' InitGenesis RAM problem.
|
||||
store.cache = make(map[string]*cValue)
|
||||
store.cache = make(map[string]*cValue[V])
|
||||
store.unsortedCache = make(map[string]struct{})
|
||||
} else {
|
||||
// Clear the cache using the map clearing idiom
|
||||
@ -112,22 +136,22 @@ func (store *Store) resetCaches() {
|
||||
delete(store.unsortedCache, key)
|
||||
}
|
||||
}
|
||||
store.sortedCache = internal.NewBTree()
|
||||
store.sortedCache = btree.NewBTree[V]()
|
||||
}
|
||||
|
||||
// Write implements Cachetypes.KVStore.
|
||||
func (store *Store) Write() {
|
||||
func (store *GStore[V]) Write() {
|
||||
store.mtx.Lock()
|
||||
defer store.mtx.Unlock()
|
||||
|
||||
if len(store.cache) == 0 && len(store.unsortedCache) == 0 {
|
||||
store.sortedCache = internal.NewBTree()
|
||||
store.sortedCache = btree.NewBTree[V]()
|
||||
return
|
||||
}
|
||||
|
||||
type cEntry struct {
|
||||
key string
|
||||
val *cValue
|
||||
val *cValue[V]
|
||||
}
|
||||
|
||||
// We need a copy of all of the keys.
|
||||
@ -152,7 +176,7 @@ func (store *Store) Write() {
|
||||
// be sure if the underlying store might do a save with the byteslice or
|
||||
// not. Once we get confirmation that .Delete is guaranteed not to
|
||||
// save the byteslice, then we can assume only a read-only copy is sufficient.
|
||||
if obj.val.value != nil {
|
||||
if !store.isZero(obj.val.value) {
|
||||
// It already exists in the parent, hence update it.
|
||||
store.parent.Set([]byte(obj.key), obj.val.value)
|
||||
} else {
|
||||
@ -162,29 +186,33 @@ func (store *Store) Write() {
|
||||
}
|
||||
|
||||
// CacheWrap implements CacheWrapper.
|
||||
func (store *Store) CacheWrap() types.CacheWrap {
|
||||
return NewStore(store)
|
||||
func (store *GStore[V]) CacheWrap() types.CacheWrap {
|
||||
return NewGStore(store, store.isZero, store.valueLen)
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace implements the CacheWrapper interface.
|
||||
func (store *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||||
return NewStore(tracekv.NewStore(store, w, tc))
|
||||
func (store *GStore[V]) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||||
// We need to make a type assertion here as the tracekv store requires bytes value types for serialization.
|
||||
if store, ok := any(store).(*GStore[[]byte]); ok {
|
||||
return NewStore(tracekv.NewStore(store, w, tc))
|
||||
}
|
||||
return store.CacheWrap()
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Iteration
|
||||
|
||||
// Iterator implements types.KVStore.
|
||||
func (store *Store) Iterator(start, end []byte) types.Iterator {
|
||||
func (store *GStore[V]) Iterator(start, end []byte) types.GIterator[V] {
|
||||
return store.iterator(start, end, true)
|
||||
}
|
||||
|
||||
// ReverseIterator implements types.KVStore.
|
||||
func (store *Store) ReverseIterator(start, end []byte) types.Iterator {
|
||||
func (store *GStore[V]) ReverseIterator(start, end []byte) types.GIterator[V] {
|
||||
return store.iterator(start, end, false)
|
||||
}
|
||||
|
||||
func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator {
|
||||
func (store *GStore[V]) iterator(start, end []byte, ascending bool) types.GIterator[V] {
|
||||
store.mtx.Lock()
|
||||
defer store.mtx.Unlock()
|
||||
|
||||
@ -193,7 +221,7 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator {
|
||||
|
||||
var (
|
||||
err error
|
||||
parent, cache types.Iterator
|
||||
parent, cache types.GIterator[V]
|
||||
)
|
||||
|
||||
if ascending {
|
||||
@ -207,7 +235,7 @@ func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return internal.NewCacheMergeIterator(parent, cache, ascending)
|
||||
return internal.NewCacheMergeIterator(parent, cache, ascending, store.isZero)
|
||||
}
|
||||
|
||||
func findStartIndex(strL []string, startQ string) int {
|
||||
@ -293,7 +321,7 @@ const (
|
||||
const minSortSize = 1024
|
||||
|
||||
// dirtyItems constructs a slice of dirty items, to use w/ memIterator.
|
||||
func (store *Store) dirtyItems(start, end []byte) {
|
||||
func (store *GStore[V]) dirtyItems(start, end []byte) {
|
||||
startStr, endStr := conv.UnsafeBytesToStr(start), conv.UnsafeBytesToStr(end)
|
||||
if end != nil && startStr > endStr {
|
||||
// Nothing to do here.
|
||||
@ -301,7 +329,7 @@ func (store *Store) dirtyItems(start, end []byte) {
|
||||
}
|
||||
|
||||
n := len(store.unsortedCache)
|
||||
unsorted := make([]*kv.Pair, 0)
|
||||
unsorted := make([]*kvPair[V], 0)
|
||||
// If the unsortedCache is too big, its costs too much to determine
|
||||
// what's in the subset we are concerned about.
|
||||
// If you are interleaving iterator calls with writes, this can easily become an
|
||||
@ -313,7 +341,7 @@ func (store *Store) dirtyItems(start, end []byte) {
|
||||
// dbm.IsKeyInDomain is nil safe and returns true iff key is greater than start
|
||||
if dbm.IsKeyInDomain(conv.UnsafeStrToBytes(key), start, end) {
|
||||
cacheValue := store.cache[key]
|
||||
unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.value})
|
||||
unsorted = append(unsorted, &kvPair[V]{Key: []byte(key), Value: cacheValue.value})
|
||||
}
|
||||
}
|
||||
store.clearUnsortedCacheSubset(unsorted, stateUnsorted)
|
||||
@ -356,18 +384,18 @@ func (store *Store) dirtyItems(start, end []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
kvL := make([]*kv.Pair, 0, 1+endIndex-startIndex)
|
||||
kvL := make([]*kvPair[V], 0, 1+endIndex-startIndex)
|
||||
for i := startIndex; i <= endIndex; i++ {
|
||||
key := strL[i]
|
||||
cacheValue := store.cache[key]
|
||||
kvL = append(kvL, &kv.Pair{Key: []byte(key), Value: cacheValue.value})
|
||||
kvL = append(kvL, &kvPair[V]{Key: []byte(key), Value: cacheValue.value})
|
||||
}
|
||||
|
||||
// kvL was already sorted so pass it in as is.
|
||||
store.clearUnsortedCacheSubset(kvL, stateAlreadySorted)
|
||||
}
|
||||
|
||||
func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sortState) {
|
||||
func (store *GStore[V]) clearUnsortedCacheSubset(unsorted []*kvPair[V], sortState sortState) {
|
||||
n := len(store.unsortedCache)
|
||||
if len(unsorted) == n { // This pattern allows the Go compiler to emit the map clearing idiom for the entire map.
|
||||
for key := range store.unsortedCache {
|
||||
@ -396,9 +424,9 @@ func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sort
|
||||
|
||||
// setCacheValue is the only entrypoint to mutate store.cache.
|
||||
// A `nil` value means a deletion.
|
||||
func (store *Store) setCacheValue(key, value []byte, dirty bool) {
|
||||
func (store *GStore[V]) setCacheValue(key []byte, value V, dirty bool) {
|
||||
keyStr := conv.UnsafeBytesToStr(key)
|
||||
store.cache[keyStr] = &cValue{
|
||||
store.cache[keyStr] = &cValue[V]{
|
||||
value: value,
|
||||
dirty: dirty,
|
||||
}
|
||||
|
||||
@ -5,10 +5,6 @@ import (
|
||||
"io"
|
||||
"maps"
|
||||
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
"cosmossdk.io/store/cachekv"
|
||||
"cosmossdk.io/store/dbadapter"
|
||||
"cosmossdk.io/store/tracekv"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
@ -25,12 +21,11 @@ const storeNameCtxKey = "store_name"
|
||||
// NOTE: a Store (and MultiStores in general) should never expose the
|
||||
// keys for the substores.
|
||||
type Store struct {
|
||||
db types.CacheKVStore
|
||||
stores map[types.StoreKey]types.CacheWrap
|
||||
keys map[string]types.StoreKey
|
||||
|
||||
traceWriter io.Writer
|
||||
traceContext types.TraceContext
|
||||
parentStore func(types.StoreKey) types.CacheWrapper
|
||||
}
|
||||
|
||||
var _ types.CacheMultiStore = Store{}
|
||||
@ -39,26 +34,17 @@ var _ types.CacheMultiStore = Store{}
|
||||
// CacheWrapper objects and a KVStore as the database. Each CacheWrapper store
|
||||
// is a branched store.
|
||||
func NewFromKVStore(
|
||||
store types.KVStore, stores map[types.StoreKey]types.CacheWrapper,
|
||||
keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext,
|
||||
stores map[types.StoreKey]types.CacheWrapper,
|
||||
traceWriter io.Writer, traceContext types.TraceContext,
|
||||
) Store {
|
||||
cms := Store{
|
||||
db: cachekv.NewStore(store),
|
||||
stores: make(map[types.StoreKey]types.CacheWrap, len(stores)),
|
||||
keys: keys,
|
||||
traceWriter: traceWriter,
|
||||
traceContext: traceContext,
|
||||
}
|
||||
|
||||
for key, store := range stores {
|
||||
if cms.TracingEnabled() {
|
||||
tctx := cms.traceContext.Clone().Merge(types.TraceContext{
|
||||
storeNameCtxKey: key.Name(),
|
||||
})
|
||||
|
||||
store = tracekv.NewStore(store.(types.KVStore), cms.traceWriter, tctx)
|
||||
}
|
||||
cms.stores[key] = cachekv.NewStore(store.(types.KVStore))
|
||||
cms.initStore(key, store)
|
||||
}
|
||||
|
||||
return cms
|
||||
@ -67,19 +53,39 @@ func NewFromKVStore(
|
||||
// NewStore creates a new Store object from a mapping of store keys to
|
||||
// CacheWrapper objects. Each CacheWrapper store is a branched store.
|
||||
func NewStore(
|
||||
db dbm.DB, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey,
|
||||
stores map[types.StoreKey]types.CacheWrapper,
|
||||
traceWriter io.Writer, traceContext types.TraceContext,
|
||||
) Store {
|
||||
return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext)
|
||||
return NewFromKVStore(stores, traceWriter, traceContext)
|
||||
}
|
||||
|
||||
func newCacheMultiStoreFromCMS(cms Store) Store {
|
||||
stores := make(map[types.StoreKey]types.CacheWrapper)
|
||||
for k, v := range cms.stores {
|
||||
stores[k] = v
|
||||
// NewFromParent constructs a cache multistore with a parent store lazily,
|
||||
// the parent is usually another cache multistore or the block-stm multiversion store.
|
||||
func NewFromParent(
|
||||
parentStore func(types.StoreKey) types.CacheWrapper,
|
||||
traceWriter io.Writer, traceContext types.TraceContext,
|
||||
) Store {
|
||||
return Store{
|
||||
stores: make(map[types.StoreKey]types.CacheWrap),
|
||||
traceWriter: traceWriter,
|
||||
traceContext: traceContext,
|
||||
parentStore: parentStore,
|
||||
}
|
||||
}
|
||||
|
||||
return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext)
|
||||
func (cms Store) initStore(key types.StoreKey, store types.CacheWrapper) types.CacheWrap {
|
||||
if cms.TracingEnabled() {
|
||||
// only support tracing on KVStore.
|
||||
if kvstore, ok := store.(types.KVStore); ok {
|
||||
tctx := cms.traceContext.Clone().Merge(types.TraceContext{
|
||||
storeNameCtxKey: key.Name(),
|
||||
})
|
||||
store = tracekv.NewStore(kvstore, cms.traceWriter, tctx)
|
||||
}
|
||||
}
|
||||
cache := store.CacheWrap()
|
||||
cms.stores[key] = cache
|
||||
return cache
|
||||
}
|
||||
|
||||
// SetTracer sets the tracer for the MultiStore that the underlying
|
||||
@ -120,7 +126,6 @@ func (cms Store) GetStoreType() types.StoreType {
|
||||
|
||||
// Write calls Write on each underlying store.
|
||||
func (cms Store) Write() {
|
||||
cms.db.Write()
|
||||
for _, store := range cms.stores {
|
||||
store.Write()
|
||||
}
|
||||
@ -139,7 +144,7 @@ func (cms Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac
|
||||
// CacheMultiStore implements MultiStore, returns a new CacheMultiStore from the
|
||||
// underlying CacheMultiStore.
|
||||
func (cms Store) CacheMultiStore() types.CacheMultiStore {
|
||||
return newCacheMultiStoreFromCMS(cms)
|
||||
return NewFromParent(cms.getCacheWrapper, cms.traceWriter, cms.traceContext)
|
||||
}
|
||||
|
||||
// CacheMultiStoreWithVersion implements the MultiStore interface. It will panic
|
||||
@ -151,20 +156,41 @@ func (cms Store) CacheMultiStoreWithVersion(_ int64) (types.CacheMultiStore, err
|
||||
panic("cannot branch cached multi-store with a version")
|
||||
}
|
||||
|
||||
// GetStore returns an underlying Store by key.
|
||||
func (cms Store) GetStore(key types.StoreKey) types.Store {
|
||||
s := cms.stores[key]
|
||||
if key == nil || s == nil {
|
||||
func (cms Store) getCacheWrapper(key types.StoreKey) types.CacheWrapper {
|
||||
store, ok := cms.stores[key]
|
||||
if !ok && cms.parentStore != nil {
|
||||
// load on demand
|
||||
store = cms.initStore(key, cms.parentStore(key))
|
||||
}
|
||||
if key == nil || store == nil {
|
||||
panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key))
|
||||
}
|
||||
return s.(types.Store)
|
||||
return store
|
||||
}
|
||||
|
||||
// GetStore returns an underlying Store by key.
|
||||
func (cms Store) GetStore(key types.StoreKey) types.Store {
|
||||
store, ok := cms.getCacheWrapper(key).(types.Store)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not Store", key))
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
// GetKVStore returns an underlying KVStore by key.
|
||||
func (cms Store) GetKVStore(key types.StoreKey) types.KVStore {
|
||||
store := cms.stores[key]
|
||||
if key == nil || store == nil {
|
||||
panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key))
|
||||
store, ok := cms.getCacheWrapper(key).(types.KVStore)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not KVStore", key))
|
||||
}
|
||||
return store.(types.KVStore)
|
||||
return store
|
||||
}
|
||||
|
||||
// GetObjKVStore returns an underlying KVStore by key.
|
||||
func (cms Store) GetObjKVStore(key types.StoreKey) types.ObjKVStore {
|
||||
store, ok := cms.getCacheWrapper(key).(types.ObjKVStore)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not ObjKVStore", key))
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
@ -8,61 +8,90 @@ import (
|
||||
|
||||
var _ types.KVStore = &Store{}
|
||||
|
||||
// Store applies gas tracking to an underlying KVStore. It implements the
|
||||
// KVStore interface.
|
||||
type Store struct {
|
||||
gasMeter types.GasMeter
|
||||
gasConfig types.GasConfig
|
||||
parent types.KVStore
|
||||
type Store = GStore[[]byte]
|
||||
|
||||
func NewStore(parent types.KVStore, gasMeter types.GasMeter, gasConfig types.GasConfig) *Store {
|
||||
return NewGStore(parent, gasMeter, gasConfig,
|
||||
types.BytesIsZero,
|
||||
types.BytesValueLen,
|
||||
)
|
||||
}
|
||||
|
||||
// NewStore returns a reference to a new GasKVStore.
|
||||
func NewStore(parent types.KVStore, gasMeter types.GasMeter, gasConfig types.GasConfig) *Store {
|
||||
kvs := &Store{
|
||||
type ObjStore = GStore[any]
|
||||
|
||||
func NewObjStore(parent types.ObjKVStore, gasMeter types.GasMeter, gasConfig types.GasConfig) *ObjStore {
|
||||
return NewGStore(parent, gasMeter, gasConfig,
|
||||
types.AnyIsZero,
|
||||
types.AnyValueLen,
|
||||
)
|
||||
}
|
||||
|
||||
// GStore applies gas tracking to an underlying KVStore. It implements the
|
||||
// KVStore interface.
|
||||
type GStore[V any] struct {
|
||||
gasMeter types.GasMeter
|
||||
gasConfig types.GasConfig
|
||||
parent types.GKVStore[V]
|
||||
|
||||
isZero func(V) bool
|
||||
valueLen func(V) int
|
||||
}
|
||||
|
||||
// NewGStore returns a reference to a new GasKVStore.
|
||||
func NewGStore[V any](
|
||||
parent types.GKVStore[V],
|
||||
gasMeter types.GasMeter,
|
||||
gasConfig types.GasConfig,
|
||||
isZero func(V) bool,
|
||||
valueLen func(V) int,
|
||||
) *GStore[V] {
|
||||
kvs := &GStore[V]{
|
||||
gasMeter: gasMeter,
|
||||
gasConfig: gasConfig,
|
||||
parent: parent,
|
||||
isZero: isZero,
|
||||
valueLen: valueLen,
|
||||
}
|
||||
return kvs
|
||||
}
|
||||
|
||||
// GetStoreType implements Store, consuming no gas and returning the underlying
|
||||
// store's type.
|
||||
func (gs *Store) GetStoreType() types.StoreType {
|
||||
func (gs *GStore[V]) GetStoreType() types.StoreType {
|
||||
return gs.parent.GetStoreType()
|
||||
}
|
||||
|
||||
// Get implements KVStore, consuming gas based on ReadCostFlat and the read per bytes cost.
|
||||
func (gs *Store) Get(key []byte) (value []byte) {
|
||||
func (gs *GStore[V]) Get(key []byte) (value V) {
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostFlat, types.GasReadCostFlatDesc)
|
||||
value = gs.parent.Get(key)
|
||||
|
||||
// TODO overflow-safe math?
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasReadPerByteDesc)
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasReadPerByteDesc)
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.ReadCostPerByte*types.Gas(gs.valueLen(value)), types.GasReadPerByteDesc)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// Set implements KVStore, consuming gas based on WriteCostFlat and the write per bytes cost.
|
||||
func (gs *Store) Set(key, value []byte) {
|
||||
func (gs *GStore[V]) Set(key []byte, value V) {
|
||||
types.AssertValidKey(key)
|
||||
types.AssertValidValue(value)
|
||||
types.AssertValidValueGeneric(value, gs.isZero, gs.valueLen)
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostFlat, types.GasWriteCostFlatDesc)
|
||||
// TODO overflow-safe math?
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(key)), types.GasWritePerByteDesc)
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(len(value)), types.GasWritePerByteDesc)
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.WriteCostPerByte*types.Gas(gs.valueLen(value)), types.GasWritePerByteDesc)
|
||||
gs.parent.Set(key, value)
|
||||
}
|
||||
|
||||
// Has implements KVStore, consuming gas based on HasCost.
|
||||
func (gs *Store) Has(key []byte) bool {
|
||||
func (gs *GStore[V]) Has(key []byte) bool {
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.HasCost, types.GasHasDesc)
|
||||
return gs.parent.Has(key)
|
||||
}
|
||||
|
||||
// Delete implements KVStore consuming gas based on DeleteCost.
|
||||
func (gs *Store) Delete(key []byte) {
|
||||
func (gs *GStore[V]) Delete(key []byte) {
|
||||
// charge gas to prevent certain attack vectors even though space is being freed
|
||||
gs.gasMeter.ConsumeGas(gs.gasConfig.DeleteCost, types.GasDeleteDesc)
|
||||
gs.parent.Delete(key)
|
||||
@ -71,7 +100,7 @@ func (gs *Store) Delete(key []byte) {
|
||||
// Iterator implements the KVStore interface. It returns an iterator which
|
||||
// incurs a flat gas cost for seeking to the first key/value pair and a variable
|
||||
// gas cost based on the current value's length if the iterator is valid.
|
||||
func (gs *Store) Iterator(start, end []byte) types.Iterator {
|
||||
func (gs *GStore[V]) Iterator(start, end []byte) types.GIterator[V] {
|
||||
return gs.iterator(start, end, true)
|
||||
}
|
||||
|
||||
@ -79,99 +108,100 @@ func (gs *Store) Iterator(start, end []byte) types.Iterator {
|
||||
// iterator which incurs a flat gas cost for seeking to the first key/value pair
|
||||
// and a variable gas cost based on the current value's length if the iterator
|
||||
// is valid.
|
||||
func (gs *Store) ReverseIterator(start, end []byte) types.Iterator {
|
||||
func (gs *GStore[V]) ReverseIterator(start, end []byte) types.GIterator[V] {
|
||||
return gs.iterator(start, end, false)
|
||||
}
|
||||
|
||||
// CacheWrap implements KVStore - it PANICS as you cannot cache a GasKVStore.
|
||||
func (gs *Store) CacheWrap() types.CacheWrap {
|
||||
func (gs *GStore[V]) CacheWrap() types.CacheWrap {
|
||||
panic("cannot CacheWrap a GasKVStore")
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace implements the KVStore interface.
|
||||
func (gs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap {
|
||||
func (gs *GStore[V]) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap {
|
||||
panic("cannot CacheWrapWithTrace a GasKVStore")
|
||||
}
|
||||
|
||||
func (gs *Store) iterator(start, end []byte, ascending bool) types.Iterator {
|
||||
var parent types.Iterator
|
||||
func (gs *GStore[V]) iterator(start, end []byte, ascending bool) types.GIterator[V] {
|
||||
var parent types.GIterator[V]
|
||||
if ascending {
|
||||
parent = gs.parent.Iterator(start, end)
|
||||
} else {
|
||||
parent = gs.parent.ReverseIterator(start, end)
|
||||
}
|
||||
|
||||
gi := newGasIterator(gs.gasMeter, gs.gasConfig, parent)
|
||||
gi.(*gasIterator).consumeSeekGas()
|
||||
gi := newGasIterator(gs.gasMeter, gs.gasConfig, parent, gs.valueLen)
|
||||
gi.consumeSeekGas()
|
||||
|
||||
return gi
|
||||
}
|
||||
|
||||
type gasIterator struct {
|
||||
type gasIterator[V any] struct {
|
||||
gasMeter types.GasMeter
|
||||
gasConfig types.GasConfig
|
||||
parent types.Iterator
|
||||
parent types.GIterator[V]
|
||||
valueLen func(V) int
|
||||
}
|
||||
|
||||
func newGasIterator(gasMeter types.GasMeter, gasConfig types.GasConfig, parent types.Iterator) types.Iterator {
|
||||
return &gasIterator{
|
||||
func newGasIterator[V any](gasMeter types.GasMeter, gasConfig types.GasConfig, parent types.GIterator[V], valueLen func(V) int) *gasIterator[V] {
|
||||
return &gasIterator[V]{
|
||||
gasMeter: gasMeter,
|
||||
gasConfig: gasConfig,
|
||||
parent: parent,
|
||||
valueLen: valueLen,
|
||||
}
|
||||
}
|
||||
|
||||
// Domain implements Iterator, getting the underlying iterator's domain.
|
||||
func (gi *gasIterator) Domain() (start, end []byte) {
|
||||
func (gi *gasIterator[V]) Domain() (start, end []byte) {
|
||||
return gi.parent.Domain()
|
||||
}
|
||||
|
||||
// Valid implements Iterator by checking the underlying iterator.
|
||||
func (gi *gasIterator) Valid() bool {
|
||||
func (gi *gasIterator[V]) Valid() bool {
|
||||
return gi.parent.Valid()
|
||||
}
|
||||
|
||||
// Next implements the Iterator interface. It seeks to the next key/value pair
|
||||
// in the iterator. It incurs a flat gas cost for seeking and a variable gas
|
||||
// cost based on the current value's length if the iterator is valid.
|
||||
func (gi *gasIterator) Next() {
|
||||
func (gi *gasIterator[V]) Next() {
|
||||
gi.consumeSeekGas()
|
||||
gi.parent.Next()
|
||||
}
|
||||
|
||||
// Key implements the Iterator interface. It returns the current key and it does
|
||||
// not incur any gas cost.
|
||||
func (gi *gasIterator) Key() (key []byte) {
|
||||
func (gi *gasIterator[V]) Key() (key []byte) {
|
||||
key = gi.parent.Key()
|
||||
return key
|
||||
}
|
||||
|
||||
// Value implements the Iterator interface. It returns the current value and it
|
||||
// does not incur any gas cost.
|
||||
func (gi *gasIterator) Value() (value []byte) {
|
||||
value = gi.parent.Value()
|
||||
return value
|
||||
func (gi *gasIterator[V]) Value() (value V) {
|
||||
return gi.parent.Value()
|
||||
}
|
||||
|
||||
// Close implements Iterator by closing the underlying iterator.
|
||||
func (gi *gasIterator) Close() error {
|
||||
func (gi *gasIterator[V]) Close() error {
|
||||
return gi.parent.Close()
|
||||
}
|
||||
|
||||
// Error delegates the Error call to the parent iterator.
|
||||
func (gi *gasIterator) Error() error {
|
||||
func (gi *gasIterator[V]) Error() error {
|
||||
return gi.parent.Error()
|
||||
}
|
||||
|
||||
// consumeSeekGas consumes on each iteration step a flat gas cost and a variable gas cost
|
||||
// based on the current value's length.
|
||||
func (gi *gasIterator) consumeSeekGas() {
|
||||
func (gi *gasIterator[V]) consumeSeekGas() {
|
||||
if gi.Valid() {
|
||||
key := gi.Key()
|
||||
value := gi.Value()
|
||||
|
||||
gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(key)), types.GasValuePerByteDesc)
|
||||
gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(len(value)), types.GasValuePerByteDesc)
|
||||
gi.gasMeter.ConsumeGas(gi.gasConfig.ReadCostPerByte*types.Gas(gi.valueLen(value)), types.GasValuePerByteDesc)
|
||||
}
|
||||
gi.gasMeter.ConsumeGas(gi.gasConfig.IterNextCostFlat, types.GasIterNextCostFlatDesc)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package btree
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -22,44 +22,46 @@ var errKeyEmpty = errors.New("key cannot be empty")
|
||||
// we need it to be as fast as possible, while `MemDB` is mainly used as a mocking db in unit tests.
|
||||
//
|
||||
// We choose tidwall/btree over google/btree here because it provides API to implement step iterator directly.
|
||||
type BTree struct {
|
||||
tree *btree.BTreeG[item]
|
||||
type BTree[V any] struct {
|
||||
tree *btree.BTreeG[item[V]]
|
||||
}
|
||||
|
||||
// NewBTree creates a wrapper around `btree.BTreeG`.
|
||||
func NewBTree() BTree {
|
||||
return BTree{
|
||||
tree: btree.NewBTreeGOptions(byKeys, btree.Options{
|
||||
func NewBTree[V any]() BTree[V] {
|
||||
return BTree[V]{
|
||||
tree: btree.NewBTreeGOptions(byKeys[V], btree.Options{
|
||||
Degree: bTreeDegree,
|
||||
NoLocks: false,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
func (bt BTree) Set(key, value []byte) {
|
||||
func (bt BTree[V]) Set(key []byte, value V) {
|
||||
bt.tree.Set(newItem(key, value))
|
||||
}
|
||||
|
||||
func (bt BTree) Get(key []byte) []byte {
|
||||
i, found := bt.tree.Get(newItem(key, nil))
|
||||
func (bt BTree[V]) Get(key []byte) V {
|
||||
var empty V
|
||||
i, found := bt.tree.Get(newItem(key, empty))
|
||||
if !found {
|
||||
return nil
|
||||
return empty
|
||||
}
|
||||
return i.value
|
||||
}
|
||||
|
||||
func (bt BTree) Delete(key []byte) {
|
||||
bt.tree.Delete(newItem(key, nil))
|
||||
func (bt BTree[V]) Delete(key []byte) {
|
||||
var empty V
|
||||
bt.tree.Delete(newItem(key, empty))
|
||||
}
|
||||
|
||||
func (bt BTree) Iterator(start, end []byte) (types.Iterator, error) {
|
||||
func (bt BTree[V]) Iterator(start, end []byte) (types.GIterator[V], error) {
|
||||
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
|
||||
return nil, errKeyEmpty
|
||||
}
|
||||
return newMemIterator(start, end, bt, true), nil
|
||||
}
|
||||
|
||||
func (bt BTree) ReverseIterator(start, end []byte) (types.Iterator, error) {
|
||||
func (bt BTree[V]) ReverseIterator(start, end []byte) (types.GIterator[V], error) {
|
||||
if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) {
|
||||
return nil, errKeyEmpty
|
||||
}
|
||||
@ -68,24 +70,28 @@ func (bt BTree) ReverseIterator(start, end []byte) (types.Iterator, error) {
|
||||
|
||||
// Copy the tree. This is a copy-on-write operation and is very fast because
|
||||
// it only performs a shadowed copy.
|
||||
func (bt BTree) Copy() BTree {
|
||||
return BTree{
|
||||
func (bt BTree[V]) Copy() BTree[V] {
|
||||
return BTree[V]{
|
||||
tree: bt.tree.Copy(),
|
||||
}
|
||||
}
|
||||
|
||||
func (bt BTree[V]) Clear() {
|
||||
bt.tree.Clear()
|
||||
}
|
||||
|
||||
// item is a btree item with byte slices as keys and values
|
||||
type item struct {
|
||||
type item[V any] struct {
|
||||
key []byte
|
||||
value []byte
|
||||
value V
|
||||
}
|
||||
|
||||
// byKeys compares the items by key
|
||||
func byKeys(a, b item) bool {
|
||||
func byKeys[V any](a, b item[V]) bool {
|
||||
return bytes.Compare(a.key, b.key) == -1
|
||||
}
|
||||
|
||||
// newItem creates a new pair item.
|
||||
func newItem(key, value []byte) item {
|
||||
return item{key: key, value: value}
|
||||
func newItem[V any](key []byte, value V) item[V] {
|
||||
return item[V]{key: key, value: value}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package btree
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestGetSetDelete(t *testing.T) {
|
||||
db := NewBTree()
|
||||
db := NewBTree[[]byte]()
|
||||
|
||||
// A nonexistent key should return nil.
|
||||
value := db.Get([]byte("a"))
|
||||
@ -40,7 +40,7 @@ func TestGetSetDelete(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDBIterator(t *testing.T) {
|
||||
db := NewBTree()
|
||||
db := NewBTree[[]byte]()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
if i != 6 { // but skip 6.
|
||||
@ -171,7 +171,7 @@ func TestDBIterator(t *testing.T) {
|
||||
[]int64(nil), "reverse iterator from 2 (ex) to 4")
|
||||
|
||||
// Ensure that the iterators don't panic with an empty database.
|
||||
db2 := NewBTree()
|
||||
db2 := NewBTree[[]byte]()
|
||||
|
||||
itr, err = db2.Iterator(nil, nil)
|
||||
require.NoError(t, err)
|
||||
@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package btree
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@ -9,13 +9,13 @@ import (
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
var _ types.Iterator = (*memIterator)(nil)
|
||||
var _ types.Iterator = (*memIterator[[]byte])(nil)
|
||||
|
||||
// memIterator iterates over iterKVCache items.
|
||||
// if value is nil, means it was deleted.
|
||||
// Implements Iterator.
|
||||
type memIterator struct {
|
||||
iter btree.IterG[item]
|
||||
type memIterator[V any] struct {
|
||||
iter btree.IterG[item[V]]
|
||||
|
||||
start []byte
|
||||
end []byte
|
||||
@ -23,18 +23,21 @@ type memIterator struct {
|
||||
valid bool
|
||||
}
|
||||
|
||||
func newMemIterator(start, end []byte, items BTree, ascending bool) *memIterator {
|
||||
func newMemIterator[V any](start, end []byte, items BTree[V], ascending bool) *memIterator[V] {
|
||||
var (
|
||||
valid bool
|
||||
empty V
|
||||
)
|
||||
iter := items.tree.Iter()
|
||||
var valid bool
|
||||
if ascending {
|
||||
if start != nil {
|
||||
valid = iter.Seek(newItem(start, nil))
|
||||
valid = iter.Seek(newItem(start, empty))
|
||||
} else {
|
||||
valid = iter.First()
|
||||
}
|
||||
} else {
|
||||
if end != nil {
|
||||
valid = iter.Seek(newItem(end, nil))
|
||||
valid = iter.Seek(newItem(end, empty))
|
||||
if !valid {
|
||||
valid = iter.Last()
|
||||
} else {
|
||||
@ -46,7 +49,7 @@ func newMemIterator(start, end []byte, items BTree, ascending bool) *memIterator
|
||||
}
|
||||
}
|
||||
|
||||
mi := &memIterator{
|
||||
mi := &memIterator[V]{
|
||||
iter: iter,
|
||||
start: start,
|
||||
end: end,
|
||||
@ -61,27 +64,27 @@ func newMemIterator(start, end []byte, items BTree, ascending bool) *memIterator
|
||||
return mi
|
||||
}
|
||||
|
||||
func (mi *memIterator) Domain() (start, end []byte) {
|
||||
func (mi *memIterator[V]) Domain() (start, end []byte) {
|
||||
return mi.start, mi.end
|
||||
}
|
||||
|
||||
func (mi *memIterator) Close() error {
|
||||
func (mi *memIterator[V]) Close() error {
|
||||
mi.iter.Release()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mi *memIterator) Error() error {
|
||||
func (mi *memIterator[V]) Error() error {
|
||||
if !mi.Valid() {
|
||||
return errors.New("invalid memIterator")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mi *memIterator) Valid() bool {
|
||||
func (mi *memIterator[V]) Valid() bool {
|
||||
return mi.valid
|
||||
}
|
||||
|
||||
func (mi *memIterator) Next() {
|
||||
func (mi *memIterator[V]) Next() {
|
||||
mi.assertValid()
|
||||
|
||||
if mi.ascending {
|
||||
@ -95,7 +98,7 @@ func (mi *memIterator) Next() {
|
||||
}
|
||||
}
|
||||
|
||||
func (mi *memIterator) keyInRange(key []byte) bool {
|
||||
func (mi *memIterator[V]) keyInRange(key []byte) bool {
|
||||
if mi.ascending && mi.end != nil && bytes.Compare(key, mi.end) >= 0 {
|
||||
return false
|
||||
}
|
||||
@ -105,15 +108,15 @@ func (mi *memIterator) keyInRange(key []byte) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (mi *memIterator) Key() []byte {
|
||||
func (mi *memIterator[V]) Key() []byte {
|
||||
return mi.iter.Item().key
|
||||
}
|
||||
|
||||
func (mi *memIterator) Value() []byte {
|
||||
func (mi *memIterator[V]) Value() V {
|
||||
return mi.iter.Item().value
|
||||
}
|
||||
|
||||
func (mi *memIterator) assertValid() {
|
||||
func (mi *memIterator[V]) assertValid() {
|
||||
if err := mi.Error(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
59
store/internal/btreeadaptor.go
Normal file
59
store/internal/btreeadaptor.go
Normal file
@ -0,0 +1,59 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"cosmossdk.io/store/cachekv"
|
||||
"cosmossdk.io/store/internal/btree"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
var _ types.KVStore = (*BTreeStore[[]byte])(nil)
|
||||
|
||||
// BTreeStore is a wrapper for a BTree with GKVStore[V] implementation
|
||||
type BTreeStore[V any] struct {
|
||||
btree.BTree[V]
|
||||
isZero func(V) bool
|
||||
valueLen func(V) int
|
||||
}
|
||||
|
||||
// NewBTreeStore constructs new BTree adapter
|
||||
func NewBTreeStore[V any](btree btree.BTree[V], isZero func(V) bool, valueLen func(V) int) *BTreeStore[V] {
|
||||
return &BTreeStore[V]{btree, isZero, valueLen}
|
||||
}
|
||||
|
||||
// Has Implements GKVStore.
|
||||
func (ts *BTreeStore[V]) Has(key []byte) bool {
|
||||
return !ts.isZero(ts.Get(key))
|
||||
}
|
||||
|
||||
func (ts *BTreeStore[V]) Iterator(start, end []byte) types.GIterator[V] {
|
||||
it, err := ts.BTree.Iterator(start, end)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
func (ts *BTreeStore[V]) ReverseIterator(start, end []byte) types.GIterator[V] {
|
||||
it, err := ts.BTree.ReverseIterator(start, end)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return it
|
||||
}
|
||||
|
||||
// GetStoreType returns the type of the store.
|
||||
func (ts *BTreeStore[V]) GetStoreType() types.StoreType {
|
||||
return types.StoreTypeDB
|
||||
}
|
||||
|
||||
// CacheWrap branches the underlying store.
|
||||
func (ts *BTreeStore[V]) CacheWrap() types.CacheWrap {
|
||||
return cachekv.NewGStore(ts, ts.isZero, ts.valueLen)
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace branches the underlying store.
|
||||
func (ts *BTreeStore[V]) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||||
return cachekv.NewGStore(ts, ts.isZero, ts.valueLen)
|
||||
}
|
||||
@ -3,6 +3,7 @@ package listenkv
|
||||
import (
|
||||
"io"
|
||||
|
||||
"cosmossdk.io/store/cachekv"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
@ -129,10 +130,9 @@ func (s *Store) GetStoreType() types.StoreType {
|
||||
return s.parent.GetStoreType()
|
||||
}
|
||||
|
||||
// CacheWrap implements the KVStore interface. It panics as a Store
|
||||
// cannot be cache wrapped.
|
||||
// CacheWrap implements the KVStore interface. It branches the kv store via creating a new cachekv around s.
|
||||
func (s *Store) CacheWrap() types.CacheWrap {
|
||||
panic("cannot CacheWrap a ListenKVStore")
|
||||
return cachekv.NewStore(s)
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace implements the KVStore interface. It panics as a
|
||||
|
||||
@ -272,7 +272,7 @@ func TestListenKVStoreGetStoreType(t *testing.T) {
|
||||
|
||||
func TestListenKVStoreCacheWrap(t *testing.T) {
|
||||
store := newEmptyListenKVStore(nil)
|
||||
require.Panics(t, func() { store.CacheWrap() })
|
||||
store.CacheWrap()
|
||||
}
|
||||
|
||||
func TestListenKVStoreCacheWrapWithTrace(t *testing.T) {
|
||||
|
||||
@ -10,20 +10,53 @@ import (
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
var _ types.KVStore = Store{}
|
||||
type (
|
||||
Store = GStore[[]byte]
|
||||
ObjStore = GStore[any]
|
||||
)
|
||||
|
||||
// Store is similar to cometbft/cometbft/libs/db/prefix_db
|
||||
// both give access only to the limited subset of the store
|
||||
// for convenience or safety
|
||||
type Store struct {
|
||||
parent types.KVStore
|
||||
prefix []byte
|
||||
}
|
||||
var (
|
||||
_ types.KVStore = Store{}
|
||||
_ types.ObjKVStore = ObjStore{}
|
||||
)
|
||||
|
||||
func NewStore(parent types.KVStore, prefix []byte) Store {
|
||||
return Store{
|
||||
return NewGStore(
|
||||
parent, prefix,
|
||||
types.BytesIsZero,
|
||||
types.BytesValueLen,
|
||||
)
|
||||
}
|
||||
|
||||
func NewObjStore(parent types.ObjKVStore, prefix []byte) ObjStore {
|
||||
return NewGStore(
|
||||
parent, prefix,
|
||||
types.AnyIsZero,
|
||||
types.AnyValueLen,
|
||||
)
|
||||
}
|
||||
|
||||
// GStore is similar to cometbft/cometbft/libs/db/prefix_db
|
||||
// both give access only to the limited subset of the store
|
||||
// for convenience or safety
|
||||
type GStore[V any] struct {
|
||||
parent types.GKVStore[V]
|
||||
prefix []byte
|
||||
|
||||
isZero func(V) bool
|
||||
valueLen func(V) int
|
||||
}
|
||||
|
||||
func NewGStore[V any](
|
||||
parent types.GKVStore[V], prefix []byte,
|
||||
isZero func(V) bool, valueLen func(V) int,
|
||||
) GStore[V] {
|
||||
return GStore[V]{
|
||||
parent: parent,
|
||||
prefix: prefix,
|
||||
|
||||
isZero: isZero,
|
||||
valueLen: valueLen,
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +67,7 @@ func cloneAppend(bz, tail []byte) (res []byte) {
|
||||
return res
|
||||
}
|
||||
|
||||
func (s Store) key(key []byte) (res []byte) {
|
||||
func (s GStore[V]) key(key []byte) (res []byte) {
|
||||
if key == nil {
|
||||
panic("nil key on Store")
|
||||
}
|
||||
@ -43,46 +76,50 @@ func (s Store) key(key []byte) (res []byte) {
|
||||
}
|
||||
|
||||
// GetStoreType implements Store, returning the parent store's type
|
||||
func (s Store) GetStoreType() types.StoreType {
|
||||
func (s GStore[V]) GetStoreType() types.StoreType {
|
||||
return s.parent.GetStoreType()
|
||||
}
|
||||
|
||||
// CacheWrap implements CacheWrap, returning a new CacheWrap with the parent store as the underlying store
|
||||
func (s Store) CacheWrap() types.CacheWrap {
|
||||
return cachekv.NewStore(s)
|
||||
func (s GStore[V]) CacheWrap() types.CacheWrap {
|
||||
return cachekv.NewGStore(s, s.isZero, s.valueLen)
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace implements the KVStore interface.
|
||||
func (s Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||||
return cachekv.NewStore(tracekv.NewStore(s, w, tc))
|
||||
func (s GStore[V]) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
|
||||
// We need to make a type assertion here as the tracekv store requires bytes value types for serialization.
|
||||
if store, ok := any(s).(*GStore[[]byte]); ok {
|
||||
return cachekv.NewGStore(tracekv.NewStore(store, w, tc), store.isZero, store.valueLen)
|
||||
}
|
||||
return s.CacheWrap()
|
||||
}
|
||||
|
||||
// Get implements KVStore, calls Get on the parent store with the key prefixed with the prefix
|
||||
func (s Store) Get(key []byte) []byte {
|
||||
func (s GStore[V]) Get(key []byte) V {
|
||||
res := s.parent.Get(s.key(key))
|
||||
return res
|
||||
}
|
||||
|
||||
// Has implements KVStore, calls Has on the parent store with the key prefixed with the prefix
|
||||
func (s Store) Has(key []byte) bool {
|
||||
func (s GStore[V]) Has(key []byte) bool {
|
||||
return s.parent.Has(s.key(key))
|
||||
}
|
||||
|
||||
// Set implements KVStore, calls Set on the parent store with the key prefixed with the prefix
|
||||
func (s Store) Set(key, value []byte) {
|
||||
func (s GStore[V]) Set(key []byte, value V) {
|
||||
types.AssertValidKey(key)
|
||||
types.AssertValidValue(value)
|
||||
types.AssertValidValueGeneric(value, s.isZero, s.valueLen)
|
||||
s.parent.Set(s.key(key), value)
|
||||
}
|
||||
|
||||
// Delete implements KVStore, calls Delete on the parent store with the key prefixed with the prefix
|
||||
func (s Store) Delete(key []byte) {
|
||||
func (s GStore[V]) Delete(key []byte) {
|
||||
s.parent.Delete(s.key(key))
|
||||
}
|
||||
|
||||
// Iterator implements KVStore
|
||||
// Check https://github.com/cometbft/cometbft-db/blob/main/prefixdb_iterator.go#L106
|
||||
func (s Store) Iterator(start, end []byte) types.Iterator {
|
||||
func (s GStore[V]) Iterator(start, end []byte) types.GIterator[V] {
|
||||
newStart := cloneAppend(s.prefix, start)
|
||||
|
||||
var newEnd []byte
|
||||
@ -99,7 +136,7 @@ func (s Store) Iterator(start, end []byte) types.Iterator {
|
||||
|
||||
// ReverseIterator implements KVStore
|
||||
// Check https://github.com/cometbft/cometbft-db/blob/main/prefixdb_iterator.go#L129
|
||||
func (s Store) ReverseIterator(start, end []byte) types.Iterator {
|
||||
func (s GStore[V]) ReverseIterator(start, end []byte) types.GIterator[V] {
|
||||
newstart := cloneAppend(s.prefix, start)
|
||||
|
||||
var newend []byte
|
||||
@ -114,18 +151,18 @@ func (s Store) ReverseIterator(start, end []byte) types.Iterator {
|
||||
return newPrefixIterator(s.prefix, start, end, iter)
|
||||
}
|
||||
|
||||
var _ types.Iterator = (*prefixIterator)(nil)
|
||||
var _ types.Iterator = (*prefixIterator[[]byte])(nil)
|
||||
|
||||
type prefixIterator struct {
|
||||
type prefixIterator[V any] struct {
|
||||
prefix []byte
|
||||
start []byte
|
||||
end []byte
|
||||
iter types.Iterator
|
||||
iter types.GIterator[V]
|
||||
valid bool
|
||||
}
|
||||
|
||||
func newPrefixIterator(prefix, start, end []byte, parent types.Iterator) *prefixIterator {
|
||||
return &prefixIterator{
|
||||
func newPrefixIterator[V any](prefix, start, end []byte, parent types.GIterator[V]) *prefixIterator[V] {
|
||||
return &prefixIterator[V]{
|
||||
prefix: prefix,
|
||||
start: start,
|
||||
end: end,
|
||||
@ -135,17 +172,17 @@ func newPrefixIterator(prefix, start, end []byte, parent types.Iterator) *prefix
|
||||
}
|
||||
|
||||
// Domain implements Iterator, returning the start and end keys of the prefixIterator.
|
||||
func (pi *prefixIterator) Domain() ([]byte, []byte) {
|
||||
func (pi *prefixIterator[V]) Domain() ([]byte, []byte) {
|
||||
return pi.start, pi.end
|
||||
}
|
||||
|
||||
// Valid implements Iterator, checking if the prefixIterator is valid and if the underlying iterator is valid.
|
||||
func (pi *prefixIterator) Valid() bool {
|
||||
func (pi *prefixIterator[V]) Valid() bool {
|
||||
return pi.valid && pi.iter.Valid()
|
||||
}
|
||||
|
||||
// Next implements Iterator, moving the underlying iterator to the next key/value pair that starts with the prefix.
|
||||
func (pi *prefixIterator) Next() {
|
||||
func (pi *prefixIterator[V]) Next() {
|
||||
if !pi.valid {
|
||||
panic("prefixIterator invalid, cannot call Next()")
|
||||
}
|
||||
@ -157,7 +194,7 @@ func (pi *prefixIterator) Next() {
|
||||
}
|
||||
|
||||
// Key implements Iterator, returning the stripped prefix key
|
||||
func (pi *prefixIterator) Key() (key []byte) {
|
||||
func (pi *prefixIterator[V]) Key() (key []byte) {
|
||||
if !pi.valid {
|
||||
panic("prefixIterator invalid, cannot call Key()")
|
||||
}
|
||||
@ -169,7 +206,7 @@ func (pi *prefixIterator) Key() (key []byte) {
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (pi *prefixIterator) Value() []byte {
|
||||
func (pi *prefixIterator[V]) Value() V {
|
||||
if !pi.valid {
|
||||
panic("prefixIterator invalid, cannot call Value()")
|
||||
}
|
||||
@ -178,13 +215,13 @@ func (pi *prefixIterator) Value() []byte {
|
||||
}
|
||||
|
||||
// Close implements Iterator, closing the underlying iterator.
|
||||
func (pi *prefixIterator) Close() error {
|
||||
func (pi *prefixIterator[V]) Close() error {
|
||||
return pi.iter.Close()
|
||||
}
|
||||
|
||||
// Error returns an error if the prefixIterator is invalid defined by the Valid
|
||||
// method.
|
||||
func (pi *prefixIterator) Error() error {
|
||||
func (pi *prefixIterator[V]) Error() error {
|
||||
if !pi.Valid() {
|
||||
return errors.New("invalid prefixIterator")
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import (
|
||||
"cosmossdk.io/store/dbadapter"
|
||||
"cosmossdk.io/store/gaskv"
|
||||
"cosmossdk.io/store/iavl"
|
||||
"cosmossdk.io/store/transient"
|
||||
"cosmossdk.io/store/types"
|
||||
"cosmossdk.io/store/wrapper"
|
||||
)
|
||||
@ -54,6 +55,52 @@ func setRandomKVPairs(t *testing.T, store types.KVStore) []kvpair {
|
||||
return kvps
|
||||
}
|
||||
|
||||
func setRandomObjKVPairs(t *testing.T, store types.ObjKVStore) []kvpair {
|
||||
t.Helper()
|
||||
kvps := genRandomKVPairs(t)
|
||||
for _, kvp := range kvps {
|
||||
store.Set(kvp.key, kvp.value)
|
||||
}
|
||||
return kvps
|
||||
}
|
||||
|
||||
func TestObjStorePrefix(t *testing.T) {
|
||||
baseStore := transient.NewObjStore()
|
||||
prefix := []byte("test")
|
||||
prefixStore := NewObjStore(baseStore, prefix)
|
||||
prefixPrefixStore := NewObjStore(prefixStore, []byte("prefix"))
|
||||
|
||||
require.Panics(t, func() { prefixStore.Get(nil) })
|
||||
require.Panics(t, func() { prefixStore.Set(nil, []byte{}) })
|
||||
|
||||
kvps := setRandomObjKVPairs(t, prefixPrefixStore)
|
||||
|
||||
for i := 0; i < 20; i++ {
|
||||
key := kvps[i].key
|
||||
value := kvps[i].value
|
||||
require.True(t, prefixPrefixStore.Has(key))
|
||||
require.Equal(t, value, prefixPrefixStore.Get(key))
|
||||
|
||||
key = append([]byte("prefix"), key...)
|
||||
require.True(t, prefixStore.Has(key))
|
||||
require.Equal(t, value, prefixStore.Get(key))
|
||||
key = append(prefix, key...)
|
||||
require.True(t, baseStore.Has(key))
|
||||
require.Equal(t, value, baseStore.Get(key))
|
||||
|
||||
key = kvps[i].key
|
||||
prefixPrefixStore.Delete(key)
|
||||
require.False(t, prefixPrefixStore.Has(key))
|
||||
require.Nil(t, prefixPrefixStore.Get(key))
|
||||
key = append([]byte("prefix"), key...)
|
||||
require.False(t, prefixStore.Has(key))
|
||||
require.Nil(t, prefixStore.Get(key))
|
||||
key = append(prefix, key...)
|
||||
require.False(t, baseStore.Has(key))
|
||||
require.Nil(t, baseStore.Get(key))
|
||||
}
|
||||
}
|
||||
|
||||
func testPrefixStore(t *testing.T, baseStore types.KVStore, prefix []byte) {
|
||||
t.Helper()
|
||||
prefixStore := NewStore(baseStore, prefix)
|
||||
@ -105,6 +152,32 @@ func TestPrefixKVStoreNoNilSet(t *testing.T) {
|
||||
require.Panics(t, func() { gasStore.Set([]byte("key"), nil) }, "setting a nil value should panic")
|
||||
}
|
||||
|
||||
func TestObjPrefixStoreIterate(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
baseStore := dbadapter.Store{DB: db}
|
||||
prefix := []byte("test")
|
||||
prefixObjStore := NewObjStore(transient.NewObjStore(), prefix)
|
||||
|
||||
setRandomObjKVPairs(t, prefixObjStore)
|
||||
|
||||
bIter := types.KVStorePrefixIterator(baseStore, prefix)
|
||||
objIter := prefixObjStore.Iterator(nil, nil)
|
||||
|
||||
start, end := objIter.Domain()
|
||||
require.Equal(t, start, end)
|
||||
|
||||
for bIter.Valid() && objIter.Valid() {
|
||||
require.Equal(t, bIter.Key(), append(prefix, objIter.Key()...))
|
||||
require.Equal(t, bIter.Value(), objIter.Value())
|
||||
|
||||
bIter.Next()
|
||||
objIter.Next()
|
||||
}
|
||||
|
||||
bIter.Close()
|
||||
objIter.Close()
|
||||
}
|
||||
|
||||
func TestPrefixStoreIterate(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
baseStore := dbadapter.Store{DB: db}
|
||||
|
||||
@ -67,9 +67,10 @@ type Store struct {
|
||||
// iavlSyncPruning should rarely be set to true.
|
||||
// The Prune command will automatically set this to true.
|
||||
// This allows the prune command to wait for the pruning to finish before returning.
|
||||
iavlSyncPruning bool
|
||||
storesParams map[types.StoreKey]storeParams
|
||||
stores map[types.StoreKey]types.CommitKVStore
|
||||
iavlSyncPruning bool
|
||||
storesParams map[types.StoreKey]storeParams
|
||||
// CommitStore is a common interface to unify generic CommitKVStore of different value types
|
||||
stores map[types.StoreKey]types.CommitStore
|
||||
keysByName map[string]types.StoreKey
|
||||
initialVersion int64
|
||||
removalMap map[types.StoreKey]bool
|
||||
@ -99,7 +100,7 @@ func NewStore(db dbm.DB, logger log.Logger, metricGatherer metrics.StoreMetrics)
|
||||
iavlCacheSize: iavl.DefaultIAVLCacheSize,
|
||||
iavlDisableFastNode: iavlDisablefastNodeDefault,
|
||||
storesParams: make(map[types.StoreKey]storeParams),
|
||||
stores: make(map[types.StoreKey]types.CommitKVStore),
|
||||
stores: make(map[types.StoreKey]types.CommitStore),
|
||||
keysByName: make(map[string]types.StoreKey),
|
||||
listeners: make(map[types.StoreKey]*types.MemoryListener),
|
||||
removalMap: make(map[types.StoreKey]bool),
|
||||
@ -166,12 +167,6 @@ func (rs *Store) MountStoreWithDB(key types.StoreKey, typ types.StoreType, db db
|
||||
// GetCommitStore returns a mounted CommitStore for a given StoreKey. If the
|
||||
// store is wrapped in an inter-block cache, it will be unwrapped before returning.
|
||||
func (rs *Store) GetCommitStore(key types.StoreKey) types.CommitStore {
|
||||
return rs.GetCommitKVStore(key)
|
||||
}
|
||||
|
||||
// GetCommitKVStore returns a mounted CommitKVStore for a given StoreKey. If the
|
||||
// store is wrapped in an inter-block cache, it will be unwrapped before returning.
|
||||
func (rs *Store) GetCommitKVStore(key types.StoreKey) types.CommitKVStore {
|
||||
// If the Store has an inter-block cache, first attempt to lookup and unwrap
|
||||
// the underlying CommitKVStore by StoreKey. If it does not exist, fallback to
|
||||
// the main mapping of CommitKVStores.
|
||||
@ -184,6 +179,17 @@ func (rs *Store) GetCommitKVStore(key types.StoreKey) types.CommitKVStore {
|
||||
return rs.stores[key]
|
||||
}
|
||||
|
||||
// GetCommitKVStore returns a mounted CommitKVStore for a given StoreKey. If the
|
||||
// store is wrapped in an inter-block cache, it will be unwrapped before returning.
|
||||
func (rs *Store) GetCommitKVStore(key types.StoreKey) types.CommitKVStore {
|
||||
store, ok := rs.GetCommitStore(key).(types.CommitKVStore)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not CommitKVStore", key))
|
||||
}
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
// StoreKeysByName returns mapping storeNames -> StoreKeys
|
||||
func (rs *Store) StoreKeysByName() map[string]types.StoreKey {
|
||||
return rs.keysByName
|
||||
@ -232,7 +238,7 @@ func (rs *Store) loadVersion(ver int64, upgrades *types.StoreUpgrades) error {
|
||||
}
|
||||
|
||||
// load each Store (note this doesn't panic on unmounted keys now)
|
||||
newStores := make(map[types.StoreKey]types.CommitKVStore)
|
||||
newStores := make(map[types.StoreKey]types.CommitStore)
|
||||
|
||||
storesKeys := make([]types.StoreKey, 0, len(rs.storesParams))
|
||||
|
||||
@ -574,15 +580,17 @@ func (rs *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.Cac
|
||||
func (rs *Store) CacheMultiStore() types.CacheMultiStore {
|
||||
stores := make(map[types.StoreKey]types.CacheWrapper)
|
||||
for k, v := range rs.stores {
|
||||
store := types.KVStore(v)
|
||||
// Wire the listenkv.Store to allow listeners to observe the writes from the cache store,
|
||||
// set same listeners on cache store will observe duplicated writes.
|
||||
if rs.ListeningEnabled(k) {
|
||||
store = listenkv.NewStore(store, k, rs.listeners[k])
|
||||
store := types.CacheWrapper(v)
|
||||
if kv, ok := store.(types.KVStore); ok {
|
||||
// Wire the listenkv.Store to allow listeners to observe the writes from the cache store,
|
||||
// set same listeners on cache store will observe duplicated writes.
|
||||
if rs.ListeningEnabled(k) {
|
||||
store = listenkv.NewStore(kv, k, rs.listeners[k])
|
||||
}
|
||||
}
|
||||
stores[k] = store
|
||||
}
|
||||
return cachemulti.NewStore(rs.db, stores, rs.keysByName, rs.traceWriter, rs.getTracingContext())
|
||||
return cachemulti.NewStore(stores, rs.traceWriter, rs.getTracingContext())
|
||||
}
|
||||
|
||||
// CacheMultiStoreWithVersion is analogous to CacheMultiStore except that it
|
||||
@ -594,7 +602,7 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor
|
||||
var commitInfo *types.CommitInfo
|
||||
storeInfos := map[string]bool{}
|
||||
for key, store := range rs.stores {
|
||||
var cacheStore types.KVStore
|
||||
var cacheStore types.CacheWrapper
|
||||
switch store.GetStoreType() {
|
||||
case types.StoreTypeIAVL:
|
||||
// If the store is wrapped with an inter-block cache, we must first unwrap
|
||||
@ -637,16 +645,18 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor
|
||||
cacheStore = store
|
||||
}
|
||||
|
||||
// Wire the listenkv.Store to allow listeners to observe the writes from the cache store,
|
||||
// set same listeners on cache store will observe duplicated writes.
|
||||
if rs.ListeningEnabled(key) {
|
||||
cacheStore = listenkv.NewStore(cacheStore, key, rs.listeners[key])
|
||||
if kv, ok := cacheStore.(types.KVStore); ok {
|
||||
// Wire the listenkv.Store to allow listeners to observe the writes from the cache store,
|
||||
// set same listeners on cache store will observe duplicated writes.
|
||||
if rs.ListeningEnabled(key) {
|
||||
cacheStore = listenkv.NewStore(kv, key, rs.listeners[key])
|
||||
}
|
||||
}
|
||||
|
||||
cachedStores[key] = cacheStore
|
||||
}
|
||||
|
||||
return cachemulti.NewStore(rs.db, cachedStores, rs.keysByName, rs.traceWriter, rs.getTracingContext()), nil
|
||||
return cachemulti.NewStore(cachedStores, rs.traceWriter, rs.getTracingContext()), nil
|
||||
}
|
||||
|
||||
// GetStore returns a mounted Store for a given StoreKey. If the StoreKey does
|
||||
@ -656,7 +666,7 @@ func (rs *Store) CacheMultiStoreWithVersion(version int64) (types.CacheMultiStor
|
||||
// TODO: This isn't used directly upstream. Consider returning the Store as-is
|
||||
// instead of unwrapping.
|
||||
func (rs *Store) GetStore(key types.StoreKey) types.Store {
|
||||
store := rs.GetCommitKVStore(key)
|
||||
store := rs.GetCommitStore(key)
|
||||
if store == nil {
|
||||
panic(fmt.Sprintf("store does not exist for key: %s", key.Name()))
|
||||
}
|
||||
@ -675,7 +685,10 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore {
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("store does not exist for key: %s", key.Name()))
|
||||
}
|
||||
store := types.KVStore(s)
|
||||
store, ok := s.(types.KVStore)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not KVStore", key))
|
||||
}
|
||||
|
||||
if rs.TracingEnabled() {
|
||||
store = tracekv.NewStore(store, rs.traceWriter, rs.getTracingContext())
|
||||
@ -687,6 +700,20 @@ func (rs *Store) GetKVStore(key types.StoreKey) types.KVStore {
|
||||
return store
|
||||
}
|
||||
|
||||
// GetObjKVStore returns a mounted ObjKVStore for a given StoreKey.
|
||||
func (rs *Store) GetObjKVStore(key types.StoreKey) types.ObjKVStore {
|
||||
s := rs.stores[key]
|
||||
if s == nil {
|
||||
panic(fmt.Sprintf("store does not exist for key: %s", key.Name()))
|
||||
}
|
||||
store, ok := s.(types.ObjKVStore)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("store with key %v is not ObjKVStore", key))
|
||||
}
|
||||
|
||||
return store
|
||||
}
|
||||
|
||||
func (rs *Store) handlePruning(version int64) error {
|
||||
pruneHeight := rs.pruningManager.GetPruningHeight(version)
|
||||
rs.logger.Debug("prune start", "height", version)
|
||||
@ -738,7 +765,7 @@ func (rs *Store) GetStoreByName(name string) types.Store {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rs.GetCommitKVStore(key)
|
||||
return rs.GetCommitStore(key)
|
||||
}
|
||||
|
||||
// Query calls substore.Query with the same `req` where `req.Path` is
|
||||
@ -852,10 +879,10 @@ func (rs *Store) Snapshot(height uint64, protoWriter protoio.Writer) error {
|
||||
stores := []namedStore{}
|
||||
keys := keysFromStoreKeyMap(rs.stores)
|
||||
for _, key := range keys {
|
||||
switch store := rs.GetCommitKVStore(key).(type) {
|
||||
switch store := rs.GetCommitStore(key).(type) {
|
||||
case *iavl.Store:
|
||||
stores = append(stores, namedStore{name: key.Name(), Store: store})
|
||||
case *transient.Store, *mem.Store:
|
||||
case *transient.Store, *mem.Store, *transient.ObjStore:
|
||||
// Non-persisted stores shouldn't be snapshotted
|
||||
continue
|
||||
default:
|
||||
@ -1015,7 +1042,7 @@ loop:
|
||||
return snapshotItem, rs.LoadLatestVersion()
|
||||
}
|
||||
|
||||
func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID, params storeParams) (types.CommitKVStore, error) {
|
||||
func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID, params storeParams) (types.CommitStore, error) {
|
||||
var db dbm.DB
|
||||
|
||||
if params.db != nil {
|
||||
@ -1047,20 +1074,26 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, id types.CommitID
|
||||
return commitDBStoreAdapter{Store: dbadapter.Store{DB: db}}, nil
|
||||
|
||||
case types.StoreTypeTransient:
|
||||
_, ok := key.(*types.TransientStoreKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid StoreKey for StoreTypeTransient: %s", key.String())
|
||||
if _, ok := key.(*types.TransientStoreKey); !ok {
|
||||
return nil, fmt.Errorf("unexpected key type for a TransientStoreKey; got: %s, %T", key.String(), key)
|
||||
}
|
||||
|
||||
return transient.NewStore(), nil
|
||||
|
||||
case types.StoreTypeMemory:
|
||||
if _, ok := key.(*types.MemoryStoreKey); !ok {
|
||||
return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s", key.String())
|
||||
return nil, fmt.Errorf("unexpected key type for a MemoryStoreKey; got: %s, %T", key.String(), key)
|
||||
}
|
||||
|
||||
return mem.NewStore(), nil
|
||||
|
||||
case types.StoreTypeObject:
|
||||
if _, ok := key.(*types.ObjectStoreKey); !ok {
|
||||
return nil, fmt.Errorf("unexpected key type for a ObjectStoreKey; got: %s, %T", key.String(), key)
|
||||
}
|
||||
|
||||
return transient.NewObjStore(), nil
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unrecognized store type %v", params.typ))
|
||||
}
|
||||
@ -1072,7 +1105,7 @@ func (rs *Store) buildCommitInfo(version int64) *types.CommitInfo {
|
||||
for _, key := range keys {
|
||||
store := rs.stores[key]
|
||||
storeType := store.GetStoreType()
|
||||
if storeType == types.StoreTypeTransient || storeType == types.StoreTypeMemory {
|
||||
if storeType == types.StoreTypeTransient || storeType == types.StoreTypeMemory || storeType == types.StoreTypeObject {
|
||||
continue
|
||||
}
|
||||
storeInfos = append(storeInfos, types.StoreInfo{
|
||||
@ -1190,7 +1223,7 @@ func GetLatestVersion(db dbm.DB) int64 {
|
||||
}
|
||||
|
||||
// commitStores commits each store and returns a new commitInfo.
|
||||
func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore, removalMap map[types.StoreKey]bool) *types.CommitInfo {
|
||||
func commitStores(version int64, storeMap map[types.StoreKey]types.CommitStore, removalMap map[types.StoreKey]bool) *types.CommitInfo {
|
||||
storeInfos := make([]types.StoreInfo, 0, len(storeMap))
|
||||
storeKeys := keysFromStoreKeyMap(storeMap)
|
||||
|
||||
@ -1210,7 +1243,7 @@ func commitStores(version int64, storeMap map[types.StoreKey]types.CommitKVStore
|
||||
}
|
||||
|
||||
storeType := store.GetStoreType()
|
||||
if storeType == types.StoreTypeTransient || storeType == types.StoreTypeMemory {
|
||||
if storeType == types.StoreTypeTransient || storeType == types.StoreTypeMemory || storeType == types.StoreTypeObject {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import (
|
||||
sdkmaps "cosmossdk.io/store/internal/maps"
|
||||
"cosmossdk.io/store/metrics"
|
||||
pruningtypes "cosmossdk.io/store/pruning/types"
|
||||
"cosmossdk.io/store/transient"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
@ -29,6 +30,23 @@ func TestStoreType(t *testing.T) {
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db)
|
||||
}
|
||||
|
||||
func TestGetObjKVStore(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningDefault))
|
||||
err := ms.LoadLatestVersion()
|
||||
require.Nil(t, err)
|
||||
|
||||
key := ms.keysByName["store6"]
|
||||
|
||||
store1 := ms.GetObjKVStore(key)
|
||||
require.NotNil(t, store1)
|
||||
require.IsType(t, &transient.ObjStore{}, store1)
|
||||
|
||||
store2 := ms.GetCommitStore(key)
|
||||
require.NotNil(t, store2)
|
||||
require.IsType(t, &transient.ObjStore{}, store2)
|
||||
}
|
||||
|
||||
func TestGetCommitKVStore(t *testing.T) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
ms := newMultiStoreWithMounts(db, pruningtypes.NewPruningOptions(pruningtypes.PruningDefault))
|
||||
@ -938,6 +956,8 @@ var (
|
||||
testStoreKey1 = types.NewKVStoreKey("store1")
|
||||
testStoreKey2 = types.NewKVStoreKey("store2")
|
||||
testStoreKey3 = types.NewKVStoreKey("store3")
|
||||
testStoreKey4 = types.NewKVStoreKey("store4")
|
||||
testStoreKey6 = types.NewObjectStoreKey("store6")
|
||||
)
|
||||
|
||||
func newMultiStoreWithMounts(db dbm.DB, pruningOpts pruningtypes.PruningOptions) *Store {
|
||||
@ -947,6 +967,7 @@ func newMultiStoreWithMounts(db dbm.DB, pruningOpts pruningtypes.PruningOptions)
|
||||
store.MountStoreWithDB(testStoreKey1, types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(testStoreKey2, types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(testStoreKey3, types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(testStoreKey6, types.StoreTypeObject, nil)
|
||||
|
||||
return store
|
||||
}
|
||||
@ -1010,9 +1031,12 @@ func getExpectedCommitID(store *Store, ver int64) types.CommitID {
|
||||
}
|
||||
}
|
||||
|
||||
func hashStores(stores map[types.StoreKey]types.CommitKVStore) []byte {
|
||||
func hashStores(stores map[types.StoreKey]types.CommitStore) []byte {
|
||||
m := make(map[string][]byte, len(stores))
|
||||
for key, store := range stores {
|
||||
if store.GetStoreType() != types.StoreTypeIAVL {
|
||||
continue
|
||||
}
|
||||
name := key.Name()
|
||||
m[name] = types.StoreInfo{
|
||||
Name: name,
|
||||
@ -1065,35 +1089,40 @@ func TestStateListeners(t *testing.T) {
|
||||
require.Empty(t, ms.PopStateCache())
|
||||
}
|
||||
|
||||
type commitKVStoreStub struct {
|
||||
types.CommitKVStore
|
||||
type commitStoreStub struct {
|
||||
types.CommitStore
|
||||
Committed int
|
||||
}
|
||||
|
||||
func (stub *commitKVStoreStub) Commit() types.CommitID {
|
||||
commitID := stub.CommitKVStore.Commit()
|
||||
func (stub *commitStoreStub) Commit() types.CommitID {
|
||||
commitID := stub.CommitStore.Commit()
|
||||
stub.Committed++
|
||||
return commitID
|
||||
}
|
||||
|
||||
func prepareStoreMap() (map[types.StoreKey]types.CommitKVStore, error) {
|
||||
func prepareStoreMap() (map[types.StoreKey]types.CommitStore, error) {
|
||||
var db dbm.DB = dbm.NewMemDB()
|
||||
store := NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("iavl1"), types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(types.NewKVStoreKey("iavl2"), types.StoreTypeIAVL, nil)
|
||||
store.MountStoreWithDB(types.NewTransientStoreKey("trans1"), types.StoreTypeTransient, nil)
|
||||
store.MountStoreWithDB(types.NewMemoryStoreKey("mem1"), types.StoreTypeMemory, nil)
|
||||
store.MountStoreWithDB(types.NewObjectStoreKey("obj1"), types.StoreTypeObject, nil)
|
||||
if err := store.LoadLatestVersion(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return map[types.StoreKey]types.CommitKVStore{
|
||||
testStoreKey1: &commitKVStoreStub{
|
||||
CommitKVStore: store.GetStoreByName("iavl1").(types.CommitKVStore),
|
||||
return map[types.StoreKey]types.CommitStore{
|
||||
testStoreKey1: &commitStoreStub{
|
||||
CommitStore: store.GetStoreByName("iavl1").(types.CommitStore),
|
||||
},
|
||||
testStoreKey2: &commitKVStoreStub{
|
||||
CommitKVStore: store.GetStoreByName("iavl2").(types.CommitKVStore),
|
||||
testStoreKey2: &commitStoreStub{
|
||||
CommitStore: store.GetStoreByName("iavl2").(types.CommitStore),
|
||||
},
|
||||
testStoreKey3: &commitKVStoreStub{
|
||||
CommitKVStore: store.GetStoreByName("trans1").(types.CommitKVStore),
|
||||
testStoreKey3: &commitStoreStub{
|
||||
CommitStore: store.GetStoreByName("trans1").(types.CommitStore),
|
||||
},
|
||||
testStoreKey4: &commitStoreStub{
|
||||
CommitStore: store.GetStoreByName("obj1").(types.CommitStore),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -1124,7 +1153,7 @@ func TestCommitStores(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
storeMap, err := prepareStoreMap()
|
||||
require.NoError(t, err)
|
||||
store := storeMap[testStoreKey1].(*commitKVStoreStub)
|
||||
store := storeMap[testStoreKey1].(*commitStoreStub)
|
||||
for i := tc.committed; i > 0; i-- {
|
||||
store.Commit()
|
||||
}
|
||||
|
||||
@ -161,10 +161,9 @@ func (tkv *Store) GetStoreType() types.StoreType {
|
||||
return tkv.parent.GetStoreType()
|
||||
}
|
||||
|
||||
// CacheWrap implements the KVStore interface. It panics because a Store
|
||||
// cannot be branched.
|
||||
// CacheWrap implements CacheWrapper.
|
||||
func (tkv *Store) CacheWrap() types.CacheWrap {
|
||||
panic("cannot CacheWrap a TraceKVStore")
|
||||
return tkv.parent.CacheWrap()
|
||||
}
|
||||
|
||||
// CacheWrapWithTrace implements the KVStore interface. It panics as a
|
||||
|
||||
@ -283,7 +283,7 @@ func TestTraceKVStoreGetStoreType(t *testing.T) {
|
||||
|
||||
func TestTraceKVStoreCacheWrap(t *testing.T) {
|
||||
store := newEmptyTraceKVStore(nil)
|
||||
require.Panics(t, func() { store.CacheWrap() })
|
||||
store.CacheWrap()
|
||||
}
|
||||
|
||||
func TestTraceKVStoreCacheWrapWithTrace(t *testing.T) {
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package transient
|
||||
|
||||
import (
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
|
||||
"cosmossdk.io/store/dbadapter"
|
||||
"cosmossdk.io/store/internal"
|
||||
"cosmossdk.io/store/internal/btree"
|
||||
pruningtypes "cosmossdk.io/store/pruning/types"
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
@ -11,43 +10,73 @@ import (
|
||||
var (
|
||||
_ types.Committer = (*Store)(nil)
|
||||
_ types.KVStore = (*Store)(nil)
|
||||
|
||||
_ types.Committer = (*ObjStore)(nil)
|
||||
_ types.ObjKVStore = (*ObjStore)(nil)
|
||||
)
|
||||
|
||||
// Store is a wrapper for a MemDB with Committer implementation
|
||||
type Store struct {
|
||||
dbadapter.Store
|
||||
// GStore is a wrapper for a MemDB with Committer implementation
|
||||
type GStore[V any] struct {
|
||||
internal.BTreeStore[V]
|
||||
}
|
||||
|
||||
// NewGStore constructs new generic transient store
|
||||
func NewGStore[V any](isZero func(V) bool, valueLen func(V) int) *GStore[V] {
|
||||
return &GStore[V]{*internal.NewBTreeStore(btree.NewBTree[V](), isZero, valueLen)}
|
||||
}
|
||||
|
||||
// Store specializes GStore for []byte
|
||||
type Store struct {
|
||||
GStore[[]byte]
|
||||
}
|
||||
|
||||
// NewStore constructs new MemDB adapter
|
||||
func NewStore() *Store {
|
||||
return &Store{Store: dbadapter.Store{DB: dbm.NewMemDB()}}
|
||||
return &Store{*NewGStore(
|
||||
types.BytesIsZero,
|
||||
types.BytesValueLen,
|
||||
)}
|
||||
}
|
||||
|
||||
func (*Store) GetStoreType() types.StoreType {
|
||||
return types.StoreTypeTransient
|
||||
}
|
||||
|
||||
// ObjStore specializes GStore for any
|
||||
type ObjStore struct {
|
||||
GStore[any]
|
||||
}
|
||||
|
||||
func NewObjStore() *ObjStore {
|
||||
return &ObjStore{*NewGStore(
|
||||
types.AnyIsZero,
|
||||
types.AnyValueLen,
|
||||
)}
|
||||
}
|
||||
|
||||
func (*ObjStore) GetStoreType() types.StoreType {
|
||||
return types.StoreTypeObject
|
||||
}
|
||||
|
||||
// Commit cleans up Store.
|
||||
// Implements CommitStore
|
||||
func (ts *Store) Commit() (id types.CommitID) {
|
||||
ts.Store = dbadapter.Store{DB: dbm.NewMemDB()}
|
||||
func (ts *GStore[V]) Commit() (id types.CommitID) {
|
||||
ts.Clear()
|
||||
return id
|
||||
}
|
||||
|
||||
func (ts *Store) SetPruning(_ pruningtypes.PruningOptions) {}
|
||||
func (ts *GStore[V]) SetPruning(_ pruningtypes.PruningOptions) {}
|
||||
|
||||
// GetPruning is a no-op as pruning options cannot be directly set on this store.
|
||||
// They must be set on the root commit multi-store.
|
||||
func (ts *Store) GetPruning() pruningtypes.PruningOptions {
|
||||
func (ts *GStore[V]) GetPruning() pruningtypes.PruningOptions {
|
||||
return pruningtypes.NewPruningOptions(pruningtypes.PruningUndefined)
|
||||
}
|
||||
|
||||
// LastCommitID implements CommitStore, returns empty CommitID.
|
||||
func (ts *Store) LastCommitID() types.CommitID {
|
||||
func (ts *GStore[V]) LastCommitID() types.CommitID {
|
||||
return types.CommitID{}
|
||||
}
|
||||
|
||||
func (ts *Store) WorkingHash() []byte {
|
||||
func (ts *GStore[V]) WorkingHash() []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
// GetStoreType implements Store, returns StoreTypeTransient.
|
||||
func (ts *Store) GetStoreType() types.StoreType {
|
||||
return types.StoreTypeTransient
|
||||
}
|
||||
|
||||
@ -128,6 +128,7 @@ type MultiStore interface {
|
||||
// If the store does not exist, panics.
|
||||
GetStore(StoreKey) Store
|
||||
GetKVStore(StoreKey) KVStore
|
||||
GetObjKVStore(StoreKey) ObjKVStore
|
||||
|
||||
// TracingEnabled returns if tracing is enabled for the MultiStore.
|
||||
TracingEnabled() bool
|
||||
@ -227,25 +228,25 @@ type CommitMultiStore interface {
|
||||
//---------subsp-------------------------------
|
||||
// KVStore
|
||||
|
||||
// BasicKVStore is a simple interface to get/set data
|
||||
type BasicKVStore interface {
|
||||
// GBasicKVStore is a simple interface to get/set data
|
||||
type GBasicKVStore[V any] interface {
|
||||
// Get returns nil if key doesn't exist. Panics on nil key.
|
||||
Get(key []byte) []byte
|
||||
Get(key []byte) V
|
||||
|
||||
// Has checks if a key exists. Panics on nil key.
|
||||
Has(key []byte) bool
|
||||
|
||||
// Set sets the key. Panics on nil key or value.
|
||||
Set(key, value []byte)
|
||||
Set(key []byte, value V)
|
||||
|
||||
// Delete deletes the key. Panics on nil key.
|
||||
Delete(key []byte)
|
||||
}
|
||||
|
||||
// KVStore additionally provides iteration and deletion
|
||||
type KVStore interface {
|
||||
// GKVStore additionally provides iteration and deletion
|
||||
type GKVStore[V any] interface {
|
||||
Store
|
||||
BasicKVStore
|
||||
GBasicKVStore[V]
|
||||
|
||||
// Iterator over a domain of keys in ascending order. End is exclusive.
|
||||
// Start must be less than end, or the Iterator is invalid.
|
||||
@ -253,18 +254,54 @@ type KVStore interface {
|
||||
// To iterate over entire domain, use store.Iterator(nil, nil)
|
||||
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
|
||||
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
|
||||
Iterator(start, end []byte) Iterator
|
||||
Iterator(start, end []byte) GIterator[V]
|
||||
|
||||
// Iterator over a domain of keys in descending order. End is exclusive.
|
||||
// Start must be less than end, or the Iterator is invalid.
|
||||
// Iterator must be closed by caller.
|
||||
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
|
||||
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
|
||||
ReverseIterator(start, end []byte) Iterator
|
||||
ReverseIterator(start, end []byte) GIterator[V]
|
||||
}
|
||||
|
||||
// Iterator is an alias db's Iterator for convenience.
|
||||
type Iterator = dbm.Iterator
|
||||
// GIterator is the generic version of dbm's Iterator
|
||||
type GIterator[V any] interface {
|
||||
// Domain returns the start (inclusive) and end (exclusive) limits of the iterator.
|
||||
// CONTRACT: start, end readonly []byte
|
||||
Domain() (start, end []byte)
|
||||
|
||||
// Valid returns whether the current iterator is valid. Once invalid, the Iterator remains
|
||||
// invalid forever.
|
||||
Valid() bool
|
||||
|
||||
// Next moves the iterator to the next key in the database, as defined by order of iteration.
|
||||
// If Valid returns false, this method will panic.
|
||||
Next()
|
||||
|
||||
// Key returns the key at the current position. Panics if the iterator is invalid.
|
||||
// CONTRACT: key readonly []byte
|
||||
Key() (key []byte)
|
||||
|
||||
// Value returns the value at the current position. Panics if the iterator is invalid.
|
||||
// CONTRACT: value readonly []byte
|
||||
Value() (value V)
|
||||
|
||||
// Error returns the last error encountered by the iterator, if any.
|
||||
Error() error
|
||||
|
||||
// Close closes the iterator, relasing any allocated resources.
|
||||
Close() error
|
||||
}
|
||||
|
||||
type (
|
||||
Iterator = GIterator[[]byte]
|
||||
BasicKVStore = GBasicKVStore[[]byte]
|
||||
KVStore = GKVStore[[]byte]
|
||||
|
||||
ObjIterator = GIterator[any]
|
||||
ObjBasicKVStore = GBasicKVStore[any]
|
||||
ObjKVStore = GKVStore[any]
|
||||
)
|
||||
|
||||
// CacheKVStore branches a KVStore and provides read cache functionality.
|
||||
// After calling .Write() on the CacheKVStore, all previously created
|
||||
@ -290,14 +327,10 @@ type CommitKVStore interface {
|
||||
// a Committer, since Commit ephemeral store make no sense. It can return KVStore,
|
||||
// HeapStore, SpaceStore, etc.
|
||||
type CacheWrap interface {
|
||||
CacheWrapper
|
||||
|
||||
// Write syncs with the underlying store.
|
||||
Write()
|
||||
|
||||
// CacheWrap recursively wraps again.
|
||||
CacheWrap() CacheWrap
|
||||
|
||||
// CacheWrapWithTrace recursively wraps again with tracing enabled.
|
||||
CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap
|
||||
}
|
||||
|
||||
type CacheWrapper interface {
|
||||
@ -330,6 +363,7 @@ const (
|
||||
StoreTypeMemory
|
||||
StoreTypeSMT
|
||||
StoreTypePersistent
|
||||
StoreTypeObject
|
||||
)
|
||||
|
||||
func (st StoreType) String() string {
|
||||
@ -354,6 +388,9 @@ func (st StoreType) String() string {
|
||||
|
||||
case StoreTypePersistent:
|
||||
return "StoreTypePersistent"
|
||||
|
||||
case StoreTypeObject:
|
||||
return "StoreTypeObject"
|
||||
}
|
||||
|
||||
return "unknown store type"
|
||||
@ -433,6 +470,29 @@ func (key *TransientStoreKey) String() string {
|
||||
return fmt.Sprintf("TransientStoreKey{%p, %s}", key, key.name)
|
||||
}
|
||||
|
||||
// ObjectStoreKey is used for indexing transient stores in a MultiStore
|
||||
type ObjectStoreKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
// NewObjectStoreKey constructs new ObjectStoreKey
|
||||
// Must return a pointer according to the ocap principle
|
||||
func NewObjectStoreKey(name string) *ObjectStoreKey {
|
||||
return &ObjectStoreKey{
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the name of the ObjectStoreKey
|
||||
func (key *ObjectStoreKey) Name() string {
|
||||
return key.name
|
||||
}
|
||||
|
||||
// String returns a string representation of the ObjectStoreKey
|
||||
func (key *ObjectStoreKey) String() string {
|
||||
return fmt.Sprintf("ObjectStoreKey{%p, %s}", key, key.name)
|
||||
}
|
||||
|
||||
// MemoryStoreKey defines a typed key to be used with an in-memory KVStore.
|
||||
type MemoryStoreKey struct {
|
||||
name string
|
||||
@ -526,3 +586,17 @@ func NewMemoryStoreKeys(names ...string) map[string]*MemoryStoreKey {
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
// NewObjectStoreKeys constructs a new map matching store key names to their
|
||||
// respective ObjectStoreKey references.
|
||||
// The function will panic if there is a potential conflict in names (see `assertNoPrefix`
|
||||
// function for more details).
|
||||
func NewObjectStoreKeys(names ...string) map[string]*ObjectStoreKey {
|
||||
assertNoCommonPrefix(names)
|
||||
keys := make(map[string]*ObjectStoreKey)
|
||||
for _, n := range names {
|
||||
keys[n] = NewObjectStoreKey(n)
|
||||
}
|
||||
|
||||
return keys
|
||||
}
|
||||
|
||||
@ -99,6 +99,14 @@ func TestTransientStoreKey(t *testing.T) {
|
||||
require.Equal(t, fmt.Sprintf("TransientStoreKey{%p, test}", key), key.String())
|
||||
}
|
||||
|
||||
func TestObjectStoreKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := NewObjectStoreKey("test")
|
||||
require.Equal(t, "test", key.name)
|
||||
require.Equal(t, key.name, key.Name())
|
||||
require.Equal(t, fmt.Sprintf("ObjectStoreKey{%p, test}", key), key.String())
|
||||
}
|
||||
|
||||
func TestMemoryStoreKey(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := NewMemoryStoreKey("test")
|
||||
@ -229,6 +237,11 @@ func TestNewTransientStoreKeys(t *testing.T) {
|
||||
assert.DeepEqual(t, 1, len(NewTransientStoreKeys("one")))
|
||||
}
|
||||
|
||||
func TestNewObjectStoreKeys(t *testing.T) {
|
||||
assert.DeepEqual(t, map[string]*ObjectStoreKey{}, NewObjectStoreKeys())
|
||||
assert.DeepEqual(t, 1, len(NewObjectStoreKeys("one")))
|
||||
}
|
||||
|
||||
func TestNewInfiniteGasMeter(t *testing.T) {
|
||||
gm := NewInfiniteGasMeter()
|
||||
require.NotNil(t, gm)
|
||||
|
||||
@ -7,6 +7,26 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// BytesIsZero returns whether the byte array is nil
|
||||
func BytesIsZero(v []byte) bool {
|
||||
return v == nil
|
||||
}
|
||||
|
||||
// BytesValueLen returns the length of the byte array
|
||||
func BytesValueLen(v []byte) int {
|
||||
return len(v)
|
||||
}
|
||||
|
||||
// AnyIsZero returns whether the underlying data is nil
|
||||
func AnyIsZero(v any) bool {
|
||||
return v == nil
|
||||
}
|
||||
|
||||
// AnyValueLen returns 16 because the any type has a constant size and functions like unsafe.Sizeof cannot introspect.
|
||||
func AnyValueLen[V any](v V) int {
|
||||
return 16
|
||||
}
|
||||
|
||||
// KVStorePrefixIterator iterates over all the keys with a certain prefix in ascending order
|
||||
func KVStorePrefixIterator(kvs KVStore, prefix []byte) Iterator {
|
||||
return kvs.Iterator(prefix, PrefixEndBytes(prefix))
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/v3/assert"
|
||||
@ -8,6 +9,143 @@ import (
|
||||
"cosmossdk.io/store/types"
|
||||
)
|
||||
|
||||
func TestBytesIsZero(t *testing.T) {
|
||||
tests := []struct {
|
||||
tc []byte
|
||||
expected bool
|
||||
}{
|
||||
{[]byte("foobar"), false},
|
||||
{[]byte(""), false},
|
||||
{[]byte{}, false},
|
||||
{nil, true},
|
||||
}
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("%v", i), func(t *testing.T) {
|
||||
assert.Equal(t, test.expected, types.BytesIsZero(test.tc))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesValueLen(t *testing.T) {
|
||||
tests := []struct {
|
||||
tc []byte
|
||||
expected int
|
||||
}{
|
||||
{[]byte("foobar"), 6},
|
||||
{[]byte(""), 0},
|
||||
{[]byte{}, 0},
|
||||
{nil, 0},
|
||||
}
|
||||
for _, test := range tests {
|
||||
assert.Equal(t, test.expected, types.BytesValueLen(test.tc))
|
||||
}
|
||||
}
|
||||
|
||||
type struct1 struct {
|
||||
a int
|
||||
b []string
|
||||
}
|
||||
|
||||
type struct2 struct {
|
||||
a int
|
||||
b []string
|
||||
c bool
|
||||
}
|
||||
|
||||
func TestAnyIsZero(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
name string
|
||||
obj any
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
"string length",
|
||||
"foobar",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"struct1 length",
|
||||
struct1{4, []string{"1", "2", "3"}},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"struct2 length",
|
||||
struct2{4, []string{"1", "2", "3"}, true},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"struct1 pointer length",
|
||||
&struct2{4, []string{"1", "2", "3"}, true},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"empty string",
|
||||
"",
|
||||
false,
|
||||
},
|
||||
{
|
||||
"nil",
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"empty array",
|
||||
[]string{},
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.expected, types.AnyIsZero(test.obj))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnyValueLen(t *testing.T) {
|
||||
t.Parallel()
|
||||
type struct1 struct {
|
||||
a int
|
||||
b []string
|
||||
}
|
||||
type struct2 struct {
|
||||
a int
|
||||
b []string
|
||||
c bool
|
||||
}
|
||||
testCases := []struct {
|
||||
name string
|
||||
obj any
|
||||
expectedLen int
|
||||
}{
|
||||
{
|
||||
"string length",
|
||||
"foobar",
|
||||
16,
|
||||
},
|
||||
{
|
||||
"struct1 length",
|
||||
struct1{4, []string{"1", "2", "3"}},
|
||||
16,
|
||||
},
|
||||
{
|
||||
"struct2 length",
|
||||
struct2{4, []string{"1", "2", "3"}, true},
|
||||
16,
|
||||
},
|
||||
{
|
||||
"struct1 pointer length",
|
||||
&struct2{4, []string{"1", "2", "3"}, true},
|
||||
16,
|
||||
},
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
assert.Equal(t, test.expectedLen, types.AnyValueLen(test.obj))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrefixEndBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCases := []struct {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package types
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// MaxKeyLength is 128K - 1
|
||||
MaxKeyLength = (1 << 17) - 1
|
||||
@ -22,7 +24,20 @@ func AssertValidValue(value []byte) {
|
||||
if value == nil {
|
||||
panic("value is nil")
|
||||
}
|
||||
if len(value) > MaxValueLength {
|
||||
panic("value is too large")
|
||||
AssertValidValueLength(len(value))
|
||||
}
|
||||
|
||||
// AssertValidValueGeneric checks if the value is valid(value is not nil and within length limit)
|
||||
func AssertValidValueGeneric[V any](value V, isZero func(V) bool, valueLen func(V) int) {
|
||||
if isZero(value) {
|
||||
panic("value is nil")
|
||||
}
|
||||
AssertValidValueLength(valueLen(value))
|
||||
}
|
||||
|
||||
// AssertValidValueLength checks if the value length is within length limit
|
||||
func AssertValidValueLength(l int) {
|
||||
if l > MaxValueLength {
|
||||
panic(errors.New("value is too large"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,3 +21,37 @@ func TestAssertValidValue(t *testing.T) {
|
||||
require.NotPanics(t, func() { types.AssertValidValue([]byte{0x01}) })
|
||||
require.Panics(t, func() { types.AssertValidValue(nil) })
|
||||
}
|
||||
|
||||
func TestAssertValidValueGeneric(t *testing.T) {
|
||||
t.Parallel()
|
||||
bytesIsZero := func(b []byte) bool { return b == nil }
|
||||
bytesValueLen := func(b []byte) int { return len(b) }
|
||||
require.NotPanics(t, func() {
|
||||
types.AssertValidValueGeneric(
|
||||
[]byte{},
|
||||
bytesIsZero,
|
||||
bytesValueLen,
|
||||
)
|
||||
})
|
||||
require.NotPanics(t, func() {
|
||||
types.AssertValidValueGeneric(
|
||||
[]byte{0x1},
|
||||
bytesIsZero,
|
||||
bytesValueLen,
|
||||
)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
types.AssertValidValueGeneric(
|
||||
nil,
|
||||
bytesIsZero,
|
||||
bytesValueLen,
|
||||
)
|
||||
})
|
||||
require.Panics(t, func() {
|
||||
types.AssertValidValueGeneric(
|
||||
make([]byte, types.MaxValueLength+1),
|
||||
bytesIsZero,
|
||||
bytesValueLen,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ go 1.24.0
|
||||
|
||||
require (
|
||||
cosmossdk.io/math v1.5.3
|
||||
github.com/cometbft/cometbft v0.38.19
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685
|
||||
github.com/cosmos/cosmos-sdk v0.53.4
|
||||
github.com/creachadair/tomledit v0.0.29
|
||||
github.com/stretchr/testify v1.11.1
|
||||
@ -28,7 +28,6 @@ require (
|
||||
github.com/99designs/keyring v1.2.1 // indirect
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible // indirect
|
||||
github.com/DataDog/zstd v1.5.7 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.2.0 // indirect
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
@ -104,7 +103,7 @@ require (
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/linxGnu/grocksdb v1.9.8 // indirect
|
||||
github.com/linxGnu/grocksdb v1.10.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/minio/highwayhash v1.0.3 // indirect
|
||||
@ -112,7 +111,6 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20250813065127-a731cc31b4fe // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
@ -134,9 +132,10 @@ require (
|
||||
github.com/spf13/pflag v1.0.10 // indirect
|
||||
github.com/spf13/viper v1.21.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/supranational/blst v0.3.16 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
|
||||
github.com/tendermint/go-amino v0.16.0 // indirect
|
||||
github.com/tidwall/btree v1.7.0 // indirect
|
||||
github.com/tidwall/btree v1.8.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
@ -161,7 +160,7 @@ require (
|
||||
golang.org/x/term v0.36.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
@ -170,3 +169,7 @@ require (
|
||||
pgregory.net/rapid v1.2.0 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
|
||||
replace cosmossdk.io/store => ../store
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk => ../
|
||||
|
||||
@ -16,8 +16,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
|
||||
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
|
||||
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
|
||||
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
|
||||
cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o=
|
||||
cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A=
|
||||
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
|
||||
cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -44,8 +42,8 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX
|
||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
|
||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||
github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I=
|
||||
github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg=
|
||||
github.com/adlio/schema v1.3.9 h1:MLYk1VX1dn7xHW7Kdm1ywKKLjh19DRnrc65axS5xQA8=
|
||||
github.com/adlio/schema v1.3.9/go.mod h1:GnxXztHzNh6pIc7qm3sw+jsmHrXgBy/x2RBSkKZ3L4w=
|
||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@ -71,8 +69,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E=
|
||||
github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4=
|
||||
github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/bits-and-blooms/bitset v1.24.1 h1:hqnfFbjjk3pxGa5E9Ho3hjoU7odtUuNmJ9Ao+Bo8s1c=
|
||||
github.com/bits-and-blooms/bitset v1.24.1/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.5 h1:dpAlnAwmT1yIBm3exhT1/8iUSD98RDJM5vqJVQDQLiU=
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.5/go.mod h1:m22FrOAiuxl/tht9wIqAoGHcbnCCaPWyauO8y2LGGtQ=
|
||||
github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
|
||||
@ -131,8 +129,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/cometbft/cometbft v0.38.19 h1:vNdtCkvhuwUlrcLPAyigV7lQpmmo+tAq8CsB8gZjEYw=
|
||||
github.com/cometbft/cometbft v0.38.19/go.mod h1:UCu8dlHqvkAsmAFmWDRWNZJPlu6ya2fTWZlDrWsivwo=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685 h1:yv853Uyyhz68mtHr+AyOSimx/7qpuoEiAhc1Yp9Et1c=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685/go.mod h1:6Lt9liF9HxSth+zDotxtv94SuGMzRfuHmI287USgjlw=
|
||||
github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ=
|
||||
github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ=
|
||||
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
|
||||
@ -147,8 +145,6 @@ github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOP
|
||||
github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA=
|
||||
github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec=
|
||||
github.com/cosmos/cosmos-sdk v0.53.4 h1:kPF6vY68+/xi1/VebSZGpoxQqA52qkhUzqkrgeBn3Mg=
|
||||
github.com/cosmos/cosmos-sdk v0.53.4/go.mod h1:7U3+WHZtI44dEOnU46+lDzBb2tFh1QlMvi8Z5JugopI=
|
||||
github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY=
|
||||
github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw=
|
||||
github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE=
|
||||
@ -377,8 +373,9 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
@ -455,8 +452,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/linxGnu/grocksdb v1.9.8 h1:vOIKv9/+HKiqJAElJIEYv3ZLcihRxyP7Suu/Mu8Dxjs=
|
||||
github.com/linxGnu/grocksdb v1.9.8/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk=
|
||||
github.com/linxGnu/grocksdb v1.10.1 h1:YX6gUcKvSC3d0s9DaqgbU+CRkZHzlELgHu1Z/kmtslg=
|
||||
github.com/linxGnu/grocksdb v1.10.1/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk=
|
||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
@ -538,8 +535,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI=
|
||||
github.com/opencontainers/image-spec v1.1.0-rc5/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
|
||||
github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss=
|
||||
github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8=
|
||||
github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
|
||||
github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
|
||||
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
|
||||
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
@ -683,12 +680,14 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
|
||||
github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
|
||||
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
|
||||
github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
|
||||
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
|
||||
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
|
||||
github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA=
|
||||
github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@ -742,8 +741,8 @@ go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
@ -944,8 +943,8 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
|
||||
@ -233,6 +233,7 @@ require (
|
||||
// replace (
|
||||
// <temporary replace>
|
||||
// )
|
||||
replace cosmossdk.io/store => ../store
|
||||
|
||||
// Below are the long-lived replace for tests.
|
||||
replace (
|
||||
|
||||
@ -40,8 +40,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
|
||||
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
|
||||
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
|
||||
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
|
||||
cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o=
|
||||
cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A=
|
||||
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
|
||||
cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -479,8 +477,9 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
|
||||
@ -45,7 +45,7 @@ require (
|
||||
github.com/cockroachdb/pebble v1.1.5 // indirect
|
||||
github.com/cockroachdb/redact v1.1.6 // indirect
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb // indirect
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2 // indirect
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685 // indirect
|
||||
github.com/cometbft/cometbft-db v0.14.1 // indirect
|
||||
github.com/cosmos/btcutil v1.0.5 // indirect
|
||||
github.com/cosmos/cosmos-db v1.1.3 // indirect
|
||||
@ -176,3 +176,5 @@ require (
|
||||
pgregory.net/rapid v1.2.0 // indirect
|
||||
sigs.k8s.io/yaml v1.6.0 // indirect
|
||||
)
|
||||
|
||||
replace cosmossdk.io/store => ../../store
|
||||
|
||||
@ -16,8 +16,6 @@ cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U=
|
||||
cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ=
|
||||
cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE=
|
||||
cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI=
|
||||
cosmossdk.io/store v1.1.2 h1:3HOZG8+CuThREKv6cn3WSohAc6yccxO3hLzwK6rBC7o=
|
||||
cosmossdk.io/store v1.1.2/go.mod h1:60rAGzTHevGm592kFhiUVkNC9w7gooSEn5iUBPzHQ6A=
|
||||
cosmossdk.io/x/tx v0.14.0 h1:hB3O25kIcyDW/7kMTLMaO8Ripj3yqs5imceVd6c/heA=
|
||||
cosmossdk.io/x/tx v0.14.0/go.mod h1:Tn30rSRA1PRfdGB3Yz55W4Sn6EIutr9xtMKSHij+9PM=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
@ -131,8 +129,8 @@ github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZ
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb h1:3bCgBvB8PbJVMX1ouCcSIxvsqKPYM7gs72o0zC76n9g=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20250429170803-42689b6311bb/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2 h1:OfP4Qlw2L66xqvrNYSlVufYwXXP9frOPBnwYPyDttOk=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2/go.mod h1:6Lt9liF9HxSth+zDotxtv94SuGMzRfuHmI287USgjlw=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685 h1:yv853Uyyhz68mtHr+AyOSimx/7qpuoEiAhc1Yp9Et1c=
|
||||
github.com/cometbft/cometbft v0.39.0-beta.2.0.20251020144122-cd33e1fff685/go.mod h1:6Lt9liF9HxSth+zDotxtv94SuGMzRfuHmI287USgjlw=
|
||||
github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ=
|
||||
github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ=
|
||||
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
|
||||
@ -375,8 +373,9 @@ github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
|
||||
@ -351,6 +351,11 @@ func (c Context) TransientStore(key storetypes.StoreKey) storetypes.KVStore {
|
||||
return gaskv.NewStore(c.ms.GetKVStore(key), c.gasMeter, c.transientKVGasConfig)
|
||||
}
|
||||
|
||||
// ObjectStore fetches an object store from the MultiStore,
|
||||
func (c Context) ObjectStore(key storetypes.StoreKey) storetypes.ObjKVStore {
|
||||
return gaskv.NewObjStore(c.ms.GetObjKVStore(key), c.gasMeter, c.transientKVGasConfig)
|
||||
}
|
||||
|
||||
// CacheContext returns a new Context with the multi-store cached and a new
|
||||
// EventManager. The cached context is written to the context when writeCache
|
||||
// is called. Note, events are automatically emitted on the parent context's
|
||||
|
||||
@ -8,9 +8,13 @@ import (
|
||||
abci "github.com/cometbft/cometbft/abci/types"
|
||||
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
|
||||
cmttime "github.com/cometbft/cometbft/types/time"
|
||||
dbm "github.com/cosmos/cosmos-db"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"cosmossdk.io/log"
|
||||
"cosmossdk.io/store/metrics"
|
||||
"cosmossdk.io/store/rootmulti"
|
||||
storetypes "cosmossdk.io/store/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
@ -241,3 +245,15 @@ func (s *contextTestSuite) TestUnwrapSDKContext() {
|
||||
sdkCtx2 = types.UnwrapSDKContext(ctx)
|
||||
s.Require().Equal(sdkCtx, sdkCtx2)
|
||||
}
|
||||
|
||||
func (s *contextTestSuite) TestMultiStore() {
|
||||
db := dbm.NewMemDB()
|
||||
rms := rootmulti.NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics())
|
||||
ctx := types.NewContext(rms, cmtproto.Header{}, false, nil)
|
||||
|
||||
objKey := storetypes.NewObjectStoreKey("obj")
|
||||
rms.MountStoreWithDB(objKey, storetypes.StoreTypeObject, nil)
|
||||
s.Require().NoError(rms.LoadLatestVersion())
|
||||
objKVStore := ctx.ObjectStore(objKey)
|
||||
s.Require().Equal(objKVStore.GetStoreType(), storetypes.StoreTypeObject)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user