chore: remove v2 from 0.52 release branch (#23445)

Co-authored-by: aljo242 <alex@skip.money>
This commit is contained in:
Alex | Interchain Labs 2025-01-17 16:58:29 -05:00 committed by GitHub
parent 84186b07e1
commit 3a48b2941f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 31 additions and 13494 deletions

View File

@ -39,8 +39,6 @@ jobs:
- name: Build with Secp_cgo
if: matrix.go-arch == 'amd64'
run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS=secp make build
- name: Build v2 with sqlite backend
run: GOARCH=${{ matrix.go-arch }} COSMOS_BUILD_OPTIONS=v2,sqlite make build
###################
## Build Tooling ##
###################

View File

@ -531,48 +531,6 @@ jobs:
cd simapp
go test -mod=readonly -timeout 30m -tags='app_v1 norace ledger test_ledger_mock' ./...
test-simapp-v2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
- name: tests simapp
if: env.GIT_DIFF
run: |
cd simapp/v2
go test -mod=readonly -timeout 30m -tags='norace ledger test_ledger_mock' ./...
- name: simapp-v2-smoke-test
if: env.GIT_DIFF
run: |
COSMOS_BUILD_OPTIONS=v2 make install
./scripts/init-simapp-v2.sh
simdv2 start &
SIMD_PID=$!
cnt=0
while ! simdv2 query comet block --type=height 5; do
cnt=$((cnt + 1))
if [ $cnt -gt 30 ]; then
kill -9 "$SIMD_PID"
exit 1
fi
sleep 1
done
kill -9 "$SIMD_PID"
test-collections:
runs-on: ubuntu-latest
steps:

View File

@ -1,151 +0,0 @@
name: v2 core Tests
on:
pull_request:
merge_group:
push:
branches:
- main
permissions:
contents: read
concurrency:
group: ci-${{ github.ref }}-v2-tests
cancel-in-progress: true
jobs:
server-v2:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
server/v2/*.go
server/v2/go.mod
server/v2/go.sum
server/v2/testdata/*.toml
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cd server/v2 && go test -mod=readonly -race -timeout 30m -tags='ledger test_ledger_mock'
stf:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
server/v2/stf/**/*.go
server/v2/stf/go.mod
server/v2/stf/go.sum
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cd server/v2/stf && go test -mod=readonly -race -timeout 30m -tags='ledger test_ledger_mock'
appmanager:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
server/v2/appmanager/**/*.go
server/v2/appmanager/go.mod
server/v2/appmanager/go.sum
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cd server/v2/appmanager && go test -mod=readonly -race -timeout 30m -tags='ledger test_ledger_mock'
cometbft:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
server/v2/cometbft/**/*.go
server/v2/cometbft/go.mod
server/v2/cometbft/go.sum
- name: test & coverage report creation
if: env.GIT_DIFF
run: |
cd server/v2/cometbft && go test -mod=readonly -race -timeout 30m -tags='ledger test_ledger_mock'
test-system-v2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-tags: true
- uses: actions/setup-go@v5
with:
go-version: "1.23"
check-latest: true
cache: true
cache-dependency-path: |
simapp/v2/go.sum
systemtest/go.sum
- uses: technote-space/get-diff-action@v6.1.2
id: git_diff
with:
PATTERNS: |
**/*.go
go.mod
go.sum
**/go.mod
**/go.sum
**/Makefile
Makefile
- name: Install musl lib for simd (docker) binary
if: env.GIT_DIFF
run: |
sudo apt-get install -y musl
- name: system tests v2
if: env.GIT_DIFF
run: |
COSMOS_BUILD_OPTIONS=v2 make test-system
- uses: actions/upload-artifact@v4
if: failure()
with:
name: "testnet-setup"
path: ./systemtests/testnet/
retention-days: 3

View File

@ -52,6 +52,7 @@ Every module contains its own CHANGELOG.md. Please refer to the module you are i
### Improvements
* (all) [#23445](https://github.com/cosmos/cosmos-sdk/pull/23445) Remove `v2` code from codebase.
* (codec) [#22988](https://github.com/cosmos/cosmos-sdk/pull/22988) Improve edge case handling for recursion limits.
### Bug Fixes

View File

@ -62,23 +62,19 @@ The IBC module for the Cosmos SDK has its own [cosmos/ibc-go repository](https:/
The version matrix below shows which versions of the Cosmos SDK, modules and libraries are compatible with each other.
> [!IMPORTANT]
> Cosmos SDK `v2` corresponds to a chain using the `runtime/v2`, `server/v2/**`, and `store/v2` packages. The `github.com/cosmos/cosmos-sdk` module has a less important role in a `v2` chain.
#### Core Dependencies
Core dependencies are the core libraries that an application may depend on.
Core dependencies not mentioned here as compatible across all maintained SDK versions.
See an exhaustive list of core dependencies at [cosmossdk.io](https://cosmossdk.io).
| Version | v2 | 0.52.z | 0.50.z | 0.47.z |
| ------------------------ | ----- | --------- | -------------- | ------- |
| cosmossdk.io/core | 1.y.z | 1.y.z | 0.11.z | 0.5.z |
| cosmossdk.io/api | 0.8.z | 0.8.z | 0.7.z | 0.3.z |
| cosmossdk.io/x/tx | 1.y.z | 1.y.z | < 1.y.z | N/A |
| cosmossdk.io/store | N/A | >= 1.10.z | 1.0.0 >= 1.9.z | N/A |
| cosmossdk.io/store/v2 | 2.y.z | N/A | N/A | N/A |
| cosmossdk.io/collections | 1.y.z | 1.y.z | < 1.y.z | < 1.y.z |
| Version | 0.52.z | 0.50.z | 0.47.z |
|--------------------------|-----------|----------------|---------|
| cosmossdk.io/core | 1.y.z | 0.11.z | 0.5.z |
| cosmossdk.io/api | 0.8.z | 0.7.z | 0.3.z |
| cosmossdk.io/x/tx | 1.y.z | < 1.y.z | N/A |
| cosmossdk.io/store | >= 1.10.z | 1.0.0 >= 1.9.z | N/A |
| cosmossdk.io/collections | 1.y.z | < 1.y.z | < 1.y.z |
#### Module Dependencies
@ -88,24 +84,24 @@ Module Dependencies are the modules that an application may depend on and which
> X signals that the module was not spun out into its own go.mod file.
> N/A signals that the module was not available in the Cosmos SDK at that time.
| Cosmos SDK | v2 | 0.52.z | 0.50.z |
| --------------------------- | ----- | ------ | ------ |
| cosmossdk.io/x/accounts | 0.2.z | 0.2.z | N/A |
| cosmossdk.io/x/bank | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/circuit | 0.2.z | 0.2.z | 0.1.z |
| cosmossdk.io/x/consensus | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/distribution | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/epochs | 0.2.z | 0.2.z | N/A |
| cosmossdk.io/x/evidence | 0.2.z | 0.2.z | 0.1.z |
| cosmossdk.io/x/feegrant | 0.2.z | 0.2.z | 0.1.z |
| cosmossdk.io/x/gov | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/group | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/mint | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/nft | 0.2.z | 0.2.z | 0.1.z |
| cosmossdk.io/x/protocolpool | 0.2.z | 0.2.z | N/A |
| cosmossdk.io/x/slashing | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/staking | 0.2.z | 0.2.z | X |
| cosmossdk.io/x/upgrade | 0.2.z | 0.2.z | 0.1.z |
| Cosmos SDK | 0.52.z | 0.50.z |
|-----------------------------|--------|--------|
| cosmossdk.io/x/accounts | 0.2.z | N/A |
| cosmossdk.io/x/bank | 0.2.z | X |
| cosmossdk.io/x/circuit | 0.2.z | 0.1.z |
| cosmossdk.io/x/consensus | 0.2.z | X |
| cosmossdk.io/x/distribution | 0.2.z | X |
| cosmossdk.io/x/epochs | 0.2.z | N/A |
| cosmossdk.io/x/evidence | 0.2.z | 0.1.z |
| cosmossdk.io/x/feegrant | 0.2.z | 0.1.z |
| cosmossdk.io/x/gov | 0.2.z | X |
| cosmossdk.io/x/group | 0.2.z | X |
| cosmossdk.io/x/mint | 0.2.z | X |
| cosmossdk.io/x/nft | 0.2.z | 0.1.z |
| cosmossdk.io/x/protocolpool | 0.2.z | N/A |
| cosmossdk.io/x/slashing | 0.2.z | X |
| cosmossdk.io/x/staking | 0.2.z | X |
| cosmossdk.io/x/upgrade | 0.2.z | 0.1.z |
## Disambiguation

View File

@ -5,8 +5,6 @@ Note, always read the **SimApp** section for more information on application wir
## [v0.52.x](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.52.0-alpha.0)
Documentation to migrate an application from v0.50.x to server/v2 is available elsewhere.
It is additional to the changes described here.
### SimApp
@ -33,7 +31,7 @@ clientCtx = clientCtx.
**When using `depinject` / `app_di`, the client codecs can be provided directly from application config.**
Refer to SimApp `root_v2.go` and `root.go` for an example with an app di and a legacy app.
Refer to SimApp `root.go` for an example with an app di and a legacy app.
Additionally, a simplification of the start command leads to the following change:
@ -329,7 +327,7 @@ All modules (expect `auth`) were spun out into their own `go.mod`. Replace their
##### Core API
Core API has been introduced for modules since v0.47. With the deprecation of `sdk.Context`, we strongly recommend to use the `cosmossdk.io/core/appmodule` interfaces for the modules. This will allow the modules to work out of the box with server/v2 and baseapp, as well as limit their dependencies on the SDK.
Core API has been introduced for modules since v0.47. With the deprecation of `sdk.Context`, we strongly recommend to use the `cosmossdk.io/core/appmodule` interfaces for the modules. This will allow the modules to work out of the box with baseapp, as well as limit their dependencies on the SDK.
Additionally, the `appmodule.Environment` struct is introduced to fetch different services from the application.
This should be used as an alternative to using `sdk.UnwrapContext(ctx)` to fetch the services.
@ -465,9 +463,6 @@ Existing chains using `x/distribution` module must add the new `x/protocolpool`
#### `x/gov`
Gov v1beta1 proposal handler has been changed to take in a `context.Context` instead of `sdk.Context`.
This change was made to allow legacy proposals to be compatible with server/v2.
If you wish to migrate to server/v2, you should update your proposal handler to take in a `context.Context` and use services.
On the other hand, if you wish to keep using baseapp, simply unwrap the sdk context in your proposal handler.
#### `x/mint`
@ -510,7 +505,7 @@ storetypes.StoreUpgrades{
#### `x/validate`
Introducing `x/validate` a module that is solely used for registering default ante/post handlers and global tx validators when using runtime and runtime/v2. If you wish to set your custom ante/post handlers, no need to use this module.
Introducing `x/validate` a module that is solely used for registering default ante/post handlers and global tx validators when using runtime. If you wish to set your custom ante/post handlers, no need to use this module.
You can however always extend them by adding extra tx validators (see `x/validate` documentation).
#### `tools/benchmark`

View File

@ -1,50 +0,0 @@
# Upgrading Cosmos SDK v2 [DRAFT, see #22531](https://github.com/cosmos/cosmos-sdk/issues/22531)
This guide provides instructions for upgrading to specific versions of Cosmos SDK.
Note, always read the **SimApp** section for more information on application wiring updates.
## Upgrading from v0.52.x to v2.
First and foremost, v2 uses [depinject](./depinject/README.md) to wire the module and application dependencies.
This guide assumes that you have already made your modules depinject compatible, and that you made use of depinject in your application.
### Modules
### Server
### SimApp
With the migration to server/v2 and runtime/v2 some changes are required in the `root.go` and `app.go` of your application.
#### `app.go`
#### `root.go`
Thanks to the more modular design of v2, the application developer is free to pick which server to use in their application:
```go
// wire server commands
return serverv2.AddCommands[T](
rootCmd,
logger,
simApp,
deps.GlobalConfig,
initServerConfig(),
deps.ConsensusServer,
grpcServer,
storeComponent,
telemetryServer,
restServer,
grpcgatewayServer,
)
```
## Upgrading from v0.50.x to v2
Upgrading directly from v0.50.x to v2 is supported.
Modules should be updated to support all the latest changes in the SDK.
Read the module section from the v0.52 [UPGRADING.md](UPGRADING.md) file for more information.
Then simply follow the instructions from the [v0.52 section](#upgrading-from-v052x-to-v200) from this file.

View File

@ -1,33 +0,0 @@
<!--
Guiding Principles:
Changelogs are for humans, not machines.
There should be an entry for every single version.
The same types of changes should be grouped.
Versions and sections should be linkable.
The latest version comes first.
The release date of each version is displayed.
Mention whether you follow Semantic Versioning.
Usage:
Change log entries are to be added to the Unreleased section from newest to oldest.
Each entry must include the Github issue reference in the following format:
* [#<issue-number>] Changelog message.
-->
# Changelog
## [Unreleased]
## [v1.0.0-beta.2](https://github.com/cosmos/cosmos-sdk/releases/tag/server/v2/cometbft/v1.0.0-beta21)
* [#23365](https://github.com/cosmos/cosmos-sdk/pull/23365) Align default response for filter cmd when `handleQueryP2P`.
* [#23102](https://github.com/cosmos/cosmos-sdk/pull/23102) Pass `TxConfig` for `cosmos.tx.v1beta1.Service` handling.
* [#22517](https://github.com/cosmos/cosmos-sdk/pull/22517) Pass `AddressCodec` in indexer.
## [v1.0.0-beta.1](https://github.com/cosmos/cosmos-sdk/releases/tag/server/v2/cometbft/v1.0.0-beta.1)
Initial tag of `cosmossdk.io/server/v2/cometbft`.

View File

@ -1,711 +0,0 @@
package cometbft
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"strings"
"sync/atomic"
abci "github.com/cometbft/cometbft/abci/types"
abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1"
gogoproto "github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
"cosmossdk.io/collections"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/comet"
corecontext "cosmossdk.io/core/context"
"cosmossdk.io/core/event"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
errorsmod "cosmossdk.io/errors/v2"
"cosmossdk.io/log"
"cosmossdk.io/schema/appdata"
"cosmossdk.io/server/v2/appmanager"
"cosmossdk.io/server/v2/cometbft/handlers"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/server/v2/cometbft/oe"
"cosmossdk.io/server/v2/cometbft/types"
cometerrors "cosmossdk.io/server/v2/cometbft/types/errors"
"cosmossdk.io/server/v2/streaming"
"cosmossdk.io/store/v2/snapshots"
consensustypes "cosmossdk.io/x/consensus/types"
)
const (
QueryPathApp = "app"
QueryPathP2P = "p2p"
QueryPathStore = "store"
)
var _ abci.Application = (*consensus[transaction.Tx])(nil)
// consensus contains the implementation of the ABCI interface for CometBFT.
type consensus[T transaction.Tx] struct {
logger log.Logger
appName, version string
app appmanager.AppManager[T]
store types.Store
listener *appdata.Listener
snapshotManager *snapshots.Manager
streamingManager streaming.Manager
mempool mempool.Mempool[T]
appCodecs AppCodecs[T]
cfg Config
chainID string
indexedABCIEvents map[string]struct{}
initialHeight uint64
// this is only available after this node has committed a block (in FinalizeBlock),
// otherwise it will be empty and we will need to query the app for the last
// committed block.
lastCommittedHeight atomic.Int64
prepareProposalHandler handlers.PrepareHandler[T]
processProposalHandler handlers.ProcessHandler[T]
verifyVoteExt handlers.VerifyVoteExtensionHandler
extendVote handlers.ExtendVoteHandler
checkTxHandler handlers.CheckTxHandler[T]
// optimisticExec contains the context required for Optimistic Execution,
// including the goroutine handling.This is experimental and must be enabled
// by developers.
optimisticExec *oe.OptimisticExecution[T]
addrPeerFilter types.PeerFilter // filter peers by address and port
idPeerFilter types.PeerFilter // filter peers by node ID
queryHandlersMap map[string]appmodulev2.Handler
getProtoRegistry func() (*protoregistry.Files, error)
cfgMap server.ConfigMap
}
// CheckTx implements types.Application.
// It is called by cometbft to verify transaction validity
func (c *consensus[T]) CheckTx(ctx context.Context, req *abciproto.CheckTxRequest) (*abciproto.CheckTxResponse, error) {
decodedTx, err := c.appCodecs.TxCodec.Decode(req.Tx)
if err != nil {
return nil, err
}
if c.checkTxHandler == nil {
resp, err := c.app.ValidateTx(ctx, decodedTx)
// we do not want to return a cometbft error, but a check tx response with the error
if err != nil && !errors.Is(err, resp.Error) {
return nil, err
}
events := make([]abci.Event, 0)
if !c.cfg.AppTomlConfig.DisableABCIEvents {
events, err = intoABCIEvents(
resp.Events,
c.indexedABCIEvents,
c.cfg.AppTomlConfig.DisableIndexABCIEvents,
)
if err != nil {
return nil, err
}
}
cometResp := &abciproto.CheckTxResponse{
Code: 0,
GasWanted: uint64ToInt64(resp.GasWanted),
GasUsed: uint64ToInt64(resp.GasUsed),
Events: events,
}
if resp.Error != nil {
space, code, log := errorsmod.ABCIInfo(resp.Error, c.cfg.AppTomlConfig.Trace)
cometResp.Code = code
cometResp.Codespace = space
cometResp.Log = log
}
return cometResp, nil
}
return c.checkTxHandler(c.app.ValidateTx)
}
// Info implements types.Application.
func (c *consensus[T]) Info(ctx context.Context, _ *abciproto.InfoRequest) (*abciproto.InfoResponse, error) {
version, _, err := c.store.StateLatest()
if err != nil {
return nil, err
}
// if height is 0, we dont know the consensus params
var appVersion uint64 = 0
if version > 0 {
cp, err := GetConsensusParams(ctx, c.app)
// if the consensus params are not found, we set the app version to 0
// in the case that the start version is > 0
if cp == nil || errors.Is(err, collections.ErrNotFound) {
appVersion = 0
} else if err != nil {
return nil, err
} else {
appVersion = cp.Version.GetApp()
}
if err != nil {
return nil, err
}
}
cid, err := c.store.LastCommitID()
if err != nil {
return nil, err
}
return &abciproto.InfoResponse{
Data: c.appName,
Version: c.version,
AppVersion: appVersion,
LastBlockHeight: int64(version),
LastBlockAppHash: cid.Hash,
}, nil
}
// Query implements types.Application.
// It is called by cometbft to query application state.
func (c *consensus[T]) Query(ctx context.Context, req *abciproto.QueryRequest) (resp *abciproto.QueryResponse, err error) {
resp, isGRPC, err := c.maybeRunGRPCQuery(ctx, req)
if isGRPC {
return resp, err
}
// when a client did not provide a query height, manually inject the latest
// for modules queries, AppManager does it automatically
if req.Height == 0 {
latestVersion, err := c.store.GetLatestVersion()
if err != nil {
return nil, err
}
req.Height = int64(latestVersion)
}
// this error most probably means that we can't handle it with a proto message, so
// it must be an app/p2p/store query
path := splitABCIQueryPath(req.Path)
if len(path) == 0 {
return queryResult(errorsmod.Wrap(cometerrors.ErrUnknownRequest, "no query path provided"), c.cfg.AppTomlConfig.Trace), nil
}
switch path[0] {
case QueryPathApp:
resp, err = c.handleQueryApp(ctx, path, req)
case QueryPathStore:
resp, err = c.handleQueryStore(path, req)
case QueryPathP2P:
resp, err = c.handleQueryP2P(path)
default:
resp = queryResult(errorsmod.Wrapf(cometerrors.ErrUnknownRequest, "unknown query path %s", req.Path), c.cfg.AppTomlConfig.Trace)
}
if err != nil {
return queryResult(err, c.cfg.AppTomlConfig.Trace), nil
}
return resp, nil
}
func (c *consensus[T]) maybeRunGRPCQuery(ctx context.Context, req *abci.QueryRequest) (resp *abciproto.QueryResponse, isGRPC bool, err error) {
// if this fails then we cannot serve queries anymore
registry, err := c.getProtoRegistry()
if err != nil {
return nil, false, err
}
path := strings.TrimPrefix(req.Path, "/")
pathFullName := protoreflect.FullName(strings.ReplaceAll(path, "/", "."))
// in order to check if it's a gRPC query we ensure that there's a descriptor
// for the path, if such descriptor exists, and it is a method descriptor
// then we assume this is a gRPC query.
desc, err := registry.FindDescriptorByName(pathFullName)
if err != nil {
return nil, false, err
}
var handlerFullName string
md, isGRPC := desc.(protoreflect.MethodDescriptor)
if !isGRPC {
handlerFullName = string(desc.FullName())
} else {
handlerFullName = string(md.Input().FullName())
}
// special case for non-module services as they are external gRPC registered on the grpc server component
// and not on the app itself, so it won't pass the router afterwards.
externalResp, err := c.maybeHandleExternalServices(ctx, req)
if err != nil {
return nil, true, err
} else if externalResp != nil {
resp, err = queryResponse(externalResp, req.Height)
return resp, true, err
}
handler, found := c.queryHandlersMap[handlerFullName]
if !found {
return nil, true, fmt.Errorf("no query handler found for %s", req.Path)
}
protoRequest := handler.MakeMsg()
err = gogoproto.Unmarshal(req.Data, protoRequest) // TODO: use codec
if err != nil {
return nil, true, fmt.Errorf("unable to decode gRPC request with path %s from ABCI.Query: %w", req.Path, err)
}
res, err := c.app.Query(ctx, uint64(req.Height), protoRequest)
if err != nil {
resp := gRPCErrorToSDKError(err)
resp.Height = req.Height
return resp, true, nil
}
resp, err = queryResponse(res, req.Height)
return resp, true, err
}
// InitChain implements types.Application.
func (c *consensus[T]) InitChain(ctx context.Context, req *abciproto.InitChainRequest) (*abciproto.InitChainResponse, error) {
c.logger.Info("InitChain", "initialHeight", req.InitialHeight, "chainID", req.ChainId)
// store chainID to be used later on in execution
c.chainID = req.ChainId
// TODO: check if we need to load the config from genesis.json or config.toml
c.initialHeight = uint64(req.InitialHeight)
if c.initialHeight == 0 { // If initial height is 0, set it to 1
c.initialHeight = 1
}
if req.ConsensusParams != nil {
ctx = context.WithValue(ctx, corecontext.CometParamsInitInfoKey, &consensustypes.MsgUpdateParams{
Block: req.ConsensusParams.Block,
Evidence: req.ConsensusParams.Evidence,
Validator: req.ConsensusParams.Validator,
Abci: req.ConsensusParams.Abci,
Synchrony: req.ConsensusParams.Synchrony,
Feature: req.ConsensusParams.Feature,
})
}
ci, err := c.store.LastCommitID()
if err != nil {
return nil, err
}
// populate hash with empty byte slice instead of nil
bz := sha256.Sum256([]byte{})
br := &server.BlockRequest[T]{
Height: uint64(req.InitialHeight - 1),
Time: req.Time,
Hash: bz[:],
AppHash: ci.Hash,
ChainId: req.ChainId,
IsGenesis: true,
}
blockResponse, genesisState, err := c.app.InitGenesis(
ctx,
br,
req.AppStateBytes,
c.appCodecs.TxCodec)
if err != nil {
return nil, fmt.Errorf("genesis state init failure: %w", err)
}
for _, txRes := range blockResponse.TxResults {
if err := txRes.Error; err != nil {
space, code, txLog := errorsmod.ABCIInfo(err, c.cfg.AppTomlConfig.Trace)
c.logger.Warn("genesis tx failed", "codespace", space, "code", code, "log", txLog)
}
}
validatorUpdates := intoABCIValidatorUpdates(blockResponse.ValidatorUpdates)
if err := c.store.SetInitialVersion(uint64(req.InitialHeight - 1)); err != nil {
return nil, fmt.Errorf("failed to set initial version: %w", err)
}
stateChanges, err := genesisState.GetStateChanges()
if err != nil {
return nil, err
}
cs := &store.Changeset{
Version: uint64(req.InitialHeight - 1),
Changes: stateChanges,
}
stateRoot, err := c.store.Commit(cs)
if err != nil {
return nil, fmt.Errorf("unable to write the changeset: %w", err)
}
return &abciproto.InitChainResponse{
ConsensusParams: req.ConsensusParams,
Validators: validatorUpdates,
AppHash: stateRoot,
}, nil
}
// PrepareProposal implements types.Application.
// It is called by cometbft to prepare a proposal block.
func (c *consensus[T]) PrepareProposal(
ctx context.Context,
req *abciproto.PrepareProposalRequest,
) (resp *abciproto.PrepareProposalResponse, err error) {
if req.Height < 1 {
return nil, errors.New("PrepareProposal called with invalid height")
}
if c.prepareProposalHandler == nil {
return nil, errors.New("no prepare proposal function was set")
}
// Abort any running OE so it cannot overlap with `PrepareProposal`. This could happen if optimistic
// `internalFinalizeBlock` from previous round takes a long time, but consensus has moved on to next round.
// Overlap is undesirable, since `internalFinalizeBlock` and `PrepareProposal` could share access to
// in-memory structs depending on application implementation.
// No-op if OE is not enabled.
// Similar call to Abort() is done in `ProcessProposal`.
c.optimisticExec.Abort()
ciCtx := contextWithCometInfo(ctx, comet.Info{
Evidence: toCoreEvidence(req.Misbehavior),
ValidatorsHash: req.NextValidatorsHash,
ProposerAddress: req.ProposerAddress,
LastCommit: toCoreExtendedCommitInfo(req.LocalLastCommit),
})
txs, err := c.prepareProposalHandler(ciCtx, c.app, c.appCodecs.TxCodec, req, c.chainID)
if err != nil {
return nil, err
}
encodedTxs := make([][]byte, len(txs))
for i, tx := range txs {
encodedTxs[i] = tx.Bytes()
}
return &abciproto.PrepareProposalResponse{
Txs: encodedTxs,
}, nil
}
// ProcessProposal implements types.Application.
// It is called by cometbft to process/verify a proposal block.
func (c *consensus[T]) ProcessProposal(
ctx context.Context,
req *abciproto.ProcessProposalRequest,
) (*abciproto.ProcessProposalResponse, error) {
if req.Height < 1 {
return nil, errors.New("ProcessProposal called with invalid height")
}
if c.processProposalHandler == nil {
return nil, errors.New("no process proposal function was set")
}
// Since the application can get access to FinalizeBlock state and write to it,
// we must be sure to reset it in case ProcessProposal timeouts and is called
// again in a subsequent round. However, we only want to do this after we've
// processed the first block, as we want to avoid overwriting the finalizeState
// after state changes during InitChain.
if req.Height > int64(c.initialHeight) {
// abort any running OE
c.optimisticExec.Abort()
}
ciCtx := contextWithCometInfo(ctx, comet.Info{
Evidence: toCoreEvidence(req.Misbehavior),
ValidatorsHash: req.NextValidatorsHash,
ProposerAddress: req.ProposerAddress,
LastCommit: toCoreCommitInfo(req.ProposedLastCommit),
})
err := c.processProposalHandler(ciCtx, c.app, c.appCodecs.TxCodec, req, c.chainID)
if err != nil {
c.logger.Error("failed to process proposal", "height", req.Height, "time", req.Time, "hash", fmt.Sprintf("%X", req.Hash), "err", err)
return &abciproto.ProcessProposalResponse{
Status: abciproto.PROCESS_PROPOSAL_STATUS_REJECT,
}, nil
}
// Only execute optimistic execution if the proposal is accepted, OE is
// enabled and the block height is greater than the initial height. During
// the first block we'll be carrying state from InitChain, so it would be
// impossible for us to easily revert.
// After the first block has been processed, the next blocks will get executed
// optimistically, so that when the ABCI client calls `FinalizeBlock` the app
// can have a response ready.
if req.Height > int64(c.initialHeight) {
c.optimisticExec.Execute(req)
}
return &abciproto.ProcessProposalResponse{
Status: abciproto.PROCESS_PROPOSAL_STATUS_ACCEPT,
}, nil
}
// FinalizeBlock implements types.Application.
// It is called by cometbft to finalize a block.
func (c *consensus[T]) FinalizeBlock(
ctx context.Context,
req *abciproto.FinalizeBlockRequest,
) (*abciproto.FinalizeBlockResponse, error) {
var (
resp *server.BlockResponse
newState store.WriterMap
decodedTxs []T
err error
)
if c.optimisticExec.Initialized() {
// check if the hash we got is the same as the one we are executing
aborted := c.optimisticExec.AbortIfNeeded(req.Hash)
// Wait for the OE to finish, regardless of whether it was aborted or not
res, optimistErr := c.optimisticExec.WaitResult()
if !aborted {
if res != nil {
resp = res.Resp
newState = res.StateChanges
decodedTxs = res.DecodedTxs
}
if optimistErr != nil {
return nil, optimistErr
}
}
c.optimisticExec.Reset()
}
if resp == nil { // if we didn't run OE, run the normal finalize block
resp, newState, decodedTxs, err = c.internalFinalizeBlock(ctx, req)
if err != nil {
return nil, err
}
}
// after we get the changeset we can produce the commit hash,
// from the store.
stateChanges, err := newState.GetStateChanges()
if err != nil {
return nil, err
}
appHash, err := c.store.Commit(&store.Changeset{Version: uint64(req.Height), Changes: stateChanges})
if err != nil {
return nil, fmt.Errorf("unable to commit the changeset: %w", err)
}
var events []event.Event
events = append(events, resp.PreBlockEvents...)
events = append(events, resp.BeginBlockEvents...)
for _, tx := range resp.TxResults {
events = append(events, tx.Events...)
}
events = append(events, resp.EndBlockEvents...)
// listen to state streaming changes in accordance with the block
err = c.streamDeliverBlockChanges(ctx, req.Height, req.Txs, decodedTxs, resp.TxResults, events, stateChanges)
if err != nil {
return nil, err
}
// remove txs from the mempool
for _, tx := range decodedTxs {
if err = c.mempool.Remove(tx); err != nil {
return nil, fmt.Errorf("unable to remove tx: %w", err)
}
}
c.lastCommittedHeight.Store(req.Height)
cp, err := GetConsensusParams(ctx, c.app) // we get the consensus params from the latest state because we committed state above
if err != nil {
return nil, err
}
return finalizeBlockResponse(
resp,
cp,
appHash,
c.indexedABCIEvents,
c.cfg.AppTomlConfig,
)
}
func (c *consensus[T]) internalFinalizeBlock(
ctx context.Context,
req *abciproto.FinalizeBlockRequest,
) (*server.BlockResponse, store.WriterMap, []T, error) {
if err := c.validateFinalizeBlockHeight(req); err != nil {
return nil, nil, nil, err
}
if err := c.checkHalt(req.Height, req.Time); err != nil {
return nil, nil, nil, err
}
// TODO(tip): can we expect some txs to not decode? if so, what we do in this case? this does not seem to be the case,
// considering that prepare and process always decode txs, assuming they're the ones providing txs we should never
// have a tx that fails decoding.
decodedTxs, err := decodeTxs(c.logger, req.Txs, c.appCodecs.TxCodec)
if err != nil {
return nil, nil, nil, err
}
cid, err := c.store.LastCommitID()
if err != nil {
return nil, nil, nil, err
}
blockReq := &server.BlockRequest[T]{
Height: uint64(req.Height),
Time: req.Time,
Hash: req.Hash,
AppHash: cid.Hash,
ChainId: c.chainID,
Txs: decodedTxs,
}
ciCtx := contextWithCometInfo(ctx, comet.Info{
Evidence: toCoreEvidence(req.Misbehavior),
ValidatorsHash: req.NextValidatorsHash,
ProposerAddress: req.ProposerAddress,
LastCommit: toCoreCommitInfo(req.DecidedLastCommit),
})
resp, stateChanges, err := c.app.DeliverBlock(ciCtx, blockReq)
return resp, stateChanges, decodedTxs, err
}
// Commit implements types.Application.
// It is called by cometbft to notify the application that a block was committed.
func (c *consensus[T]) Commit(ctx context.Context, _ *abciproto.CommitRequest) (*abciproto.CommitResponse, error) {
lastCommittedHeight := c.lastCommittedHeight.Load()
c.snapshotManager.SnapshotIfApplicable(lastCommittedHeight)
cp, err := GetConsensusParams(ctx, c.app)
if err != nil {
return nil, err
}
return &abci.CommitResponse{
RetainHeight: c.GetBlockRetentionHeight(cp, lastCommittedHeight),
}, nil
}
// Vote extensions
// VerifyVoteExtension implements types.Application.
func (c *consensus[T]) VerifyVoteExtension(
ctx context.Context,
req *abciproto.VerifyVoteExtensionRequest,
) (*abciproto.VerifyVoteExtensionResponse, error) {
// If vote extensions are not enabled, as a safety precaution, we return an
// error.
cp, err := GetConsensusParams(ctx, c.app)
if err != nil {
return nil, err
}
// Note: we verify votes extensions on VoteExtensionsEnableHeight+1. Check
// comment in ExtendVote and ValidateVoteExtensions for more details.
// Since Abci was deprecated, should check both Feature & Abci
extsEnabled := cp.Feature.VoteExtensionsEnableHeight != nil && req.Height >= cp.Feature.VoteExtensionsEnableHeight.Value && cp.Feature.VoteExtensionsEnableHeight.Value != 0
if !extsEnabled {
// check abci params
extsEnabled = cp.Abci != nil && req.Height >= cp.Abci.VoteExtensionsEnableHeight && cp.Abci.VoteExtensionsEnableHeight != 0
if !extsEnabled {
return nil, fmt.Errorf("vote extensions are not enabled; unexpected call to VerifyVoteExtension at height %d", req.Height)
}
}
if c.verifyVoteExt == nil {
return nil, errors.New("vote extensions are enabled but no verify function was set")
}
_, latestStore, err := c.store.StateLatest()
if err != nil {
return nil, err
}
resp, err := c.verifyVoteExt(ctx, latestStore, req)
if err != nil {
c.logger.Error("failed to verify vote extension", "height", req.Height, "err", err)
return &abciproto.VerifyVoteExtensionResponse{Status: abciproto.VERIFY_VOTE_EXTENSION_STATUS_REJECT}, nil
}
return resp, err
}
// ExtendVote implements types.Application.
func (c *consensus[T]) ExtendVote(ctx context.Context, req *abciproto.ExtendVoteRequest) (*abciproto.ExtendVoteResponse, error) {
// If vote extensions are not enabled, as a safety precaution, we return an
// error.
cp, err := GetConsensusParams(ctx, c.app)
if err != nil {
return nil, err
}
// Note: In this case, we do want to extend vote if the height is equal or
// greater than VoteExtensionsEnableHeight. This defers from the check done
// in ValidateVoteExtensions and PrepareProposal in which we'll check for
// vote extensions on VoteExtensionsEnableHeight+1.
// Since Abci was deprecated, should check both Feature & Abci
extsEnabled := cp.Feature.VoteExtensionsEnableHeight != nil && req.Height >= cp.Feature.VoteExtensionsEnableHeight.Value && cp.Feature.VoteExtensionsEnableHeight.Value != 0
if !extsEnabled {
// check abci params
extsEnabled = cp.Abci != nil && req.Height >= cp.Abci.VoteExtensionsEnableHeight && cp.Abci.VoteExtensionsEnableHeight != 0
if !extsEnabled {
return nil, fmt.Errorf("vote extensions are not enabled; unexpected call to ExtendVote at height %d", req.Height)
}
}
if c.extendVote == nil {
return nil, errors.New("vote extensions are enabled but no extend function was set")
}
_, latestStore, err := c.store.StateLatest()
if err != nil {
return nil, err
}
resp, err := c.extendVote(ctx, latestStore, req)
if err != nil {
c.logger.Error("failed to extend vote", "height", req.Height, "err", err)
return &abciproto.ExtendVoteResponse{}, nil
}
return resp, err
}
func decodeTxs[T transaction.Tx](logger log.Logger, rawTxs [][]byte, codec transaction.Codec[T]) ([]T, error) {
txs := make([]T, len(rawTxs))
for i, rawTx := range rawTxs {
tx, err := codec.Decode(rawTx)
if err != nil {
// do not return an error here, as we want to deliver the block even if some txs are invalid
logger.Debug("failed to decode tx", "err", err)
txs[i] = RawTx(rawTx).(T) // allows getting the raw bytes down the line
continue
}
txs[i] = tx
}
return txs, nil
}

View File

@ -1,992 +0,0 @@
package cometbft
import (
"context"
"crypto/sha256"
"encoding/json"
"errors"
"io"
"reflect"
"strings"
"sync"
"testing"
"time"
abci "github.com/cometbft/cometbft/abci/types"
abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1"
v1 "github.com/cometbft/cometbft/api/cometbft/types/v1"
gogoproto "github.com/cosmos/gogoproto/proto"
gogotypes "github.com/cosmos/gogoproto/types"
"github.com/stretchr/testify/require"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
"cosmossdk.io/server/v2/appmanager"
"cosmossdk.io/server/v2/cometbft/handlers"
cometmock "cosmossdk.io/server/v2/cometbft/internal/mock"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/server/v2/cometbft/oe"
"cosmossdk.io/server/v2/cometbft/types"
"cosmossdk.io/server/v2/stf"
"cosmossdk.io/server/v2/stf/branch"
"cosmossdk.io/server/v2/stf/mock"
consensustypes "cosmossdk.io/x/consensus/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
sum = sha256.Sum256([]byte("test-hash"))
emptyHash = sha256.Sum256([]byte(""))
DefaulConsensusParams = &v1.ConsensusParams{
Block: &v1.BlockParams{
MaxGas: 5000000,
},
}
mockTx = mock.Tx{
Sender: []byte("sender"),
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 100_000,
}
invalidMockTx = mock.Tx{
Sender: []byte("sender"),
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 0,
}
actorName = []byte("cookies")
testAcc = sdk.AccAddress([]byte("addr1_______________"))
versionStr = "0.0.0"
)
func getQueryRouterBuilder[T any, PT interface {
*T
gogoproto.Message
},
U any, UT interface {
*U
gogoproto.Message
}](
t *testing.T,
handler func(ctx context.Context, msg PT) (UT, error),
) *stf.MsgRouterBuilder {
t.Helper()
queryRouterBuilder := stf.NewMsgRouterBuilder()
err := queryRouterBuilder.RegisterHandler(
gogoproto.MessageName(PT(new(T))),
func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(PT)
typedResp, err := handler(ctx, typedReq)
if err != nil {
return nil, err
}
return typedResp, nil
},
)
require.NoError(t, err)
return queryRouterBuilder
}
func getMsgRouterBuilder[T any, PT interface {
*T
transaction.Msg
},
U any, UT interface {
*U
transaction.Msg
}](
t *testing.T,
handler func(ctx context.Context, msg PT) (UT, error),
) *stf.MsgRouterBuilder {
t.Helper()
msgRouterBuilder := stf.NewMsgRouterBuilder()
err := msgRouterBuilder.RegisterHandler(
gogoproto.MessageName(PT(new(T))),
func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(PT)
typedResp, err := handler(ctx, typedReq)
if err != nil {
return nil, err
}
return typedResp, nil
},
)
require.NoError(t, err)
return msgRouterBuilder
}
func TestConsensus_InitChain_Without_UpdateParam(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
mockStore := c.store
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, 0)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, 1)
}
func TestConsensus_InitChain_With_UpdateParam(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
mockStore := c.store
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
ConsensusParams: DefaulConsensusParams,
InitialHeight: 1,
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, 0)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, 1)
}
func TestConsensus_InitChain_Invalid_Height(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
mockStore := c.store
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 2,
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, 1)
// Shouldn't be able to commit genesis block 3
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 3,
Hash: emptyHash[:],
})
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "invalid height"))
}
func TestConsensus_FinalizeBlock_Invalid_Height(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 3,
Hash: emptyHash[:],
})
require.Error(t, err)
}
func TestConsensus_FinalizeBlock_NoTxs(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
mockStore := c.store
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
endBlock := 10
for i := 2; i <= endBlock; i++ {
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: int64(i),
Hash: sum[:],
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, uint64(i))
}
require.Equal(t, int64(endBlock), c.lastCommittedHeight.Load())
}
func TestConsensus_FinalizeBlock_MultiTxs_OutOfGas(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
endBlock := 10
for i := 2; i <= endBlock; i++ {
res, err := c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: int64(i),
Hash: sum[:],
Txs: [][]byte{invalidMockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.NotEqual(t, res.TxResults[0].Code, 0)
}
require.Equal(t, int64(endBlock), c.lastCommittedHeight.Load())
}
func TestConsensus_FinalizeBlock_MultiTxs(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
mockStore := c.store
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
endBlock := 10
for i := 2; i <= endBlock; i++ {
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: int64(i),
Hash: sum[:],
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
assertStoreLatestVersion(t, mockStore, uint64(i))
}
require.Equal(t, int64(endBlock), c.lastCommittedHeight.Load())
}
func TestConsensus_CheckTx(t *testing.T) {
c := setUpConsensus(t, 0, mempool.NoOpMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
// empty byte
_, err = c.CheckTx(context.Background(), &abciproto.CheckTxRequest{
Tx: []byte{},
})
require.Error(t, err)
// out of gas
res, err := c.CheckTx(context.Background(), &abciproto.CheckTxRequest{
Tx: mock.Tx{
Sender: []byte("sender"),
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 100_000,
}.Bytes(),
})
require.NoError(t, err)
require.NotEqual(t, res.Code, 0)
c = setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
res, err = c.CheckTx(context.Background(), &abciproto.CheckTxRequest{
Tx: mock.Tx{
Sender: []byte("sender"),
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 100_000,
}.Bytes(),
})
require.NoError(t, err)
require.NotEqual(t, res.GasUsed, 0)
}
func TestConsensus_ExtendVote(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
ConsensusParams: &v1.ConsensusParams{
Block: &v1.BlockParams{
MaxGas: 5000000,
},
Feature: &v1.FeatureParams{
VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 2},
},
},
})
require.NoError(t, err)
// Votes not enabled yet
_, err = c.ExtendVote(context.Background(), &abciproto.ExtendVoteRequest{
Height: 1,
})
require.ErrorContains(t, err, "vote extensions are not enabled")
// Empty extendVote handler
_, err = c.ExtendVote(context.Background(), &abciproto.ExtendVoteRequest{
Height: 2,
})
require.ErrorContains(t, err, "no extend function was set")
// Use NoOp handler
c.extendVote = DefaultServerOptions[mock.Tx]().ExtendVoteHandler
res, err := c.ExtendVote(context.Background(), &abciproto.ExtendVoteRequest{
Height: 2,
})
require.NoError(t, err)
require.Equal(t, len(res.VoteExtension), 0)
}
func TestConsensus_VerifyVoteExtension(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
ConsensusParams: &v1.ConsensusParams{
Block: &v1.BlockParams{
MaxGas: 5000000,
},
Feature: &v1.FeatureParams{
VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 2},
},
},
})
require.NoError(t, err)
// Votes not enabled yet
_, err = c.VerifyVoteExtension(context.Background(), &abciproto.VerifyVoteExtensionRequest{
Height: 1,
})
require.ErrorContains(t, err, "vote extensions are not enabled")
// Empty verifyVote handler
_, err = c.VerifyVoteExtension(context.Background(), &abciproto.VerifyVoteExtensionRequest{
Height: 2,
})
require.ErrorContains(t, err, "no verify function was set")
// Use NoOp handler
c.verifyVoteExt = DefaultServerOptions[mock.Tx]().VerifyVoteExtensionHandler
res, err := c.VerifyVoteExtension(context.Background(), &abciproto.VerifyVoteExtensionRequest{
Height: 2,
Hash: []byte("test"),
})
require.NoError(t, err)
require.Equal(t, res.Status, abciproto.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT)
}
func TestConsensus_PrepareProposal(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
// Invalid height
_, err := c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 0,
})
require.Error(t, err)
// empty handler
_, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
})
require.Error(t, err)
// NoOp handler
c.prepareProposalHandler = DefaultServerOptions[mock.Tx]().PrepareProposalHandler
_, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
})
require.NoError(t, err)
}
func TestConsensus_PrepareProposal_With_Handler_NoOpMempool(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
c.prepareProposalHandler = handlers.NewDefaultProposalHandler(c.mempool).PrepareHandler()
// zero MaxTxBytes
res, err := c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 0,
Txs: [][]byte{mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 0)
// have tx exceed MaxTxBytes
// each mock tx has 128 bytes, should select 2 txs
res, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 300,
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 2)
// reach MaxTxBytes
res, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 256,
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 2)
// Over gas, under MaxTxBytes
// 300_000 gas limit, should only take 3 txs
res, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 1000,
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 3)
// Reach max gas
res, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 1000,
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 3)
// have a bad encoding tx
res, err = c.PrepareProposal(context.Background(), &abciproto.PrepareProposalRequest{
Height: 1,
MaxTxBytes: 1000,
Txs: [][]byte{mockTx.Bytes(), append(mockTx.Bytes(), []byte("bad")...), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, len(res.Txs), 2)
}
func TestConsensus_ProcessProposal(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
// Invalid height
_, err := c.ProcessProposal(context.Background(), &abciproto.ProcessProposalRequest{
Height: 0,
})
require.Error(t, err)
// empty handler
_, err = c.ProcessProposal(context.Background(), &abciproto.ProcessProposalRequest{
Height: 1,
})
require.Error(t, err)
// NoOp handler
// dummy optimistic execution
optimisticMockFunc := func(context.Context, *abci.FinalizeBlockRequest) (*server.BlockResponse, store.WriterMap, []mock.Tx, error) {
return nil, nil, nil, errors.New("test error")
}
c.optimisticExec = oe.NewOptimisticExecution[mock.Tx](log.NewNopLogger(), optimisticMockFunc)
c.processProposalHandler = DefaultServerOptions[mock.Tx]().ProcessProposalHandler
_, err = c.ProcessProposal(context.Background(), &abciproto.ProcessProposalRequest{
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
})
require.NoError(t, err)
}
func TestConsensus_ProcessProposal_With_Handler(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
c.processProposalHandler = handlers.NewDefaultProposalHandler(c.mempool).ProcessHandler()
// exceed max gas
res, err := c.ProcessProposal(context.Background(), &abciproto.ProcessProposalRequest{
Height: 1,
Txs: [][]byte{mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, res.Status, abciproto.PROCESS_PROPOSAL_STATUS_REJECT)
// have bad encode tx
// should reject
res, err = c.ProcessProposal(context.Background(), &abciproto.ProcessProposalRequest{
Height: 1,
Txs: [][]byte{mockTx.Bytes(), append(mockTx.Bytes(), []byte("bad")...), mockTx.Bytes(), mockTx.Bytes()},
})
require.NoError(t, err)
require.Equal(t, res.Status, abciproto.PROCESS_PROPOSAL_STATUS_REJECT)
}
func TestConsensus_Info(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
// Version 0
res, err := c.Info(context.Background(), &abciproto.InfoRequest{})
require.NoError(t, err)
require.Equal(t, res.LastBlockHeight, int64(0))
// Commit store to version 1
_, err = c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Hash: emptyHash[:],
})
require.NoError(t, err)
res, err = c.Info(context.Background(), &abciproto.InfoRequest{})
require.NoError(t, err)
require.Equal(t, res.LastBlockHeight, int64(1))
}
func TestConsensus_QueryStore(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
// Write data to state storage
err := c.store.GetStateCommitment().WriteChangeset(&store.Changeset{
Version: 1,
Changes: []store.StateChanges{
{
Actor: actorName,
StateChanges: []store.KVPair{
{
Key: []byte("key"),
Value: []byte("value"),
Remove: false,
},
},
},
},
})
require.NoError(t, err)
_, err = c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)
// empty request
res, err := c.Query(context.Background(), &abciproto.QueryRequest{})
require.NoError(t, err)
require.Equal(t, res.Code, uint32(1))
require.Contains(t, res.Log, "no query path provided")
// Query store
res, err = c.Query(context.Background(), &abciproto.QueryRequest{
Path: "store/cookies/",
Data: []byte("key"),
Height: 1,
})
require.NoError(t, err)
require.Equal(t, string(res.Value), "value")
// Query store with no value
res, err = c.Query(context.Background(), &abciproto.QueryRequest{
Path: "store/cookies/",
Data: []byte("exec"),
Height: 1,
})
require.NoError(t, err)
require.Equal(t, res.Value, []byte(nil))
}
func TestConsensus_GRPCQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)
// empty request
res, err := c.Query(context.Background(), &abciproto.QueryRequest{})
require.NoError(t, err)
require.Equal(t, res.Code, uint32(1))
require.Contains(t, res.Log, "no query path provided")
// query request not exist in handler map
invalidReq := testdata.EchoRequest{
Message: "echo",
}
invalidReqBz, err := invalidReq.Marshal()
require.NoError(t, err)
invalidQuery := abci.QueryRequest{
Data: invalidReqBz,
Path: "testpb.EchoRequest",
}
invalidRes, err := c.Query(context.TODO(), &invalidQuery)
require.Error(t, err)
require.Nil(t, invalidRes)
require.Contains(t, err.Error(), "no query handler found")
// Valid query
req := testdata.SayHelloRequest{Name: "foo"}
reqBz, err := req.Marshal()
require.NoError(t, err)
reqQuery := abci.QueryRequest{
Data: reqBz,
Path: "testpb.SayHelloRequest",
}
resQuery, err := c.Query(context.TODO(), &reqQuery)
require.NoError(t, err)
require.Equal(t, abci.CodeTypeOK, resQuery.Code, resQuery)
var response testdata.SayHelloResponse
require.NoError(t, response.Unmarshal(resQuery.Value))
require.Equal(t, "Hello foo!", response.Greeting)
}
func TestConsensus_P2PQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)
// empty request
res, err := c.Query(context.Background(), &abciproto.QueryRequest{})
require.NoError(t, err)
require.Equal(t, res.Code, uint32(1))
require.Contains(t, res.Log, "no query path provided")
addrQuery := abci.QueryRequest{
Path: "/p2p/filter/addr/1.1.1.1:8000",
}
res, err = c.Query(context.TODO(), &addrQuery)
require.NoError(t, err)
require.Equal(t, uint32(3), res.Code)
idQuery := abci.QueryRequest{
Path: "/p2p/filter/id/testid",
}
res, err = c.Query(context.TODO(), &idQuery)
require.NoError(t, err)
require.Equal(t, uint32(4), res.Code)
}
func TestConsensus_AppQuery(t *testing.T) {
c := setUpConsensus(t, 100_000, cometmock.MockMempool[mock.Tx]{})
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)
tx := mock.Tx{
Sender: testAcc,
Msg: &gogotypes.BoolValue{Value: true},
GasLimit: 1000,
}
txBytes := tx.Bytes()
// simulate by calling Query with encoded tx
query := abci.QueryRequest{
Path: "/app/simulate",
Data: txBytes,
}
queryResult, err := c.Query(context.TODO(), &query)
require.NoError(t, err)
require.True(t, queryResult.IsOK(), queryResult.Log)
// Query app version
res, err := c.Query(context.TODO(), &abci.QueryRequest{Path: "app/version"})
require.NoError(t, err)
require.True(t, res.IsOK())
require.Equal(t, versionStr, string(res.Value))
}
func setUpConsensus(t *testing.T, gasLimit uint64, mempool mempool.Mempool[mock.Tx]) *consensus[mock.Tx] {
t.Helper()
queryHandler := make(map[string]appmodulev2.Handler)
msgRouterBuilder := getMsgRouterBuilder(t, func(ctx context.Context, msg *gogotypes.BoolValue) (*gogotypes.BoolValue, error) {
return msg, nil
})
queryRouterBuilder := getQueryRouterBuilder(t, func(ctx context.Context, q *consensustypes.QueryParamsRequest) (*consensustypes.QueryParamsResponse, error) {
cParams := &v1.ConsensusParams{
Block: &v1.BlockParams{
MaxGas: 300000,
},
Feature: &v1.FeatureParams{
VoteExtensionsEnableHeight: &gogotypes.Int64Value{Value: 2},
},
}
return &consensustypes.QueryParamsResponse{
Params: cParams,
}, nil
})
helloFooHandler := func(ctx context.Context, msg transaction.Msg) (msgResp transaction.Msg, err error) {
typedReq := msg.(*testdata.SayHelloRequest)
handler := testdata.QueryImpl{}
typedResp, err := handler.SayHello(ctx, typedReq)
if err != nil {
return nil, err
}
return typedResp, nil
}
err := queryRouterBuilder.RegisterHandler(
gogoproto.MessageName(&testdata.SayHelloRequest{}),
helloFooHandler,
)
require.NoError(t, err)
queryHandler[gogoproto.MessageName(&testdata.SayHelloRequest{})] = appmodulev2.Handler{
Func: helloFooHandler,
MakeMsg: func() transaction.Msg {
return reflect.New(gogoproto.MessageType(gogoproto.MessageName(&testdata.SayHelloRequest{})).Elem()).Interface().(transaction.Msg)
},
MakeMsgResp: func() transaction.Msg {
return reflect.New(gogoproto.MessageType(gogoproto.MessageName(&testdata.SayHelloResponse{})).Elem()).Interface().(transaction.Msg)
},
}
s, err := stf.New(
log.NewNopLogger().With("module", "stf"),
msgRouterBuilder,
queryRouterBuilder,
func(ctx context.Context, txs []mock.Tx) error { return nil },
func(ctx context.Context) error {
return nil
},
func(ctx context.Context) error {
return nil
},
func(ctx context.Context, tx mock.Tx) error {
return nil
},
func(ctx context.Context) ([]appmodulev2.ValidatorUpdate, error) { return nil, nil },
func(ctx context.Context, tx mock.Tx, success bool) error {
return nil
},
branch.DefaultNewWriterMap,
)
require.NoError(t, err)
sc := cometmock.NewMockCommiter(log.NewNopLogger(), string(actorName), "stf")
mockStore := cometmock.NewMockStore(sc)
am := appmanager.New(appmanager.Config{
ValidateTxGasLimit: gasLimit,
QueryGasLimit: gasLimit,
SimulationGasLimit: gasLimit,
},
mockStore,
s,
func(ctx context.Context, src io.Reader, txHandler func(json.RawMessage) error) (store.WriterMap, []appmodulev2.ValidatorUpdate, error) {
_, st, err := mockStore.StateLatest()
require.NoError(t, err)
return branch.DefaultNewWriterMap(st), nil, nil
},
nil,
)
addrPeerFilter := func(info string) (*abci.QueryResponse, error) {
require.Equal(t, "1.1.1.1:8000", info)
return &abci.QueryResponse{Code: uint32(3)}, nil
}
idPeerFilter := func(id string) (*abci.QueryResponse, error) {
require.Equal(t, "testid", id)
return &abci.QueryResponse{Code: uint32(4)}, nil
}
return &consensus[mock.Tx]{
logger: log.NewNopLogger(),
appName: "testing-app",
app: am,
mempool: mempool,
store: mockStore,
cfg: Config{AppTomlConfig: DefaultAppTomlConfig()},
appCodecs: AppCodecs[mock.Tx]{
TxCodec: mock.TxCodec{},
},
chainID: "test",
getProtoRegistry: sync.OnceValues(gogoproto.MergedRegistry),
queryHandlersMap: queryHandler,
addrPeerFilter: addrPeerFilter,
idPeerFilter: idPeerFilter,
version: versionStr,
}
}
// Check target version same with store's latest version
// And should have commit info of target version
func assertStoreLatestVersion(t *testing.T, store types.Store, target uint64) {
t.Helper()
version, err := store.GetLatestVersion()
require.NoError(t, err)
require.Equal(t, target, version)
commitInfo, err := store.GetStateCommitment().GetCommitInfo(version)
require.NoError(t, err)
require.Equal(t, target, uint64(commitInfo.Version))
}
func TestOptimisticExecution(t *testing.T) {
c := setUpConsensus(t, 100_000, mempool.NoOpMempool[mock.Tx]{})
// Set up handlers
c.processProposalHandler = DefaultServerOptions[mock.Tx]().ProcessProposalHandler
// mock optimistic execution
calledTimes := 0
optimisticMockFunc := func(context.Context, *abci.FinalizeBlockRequest) (*server.BlockResponse, store.WriterMap, []mock.Tx, error) {
calledTimes++
return nil, nil, nil, errors.New("test error")
}
c.optimisticExec = oe.NewOptimisticExecution[mock.Tx](log.NewNopLogger(), optimisticMockFunc)
_, err := c.InitChain(context.Background(), &abciproto.InitChainRequest{
Time: time.Now(),
ChainId: "test",
InitialHeight: 1,
})
require.NoError(t, err)
_, err = c.FinalizeBlock(context.Background(), &abciproto.FinalizeBlockRequest{
Time: time.Now(),
Height: 1,
Txs: [][]byte{mockTx.Bytes()},
Hash: emptyHash[:],
})
require.NoError(t, err)
theHash := sha256.Sum256([]byte("test"))
ppReq := &abciproto.ProcessProposalRequest{
Height: 2,
Hash: theHash[:],
Time: time.Now(),
Txs: [][]byte{mockTx.Bytes()},
}
// Start optimistic execution
resp, err := c.ProcessProposal(context.Background(), ppReq)
require.NoError(t, err)
require.Equal(t, resp.Status, abciproto.PROCESS_PROPOSAL_STATUS_ACCEPT)
// Initialize FinalizeBlock with correct hash - should use optimistic result
theHash2 := sha256.Sum256([]byte("test"))
fbReq := &abciproto.FinalizeBlockRequest{
Height: 2,
Hash: theHash2[:],
Time: ppReq.Time,
Txs: ppReq.Txs,
}
fbResp, err := c.FinalizeBlock(context.Background(), fbReq)
require.Nil(t, fbResp)
require.Error(t, err)
require.ErrorContains(t, err, "test error") // from optimisticMockFunc
require.Equal(t, 1, calledTimes)
resp, err = c.ProcessProposal(context.Background(), ppReq)
require.NoError(t, err)
require.Equal(t, resp.Status, abciproto.PROCESS_PROPOSAL_STATUS_ACCEPT)
theWrongHash := sha256.Sum256([]byte("wrong_hash"))
fbReq.Hash = theWrongHash[:]
// Initialize FinalizeBlock with wrong hash - should abort optimistic execution
// Because is aborted, the result comes from the normal execution
fbResp, err = c.FinalizeBlock(context.Background(), fbReq)
require.NotNil(t, fbResp)
require.NoError(t, err)
require.Equal(t, 2, calledTimes)
// Verify optimistic execution was reset
require.False(t, c.optimisticExec.Initialized())
}

View File

@ -1,108 +0,0 @@
package rpc
import (
"context"
"encoding/hex"
"fmt"
cmttypes "github.com/cometbft/cometbft/api/cometbft/types/v1"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GetChainHeight returns the current blockchain height.
func GetChainHeight(ctx context.Context, rpcClient CometRPC) (int64, error) {
status, err := rpcClient.Status(ctx)
if err != nil {
return -1, err
}
height := status.SyncInfo.LatestBlockHeight
return height, nil
}
// QueryBlocks performs a search for blocks based on BeginBlock and EndBlock
// events via the CometBFT RPC. A custom query may be passed as described below:
//
// To tell which events you want, you need to provide a query. query is a
// string, which has a form: "condition AND condition ..." (no OR at the
// moment). condition has a form: "key operation operand". key is a string with
// a restricted set of possible symbols ( \t\n\r\\()"'=>< are not allowed).
// operation can be "=", "<", "<=", ">", ">=", "CONTAINS" AND "EXISTS". operand
// can be a string (escaped with single quotes), number, date or time.
// Examples:
// tm.event = 'NewBlock' # new blocks
// tm.event = 'CompleteProposal' # node got a complete proposal
// tm.event = 'Tx' AND tx.hash = 'XYZ' # single transaction
// tm.event = 'Tx' AND tx.height = 5 # all txs of the fifth block
// tx.height = 5 # all txs of the fifth block
//
// For more information, see the /subscribe CometBFT RPC endpoint documentation
func QueryBlocks(ctx context.Context, rpcClient CometRPC, page, limit int, query, orderBy string) (*sdk.SearchBlocksResult, error) {
resBlocks, err := rpcClient.BlockSearch(ctx, query, &page, &limit, orderBy)
if err != nil {
return nil, err
}
blocks, err := formatBlockResults(resBlocks.Blocks)
if err != nil {
return nil, err
}
totalPages := calcTotalPages(int64(resBlocks.TotalCount), int64(limit))
return &sdk.SearchBlocksResult{
TotalCount: int64(resBlocks.TotalCount),
Count: int64(len(blocks)),
PageNumber: int64(page),
PageTotal: totalPages,
Limit: int64(limit),
Blocks: blocks,
}, nil
}
// GetBlockByHeight gets block by height
func GetBlockByHeight(ctx context.Context, rpcClient CometRPC, height *int64) (*cmttypes.Block, error) {
// header -> BlockchainInfo
// header, tx -> Block
// results -> BlockResults
resBlock, err := rpcClient.Block(ctx, height)
if err != nil {
return nil, err
}
out, err := responseResultBlock(resBlock)
if err != nil {
return nil, err
}
if out == nil {
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
}
return out, nil
}
// GetBlockByHash gets block by hash
func GetBlockByHash(ctx context.Context, rpcClient CometRPC, hashHexString string) (*cmttypes.Block, error) {
hash, err := hex.DecodeString(hashHexString)
if err != nil {
return nil, err
}
resBlock, err := rpcClient.BlockByHash(ctx, hash)
if err != nil {
return nil, err
} else if resBlock.Block == nil {
return nil, fmt.Errorf("block not found with hash: %s", hashHexString)
}
out, err := responseResultBlock(resBlock)
if err != nil {
return nil, err
}
if out == nil {
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlock)
}
return out, nil
}

View File

@ -1,36 +0,0 @@
package rpc
import (
"context"
rpcclient "github.com/cometbft/cometbft/rpc/client"
coretypes "github.com/cometbft/cometbft/rpc/core/types"
)
// CometRPC defines the interface of a CometBFT RPC client needed for
// queries and transaction handling.
type CometRPC interface {
rpcclient.ABCIClient
Validators(ctx context.Context, height *int64, page, perPage *int) (*coretypes.ResultValidators, error)
Status(context.Context) (*coretypes.ResultStatus, error)
Block(ctx context.Context, height *int64) (*coretypes.ResultBlock, error)
BlockByHash(ctx context.Context, hash []byte) (*coretypes.ResultBlock, error)
BlockResults(ctx context.Context, height *int64) (*coretypes.ResultBlockResults, error)
BlockchainInfo(ctx context.Context, minHeight, maxHeight int64) (*coretypes.ResultBlockchainInfo, error)
Commit(ctx context.Context, height *int64) (*coretypes.ResultCommit, error)
Tx(ctx context.Context, hash []byte, prove bool) (*coretypes.ResultTx, error)
TxSearch(
ctx context.Context,
query string,
prove bool,
page, perPage *int,
orderBy string,
) (*coretypes.ResultTxSearch, error)
BlockSearch(
ctx context.Context,
query string,
page, perPage *int,
orderBy string,
) (*coretypes.ResultBlockSearch, error)
}

View File

@ -1,60 +0,0 @@
package rpc
import (
"fmt"
cmttypes "github.com/cometbft/cometbft/api/cometbft/types/v1"
coretypes "github.com/cometbft/cometbft/rpc/core/types"
gogoproto "github.com/cosmos/gogoproto/proto"
)
// formatBlockResults parses the indexed blocks into a slice of BlockResponse objects.
func formatBlockResults(resBlocks []*coretypes.ResultBlock) ([]*cmttypes.Block, error) {
var (
err error
out = make([]*cmttypes.Block, len(resBlocks))
)
for i := range resBlocks {
out[i], err = responseResultBlock(resBlocks[i])
if err != nil {
return nil, fmt.Errorf("unable to create response block from comet result block: %v: %w", resBlocks[i], err)
}
if out[i] == nil {
return nil, fmt.Errorf("unable to create response block from comet result block: %v", resBlocks[i])
}
}
return out, nil
}
// responseResultBlock returns a BlockResponse given a ResultBlock from CometBFT
func responseResultBlock(res *coretypes.ResultBlock) (*cmttypes.Block, error) {
blkProto, err := res.Block.ToProto()
if err != nil {
return nil, err
}
blkBz, err := gogoproto.Marshal(blkProto)
if err != nil {
return nil, err
}
blk := &cmttypes.Block{}
err = gogoproto.Unmarshal(blkBz, blk)
if err != nil {
return nil, err
}
return blk, nil
}
// calcTotalPages calculates total pages in an overflow safe manner
func calcTotalPages(totalCount, limit int64) int64 {
totalPages := int64(0)
if totalCount != 0 && limit != 0 {
if totalCount%limit > 0 {
totalPages = totalCount/limit + 1
} else {
totalPages = totalCount / limit
}
}
return totalPages
}

View File

@ -1,435 +0,0 @@
package cometbft
import (
"encoding/json"
"errors"
"fmt"
"strconv"
"strings"
cmtcfg "github.com/cometbft/cometbft/config"
cmtjson "github.com/cometbft/cometbft/libs/json"
"github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/p2p"
pvm "github.com/cometbft/cometbft/privval"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
cmtversion "github.com/cometbft/cometbft/version"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
"cosmossdk.io/server/v2/cometbft/client/rpc"
"github.com/cosmos/cosmos-sdk/client"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
"github.com/cosmos/cosmos-sdk/version"
)
func rpcClient(cmd *cobra.Command) (rpc.CometRPC, error) {
rpcURI, err := cmd.Flags().GetString(FlagNode)
if err != nil {
return nil, err
}
if rpcURI == "" {
return nil, fmt.Errorf("rpc URI is empty")
}
return rpchttp.New(rpcURI)
}
// StatusCommand returns the command to return the status of the network.
func StatusCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "Query remote node for status",
RunE: func(cmd *cobra.Command, _ []string) error {
rpcclient, err := rpcClient(cmd)
if err != nil {
return err
}
status, err := rpcclient.Status(cmd.Context())
if err != nil {
return err
}
output, err := cmtjson.Marshal(status)
if err != nil {
return err
}
return printOutput(cmd, output)
},
}
cmd.Flags().StringP(FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
cmd.Flags().StringP(FlagOutput, "o", "json", "Output format (text|json)")
return cmd
}
// ShowNodeIDCmd - ported from CometBFT, dump node ID to stdout
func ShowNodeIDCmd() *cobra.Command {
return &cobra.Command{
Use: "show-node-id",
Short: "Show this node's ID",
RunE: func(cmd *cobra.Command, args []string) error {
cmtConfig := client.GetConfigFromCmd(cmd)
nodeKey, err := p2p.LoadNodeKey(cmtConfig.NodeKeyFile())
if err != nil {
return err
}
cmd.Println(nodeKey.ID())
return nil
},
}
}
// ShowValidatorCmd - ported from CometBFT, show this node's validator info
func ShowValidatorCmd() *cobra.Command {
cmd := cobra.Command{
Use: "show-validator",
Short: "Show this node's CometBFT validator info",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := client.GetConfigFromCmd(cmd)
privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile())
pk, err := privValidator.GetPubKey()
if err != nil {
return err
}
sdkPK, err := cryptocodec.FromCmtPubKeyInterface(pk)
if err != nil {
return err
}
clientCtx := client.GetClientContextFromCmd(cmd)
bz, err := clientCtx.Codec.MarshalInterfaceJSON(sdkPK)
if err != nil {
return err
}
cmd.Println(string(bz))
return nil
},
}
return &cmd
}
// ShowAddressCmd - show this node's validator address
func ShowAddressCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show-address",
Short: "Shows this node's CometBFT validator consensus address",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := client.GetConfigFromCmd(cmd)
privValidator := pvm.LoadFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile())
// TODO: use address codec?
valConsAddr := (sdk.ConsAddress)(privValidator.GetAddress())
cmd.Println(valConsAddr.String())
return nil
},
}
return cmd
}
// VersionCmd prints CometBFT and ABCI version numbers.
func VersionCmd() *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Print CometBFT libraries' version",
Long: "Print protocols' and libraries' version numbers against which this app has been compiled.",
RunE: func(cmd *cobra.Command, args []string) error {
bs, err := yaml.Marshal(&struct {
CometBFT string
ABCI string
BlockProtocol uint64
P2PProtocol uint64
}{
CometBFT: cmtversion.CMTSemVer,
ABCI: cmtversion.ABCIVersion,
BlockProtocol: cmtversion.BlockProtocol,
P2PProtocol: cmtversion.P2PProtocol,
})
if err != nil {
return err
}
cmd.Println(string(bs))
return nil
},
}
}
// QueryBlocksCmd returns a command to search through blocks by events.
func QueryBlocksCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "blocks",
Short: "Query for paginated blocks that match a set of events",
Long: `Search for blocks that match the exact given events where results are paginated.
The events query is directly passed to CometBFT's RPC BlockSearch method and must
conform to CometBFT's query syntax.
Please refer to each module's documentation for the full set of events to query
for. Each module documents its respective events under 'xx_events.md'.
`,
Example: fmt.Sprintf(
"$ %s query blocks --query \"message.sender='cosmos1...' AND block.height > 7\" --page 1 --limit 30 --order_by asc",
version.AppName,
),
RunE: func(cmd *cobra.Command, args []string) error {
rpcclient, err := rpcClient(cmd)
if err != nil {
return err
}
query, _ := cmd.Flags().GetString(FlagQuery)
page, _ := cmd.Flags().GetInt(FlagPage)
limit, _ := cmd.Flags().GetInt(FlagLimit)
orderBy, _ := cmd.Flags().GetString(FlagOrderBy)
blocks, err := rpc.QueryBlocks(cmd.Context(), rpcclient, page, limit, query, orderBy)
if err != nil {
return err
}
bz, err := gogoproto.Marshal(blocks)
if err != nil {
return err
}
return printOutput(cmd, bz)
},
}
AddQueryFlagsToCmd(cmd)
cmd.Flags().Int(FlagPage, query.DefaultPage, "Query a specific page of paginated results")
cmd.Flags().Int(FlagLimit, query.DefaultLimit, "Query number of transactions results per page returned")
cmd.Flags().String(FlagQuery, "", "The blocks events query per CometBFT's query semantics")
cmd.Flags().String(FlagOrderBy, "", "The ordering semantics (asc|dsc)")
_ = cmd.MarkFlagRequired(FlagQuery)
return cmd
}
// QueryBlockCmd implements the default command for a Block query.
func QueryBlockCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "block --type={height|hash} [height|hash]",
Short: "Query for a committed block by height, hash, or event(s)",
Long: "Query for a specific committed block using the CometBFT RPC `block` and `block_by_hash` method",
Example: strings.TrimSpace(fmt.Sprintf(`
$ %s query block --%s=%s <height>
$ %s query block --%s=%s <hash>
`,
version.AppName, FlagType, TypeHeight,
version.AppName, FlagType, TypeHash)),
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
rpcclient, err := rpcClient(cmd)
if err != nil {
return err
}
typ, _ := cmd.Flags().GetString(FlagType)
if len(args) == 0 {
// do not break default v0.50 behavior of block hash
// if no args are provided, set the type to height
typ = TypeHeight
}
switch typ {
case TypeHeight:
var (
err error
height int64
)
heightStr := ""
if len(args) > 0 {
heightStr = args[0]
}
if heightStr == "" {
cmd.Println("Falling back to latest block height:")
height, err = rpc.GetChainHeight(cmd.Context(), rpcclient)
if err != nil {
return fmt.Errorf("failed to get chain height: %w", err)
}
} else {
height, err = strconv.ParseInt(heightStr, 10, 64)
if err != nil {
return fmt.Errorf("failed to parse block height: %w", err)
}
}
output, err := rpc.GetBlockByHeight(cmd.Context(), rpcclient, &height)
if err != nil {
return err
}
if output.Header.Height == 0 {
return fmt.Errorf("no block found with height %s", args[0])
}
bz, err := json.Marshal(output)
if err != nil {
return err
}
return printOutput(cmd, bz)
case TypeHash:
if args[0] == "" {
return errors.New("argument should be a tx hash")
}
// If hash is given, then query the tx by hash.
output, err := rpc.GetBlockByHash(cmd.Context(), rpcclient, args[0])
if err != nil {
return err
}
if output.Header.AppHash == nil {
return fmt.Errorf("no block found with hash %s", args[0])
}
bz, err := json.Marshal(output)
if err != nil {
return err
}
return printOutput(cmd, bz)
default:
return fmt.Errorf("unknown --%s value %s", FlagType, typ)
}
},
}
AddQueryFlagsToCmd(cmd)
cmd.Flags().String(FlagType, TypeHash, fmt.Sprintf("The type to be used when querying tx, can be one of \"%s\", \"%s\"", TypeHeight, TypeHash))
return cmd
}
// QueryBlockResultsCmd implements the default command for a BlockResults query.
func QueryBlockResultsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "block-results [height]",
Short: "Query for a committed block's results by height",
Long: "Query for a specific committed block's results using the CometBFT RPC `block_results` method",
Args: cobra.RangeArgs(0, 1),
RunE: func(cmd *cobra.Command, args []string) error {
node, err := rpcClient(cmd)
if err != nil {
return err
}
// optional height
var height *int64
if len(args) > 0 {
height, err = parseOptionalHeight(args[0])
if err != nil {
return err
}
}
blockRes, err := node.BlockResults(cmd.Context(), height)
if err != nil {
return err
}
// coretypes.ResultBlockResults doesn't implement proto.Message interface
// so we can't print it using clientCtx.PrintProto
// we choose to serialize it to json and print the json instead
blockResStr, err := json.Marshal(blockRes)
if err != nil {
return err
}
return printOutput(cmd, blockResStr)
},
}
AddQueryFlagsToCmd(cmd)
return cmd
}
func parseOptionalHeight(heightStr string) (*int64, error) {
h, err := strconv.Atoi(heightStr)
if err != nil {
return nil, err
}
if h == 0 {
return nil, nil
}
tmp := int64(h)
return &tmp, nil
}
func (s *CometBFTServer[T]) BootstrapStateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bootstrap-state",
Short: "Bootstrap CometBFT state at an arbitrary block height using a light client",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
cfg := client.GetConfigFromCmd(cmd)
height, err := cmd.Flags().GetUint64("height")
if err != nil {
return err
}
if height == 0 {
height, err = s.store.GetLatestVersion()
if err != nil {
return err
}
}
// TODO genensis doc provider and apphash
return node.BootstrapState(cmd.Context(), cfg, cmtcfg.DefaultDBProvider, nil, height, nil)
},
}
cmd.Flags().Int64("height", 0, "Block height to bootstrap state at, if not provided it uses the latest block height in app state")
return cmd
}
func printOutput(cmd *cobra.Command, out []byte) error {
// Get flags output
outFlag, err := cmd.Flags().GetString(FlagOutput)
if err != nil {
return err
}
if outFlag == "text" {
out, err = yaml.JSONToYAML(out)
if err != nil {
return err
}
}
writer := cmd.OutOrStdout()
_, err = writer.Write(out)
if err != nil {
return err
}
if outFlag != "text" {
// append new-line for formats besides YAML
_, err = writer.Write([]byte("\n"))
if err != nil {
return err
}
}
return nil
}

View File

@ -1,68 +0,0 @@
package cometbft
import (
cmtcfg "github.com/cometbft/cometbft/config"
"cosmossdk.io/schema/indexer"
"cosmossdk.io/server/v2/cometbft/mempool"
)
// Config is the configuration for the CometBFT application
type Config struct {
AppTomlConfig *AppTomlConfig
ConfigTomlConfig *cmtcfg.Config
}
func DefaultAppTomlConfig() *AppTomlConfig {
return &AppTomlConfig{
MinRetainBlocks: 0,
HaltHeight: 0,
HaltTime: 0,
Address: "tcp://127.0.0.1:26658",
Transport: "socket",
Trace: false,
Standalone: false,
Mempool: mempool.DefaultConfig(),
Indexer: indexer.IndexingConfig{
Target: make(map[string]indexer.Config),
ChannelBufferSize: 1024,
},
IndexABCIEvents: make([]string, 0),
DisableIndexABCIEvents: false,
DisableABCIEvents: false,
}
}
type AppTomlConfig struct {
MinRetainBlocks uint64 `mapstructure:"min-retain-blocks" toml:"min-retain-blocks" comment:"min-retain-blocks defines the minimum block height offset from the current block being committed, such that all blocks past this offset are pruned from CometBFT. A value of 0 indicates that no blocks should be pruned."`
HaltHeight uint64 `mapstructure:"halt-height" toml:"halt-height" comment:"halt-height contains a non-zero block height at which a node will gracefully halt and shutdown that can be used to assist upgrades and testing."`
HaltTime uint64 `mapstructure:"halt-time" toml:"halt-time" comment:"halt-time contains a non-zero minimum block time (in Unix seconds) at which a node will gracefully halt and shutdown that can be used to assist upgrades and testing."`
Address string `mapstructure:"address" toml:"address" comment:"address defines the CometBFT RPC server address to bind to."`
Transport string `mapstructure:"transport" toml:"transport" comment:"transport defines the CometBFT RPC server transport protocol: socket, grpc"`
Trace bool `mapstructure:"trace" toml:"trace" comment:"trace enables the CometBFT RPC server to output trace information about its internal operations."`
Standalone bool `mapstructure:"standalone" toml:"standalone" comment:"standalone starts the application without the CometBFT node. The node should be started separately."`
// Sub configs
Mempool mempool.Config `mapstructure:"mempool" toml:"mempool" comment:"mempool defines the configuration for the SDK built-in app-side mempool implementations."`
Indexer indexer.IndexingConfig `mapstructure:"indexer" toml:"indexer" comment:"indexer defines the configuration for the SDK built-in indexer implementation."`
IndexABCIEvents []string `mapstructure:"index-abci-events" toml:"index-abci-events" comment:"index-abci-events defines the set of events in the form {eventType}.{attributeKey}, which informs CometBFT what to index. If empty, all events will be indexed."`
DisableIndexABCIEvents bool `mapstructure:"disable-index-abci-events" toml:"disable-index-abci-events" comment:"disable-index-abci-events disables the ABCI event indexing done by CometBFT. Useful when relying on the SDK indexer for event indexing, but still want events to be included in FinalizeBlockResponse."`
DisableABCIEvents bool `mapstructure:"disable-abci-events" toml:"disable-abci-events" comment:"disable-abci-events disables all ABCI events. Useful when relying on the SDK indexer for event indexing."`
}
// CfgOption is a function that allows to overwrite the default server configuration.
type CfgOption func(*Config)
// OverwriteDefaultConfigTomlConfig overwrites the default comet config with the new config.
func OverwriteDefaultConfigTomlConfig(newCfg *cmtcfg.Config) CfgOption {
return func(cfg *Config) {
cfg.ConfigTomlConfig = newCfg
}
}
// OverwriteDefaultAppTomlConfig overwrites the default comet config with the new config.
func OverwriteDefaultAppTomlConfig(newCfg *AppTomlConfig) CfgOption {
return func(cfg *Config) {
cfg.AppTomlConfig = newCfg
}
}

View File

@ -1,61 +0,0 @@
package cometbft
import (
"fmt"
"github.com/spf13/cobra"
)
// Query flags
const (
FlagQuery = "query"
FlagType = "type"
FlagOrderBy = "order_by"
FlagChainID = "chain-id"
FlagNode = "node"
FlagGRPC = "grpc-addr"
FlagGRPCInsecure = "grpc-insecure"
FlagHeight = "height"
FlagPage = "page"
FlagLimit = "limit"
FlagOutput = "output"
TypeHash = "hash"
TypeHeight = "height"
)
// List of supported output formats
const (
OutputFormatJSON = "json"
OutputFormatText = "text"
)
// AddQueryFlagsToCmd adds common flags to a module query command.
func AddQueryFlagsToCmd(cmd *cobra.Command) {
cmd.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to CometBFT RPC interface for this chain")
cmd.Flags().String(FlagGRPC, "", "the gRPC endpoint to use for this chain")
cmd.Flags().Bool(FlagGRPCInsecure, false, "allow gRPC over insecure channels, if not the server must use TLS")
cmd.Flags().Int64(FlagHeight, 0, "Use a specific height to query state at (this can error if the node is pruning state)")
cmd.Flags().StringP(FlagOutput, "o", OutputFormatText, "Output format (text|json)")
// some base commands does not require chainID e.g `simd testnet` while subcommands do
// hence the flag should not be required for those commands
_ = cmd.MarkFlagRequired(FlagChainID)
}
// start flags are prefixed with the server name
// as the config in prefixed with the server name
// this allows viper to properly bind the flags
func prefix(f string) string {
return fmt.Sprintf("%s.%s", ServerName, f)
}
// Server flags
var (
Standalone = prefix("standalone")
FlagAddress = prefix("address")
FlagTransport = prefix("transport")
FlagHaltHeight = prefix("halt-height")
FlagHaltTime = prefix("halt-time")
FlagTrace = prefix("trace")
FlagMempoolMaxTxs = prefix("mempool.max-txs")
)

View File

@ -1,182 +0,0 @@
module cosmossdk.io/server/v2/cometbft
go 1.23.4
replace github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.52.0-rc.1
require (
cosmossdk.io/api v0.8.2
cosmossdk.io/collections v1.0.0
cosmossdk.io/core v1.0.0
cosmossdk.io/errors v1.0.1
cosmossdk.io/errors/v2 v2.0.0
cosmossdk.io/log v1.5.0
cosmossdk.io/schema v1.0.0 //main
cosmossdk.io/server/v2 v2.0.0-beta.2 // main
cosmossdk.io/server/v2/appmanager v1.0.0-beta.2 // main
cosmossdk.io/server/v2/stf v1.0.0-beta.2 // main
cosmossdk.io/store/v2 v2.0.0-beta.1.0.20250113105648-064c9ba6385a // main
cosmossdk.io/x/consensus v0.2.0-rc.1
github.com/cometbft/cometbft v1.0.0
github.com/cometbft/cometbft/api v1.0.0
github.com/cosmos/cosmos-sdk v0.52.0
github.com/cosmos/gogoproto v1.7.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.10.0
google.golang.org/grpc v1.69.4
google.golang.org/protobuf v1.36.2
sigs.k8s.io/yaml v1.4.0
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.2-20241120201313-68e42a58b301.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.2-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/core/testing v0.0.1 // indirect
cosmossdk.io/depinject v1.1.0 // indirect
cosmossdk.io/math v1.5.0 // indirect
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 // indirect
cosmossdk.io/x/bank v0.2.0-rc.1 // indirect
cosmossdk.io/x/staking v0.2.0-rc.1 // indirect
cosmossdk.io/x/tx v1.0.0 // indirect; main
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.2.0 // indirect
github.com/bvinc/go-sqlite-lite v0.6.1 // indirect
github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.2 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft-db v1.0.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/iavl v1.3.4 // indirect
github.com/cosmos/iavl/v2 v2.0.0-alpha.4 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.0 // indirect
github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/huandu/skiplist v1.2.1 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/kocubinski/costor-api v1.1.1 // indirect
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.3 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/highwayhash v1.0.3 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
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/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.61.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.13 // 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/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v1.0.0 // indirect
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.etcd.io/bbolt v1.4.0-alpha.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.12.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.27.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
pgregory.net/rapid v1.1.0 // indirect
)

View File

@ -1,782 +0,0 @@
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.2-20241120201313-68e42a58b301.1 h1:72N6FvGkvIAHJFuW6BFXCThbTS2qo/PlzQuw7wSjUi8=
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.2-20241120201313-68e42a58b301.1/go.mod h1:UJ1nx2WHcWAvKiaem512kYlHektAZJ/eNU032Pdar70=
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.2-20240130113600-88ef6483f90f.1 h1:LFgdGZ+BzNqHWsndyRvvFE1450BBZ2nFtyNEGZ9NOSg=
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.2-20240130113600-88ef6483f90f.1/go.mod h1:cuOHNO5SRU1J25UoI8VvPyi8dq9BpZb4gKa01Umx57Y=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cosmossdk.io/api v0.8.2 h1:klzA1RODd9tTawJ2CbBd/34RV/cB9qtd9oJN6rcRqqg=
cosmossdk.io/api v0.8.2/go.mod h1:XJUwQrihIDjErzs3+jm1zO/9KRzKf4HMjRzXC+l+Cio=
cosmossdk.io/collections v1.0.0 h1:YCYIe/pIMtc1iLDD0OrVdfWCnIkpwdy7k9NSQpaR5mg=
cosmossdk.io/collections v1.0.0/go.mod h1:mFfLxnYT1fV+B3Lx9GLap1qxmffIPqQCND4xBExerps=
cosmossdk.io/core v1.0.0 h1:e7XBbISOytLBOXMVwpRPixThXqEkeLGlg8no/qpgS8U=
cosmossdk.io/core v1.0.0/go.mod h1:mKIp3RkoEmtqdEdFHxHwWAULRe+79gfdOvmArrLDbDc=
cosmossdk.io/core/testing v0.0.1 h1:gYCTaftcRrz+HoNXmK7r9KgbG1jgBJ8pNzm/Pa/erFQ=
cosmossdk.io/core/testing v0.0.1/go.mod h1:2VDNz/25qtxgPa0+j8LW5e8Ev/xObqoJA7QuJS9/wIQ=
cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U=
cosmossdk.io/errors/v2 v2.0.0 h1:DOd65PGc4N6Mba4ov1inC1DeJeZw3GlwkM6EVfkvRMk=
cosmossdk.io/errors/v2 v2.0.0/go.mod h1:QsMpphjufUlEXk1gtxXrWFil+XlXLLhrVwyZt35sAPY=
cosmossdk.io/log v1.5.0 h1:dVdzPJW9kMrnAYyMf1duqacoidB9uZIl+7c6z0mnq0g=
cosmossdk.io/log v1.5.0/go.mod h1:Tr46PUJjiUthlwQ+hxYtUtPn4D/oCZXAkYevBeh5+FI=
cosmossdk.io/math v1.5.0 h1:sbOASxee9Zxdjd6OkzogvBZ25/hP929vdcYcBJQbkLc=
cosmossdk.io/math v1.5.0/go.mod h1:AAwwBmUhqtk2nlku174JwSll+/DepUXW3rWIXN5q+Nw=
cosmossdk.io/schema v1.0.0 h1:/diH4XJjpV1JQwuIozwr+A4uFuuwanFdnw2kKeiXwwQ=
cosmossdk.io/schema v1.0.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
cosmossdk.io/server/v2 v2.0.0-beta.2 h1:vJcsQvHVhG+biDaMUhHOP6yQxnOF01ynhNEr6dwZcRo=
cosmossdk.io/server/v2 v2.0.0-beta.2/go.mod h1:d7IJg0bUHemva35Vk24rCIkmXQg+4IjF4rBFAv4NRSM=
cosmossdk.io/server/v2/appmanager v1.0.0-beta.2 h1:58xH7Evpy/+9XbVwVf2+h009UN28NrDyXyr5wytD0Z8=
cosmossdk.io/server/v2/appmanager v1.0.0-beta.2/go.mod h1:l6oCGNcucF6/U949UwRj+RemNzq5475ovNHohcvN1YM=
cosmossdk.io/server/v2/stf v1.0.0-beta.2 h1:d4zNeDvemOOxyIr0xDBpDKxhYKZBsLcxiK28sXAHm3o=
cosmossdk.io/server/v2/stf v1.0.0-beta.2/go.mod h1:O6Njxje0LbvC0RxdgwTmvBlbGcpKOfhbkdAguyq0ntQ=
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 h1:glZ6MpmD+5AhwJYV4jzx+rn7cgUB2owHgk9o+93luz0=
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43/go.mod h1:XCWpgfueHSBY+B7Cf2Aq/CcsU+6XoFH+EmseCKglFrU=
cosmossdk.io/store/v2 v2.0.0-beta.1.0.20250113105648-064c9ba6385a h1:/y3j4oI+b/yYoPmZaF1NOuvDLhE71+/1f9Xucos4g1g=
cosmossdk.io/store/v2 v2.0.0-beta.1.0.20250113105648-064c9ba6385a/go.mod h1:RGIGNGmCeNkX7P+1eFovbvyp9kwY8AdJ0Ue096hRY/E=
cosmossdk.io/x/bank v0.2.0-rc.1 h1:tLYxL2N0U19tU50euZZKdsixsQcU6V+eMfudn/Y7YyY=
cosmossdk.io/x/bank v0.2.0-rc.1/go.mod h1:y1HipKOoiieb2gEZOQJPGwbwUBSYbIY+vG7XZAUstAE=
cosmossdk.io/x/consensus v0.2.0-rc.1 h1:6Df5E4lR7ggmOxZsm953ZR+gA6PwZzU0vpG9dmZtwuw=
cosmossdk.io/x/consensus v0.2.0-rc.1/go.mod h1:yNedASosEfhimal3ARqRa78EPRHBuy63zDdT1ByOgIA=
cosmossdk.io/x/staking v0.2.0-rc.1 h1:AZRGddRuuTaLxxpBvC7/TR7Dmt0pjziXWk13dC1beIo=
cosmossdk.io/x/staking v0.2.0-rc.1/go.mod h1:7K4hgQ6tn0XLFb2BJ9oe8nEc4RkfQ4qHqgQy2b0kVNc=
cosmossdk.io/x/tx v1.0.0 h1:pUUKRvHiMUZC/MnO8v747k1lUEA1DfAq0j0y0Mqrz/o=
cosmossdk.io/x/tx v1.0.0/go.mod h1:AXYJ47btzkcWuT1OtA3M44dv1iiYbKomtopHEbQGgH4=
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs=
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q=
github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/zstd v1.5.6 h1:LbEglqepa/ipmmQJUDnSsfvA8e8IStVcGaFWDuxvGOY=
github.com/DataDog/zstd v1.5.6/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I=
github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg=
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=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4=
github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e h1:dSeuFcs4WAJJnswS8vXy7YY1+fdlbVPuEVmDAfqvFOQ=
github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e/go.mod h1:uh71c5Vc3VNIplXOFXsnDy21T1BepgT32c5X/YPrOyc=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E=
github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ=
github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c=
github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE=
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
github.com/bvinc/go-sqlite-lite v0.6.1 h1:JU8Rz5YAOZQiU3WEulKF084wfXpytRiqD2IaW2QjPz4=
github.com/bvinc/go-sqlite-lite v0.6.1/go.mod h1:2GiE60NUdb0aNhDdY+LXgrqAVDpi2Ijc6dB6ZMp9x6s=
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I=
github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8=
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 h1:pU88SPhIFid6/k0egdR5V6eALQYq2qbSmukrkgIh/0A=
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/pebble v1.1.2 h1:CUh2IPtR4swHlEj48Rhfzw6l/d0qA31fItcIszQVIsA=
github.com/cockroachdb/pebble v1.1.2/go.mod h1:4exszw1r40423ZsmkG/09AFEG83I0uDgfujJdbL6kYU=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
github.com/cometbft/cometbft v1.0.0 h1:6Lihx2hP2BwZ/9ybNp3r4QdiV8e4uBYm+rE45GGH8HU=
github.com/cometbft/cometbft v1.0.0/go.mod h1:+hGB2I4vhCEwdceY35lf75XZZzMtm3VDOVt8hj7qkCs=
github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE=
github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk=
github.com/cometbft/cometbft/api v1.0.0 h1:gGBwvsJi/gnHJEtwYfjPIGs2AKg/Vfa1ZuKCPD1/Ko4=
github.com/cometbft/cometbft/api v1.0.0/go.mod h1:EkQiqVSu/p2ebrZEnB2z6Re7r8XNe//M7ylR0qEwWm0=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk=
github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis=
github.com/cosmos/cosmos-db v1.1.0 h1:KLHNVQ73h7vawXTpj9UJ7ZR2IXv51tsEHkQJJ9EBDzI=
github.com/cosmos/cosmos-db v1.1.0/go.mod h1:t7c4A6cfGdpUwwVxrQ0gQLeRQqGUBJu0yvE4F/26REg=
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.52.0-rc.1 h1:HgHOUYbxvjvyiX5CQF4eLT0u1wvjxajwgClOGzAmNoQ=
github.com/cosmos/cosmos-sdk v0.52.0-rc.1/go.mod h1:2Z6V16EhPG1NI6Q+b9Xue7dgabx76JQpUtlcCnYbI90=
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=
github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI=
github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU=
github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro=
github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0=
github.com/cosmos/iavl v1.3.4 h1:A0RUAms7TZ0L6EFrrBIPg4Dy7qD9vvD5lJKUxEXURLM=
github.com/cosmos/iavl v1.3.4/go.mod h1:T6SfBcyhulVIY2G/ZtAtQm/QiJvsuhIos52V4dWYk88=
github.com/cosmos/iavl-bench/bench v0.0.4 h1:J6zQPiBqF4CXMM3QBsLqZgQEBGY0taX85vLIZMhmAfQ=
github.com/cosmos/iavl-bench/bench v0.0.4/go.mod h1:j2rLae77EffacWcp7mmj3Uaa4AOAmZA7ymvhsuBQKKI=
github.com/cosmos/iavl/v2 v2.0.0-alpha.4 h1:PfpQt7xl4hojw2UFS2JdJppJnx8sjlmcxRQ7Hxk7Cl0=
github.com/cosmos/iavl/v2 v2.0.0-alpha.4/go.mod h1:7RSm0aeApe3S1x4TrLffvUL6pjOtMYV4glYnpAhr2lw=
github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU=
github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0=
github.com/cosmos/ledger-cosmos-go v0.14.0 h1:WfCHricT3rPbkPSVKRH+L4fQGKYHuGOK9Edpel8TYpE=
github.com/cosmos/ledger-cosmos-go v0.14.0/go.mod h1:E07xCWSBl3mTGofZ2QnL4cIUzMbbGVyik84QYKbX3RA=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/dgraph-io/badger/v4 v4.5.0 h1:TeJE3I1pIWLBjYhIYCA1+uxrjWEoJXImFBMEBVSm16g=
github.com/dgraph-io/badger/v4 v4.5.0/go.mod h1:ysgYmIeG8dS/E8kwxT7xHyc7MkmwNYLRoYnFbr7387A=
github.com/dgraph-io/ristretto/v2 v2.0.0 h1:l0yiSOtlJvc0otkqyMaDNysg8E9/F/TYZwMbxscNOAQ=
github.com/dgraph-io/ristretto/v2 v2.0.0/go.mod h1:FVFokF2dRqXyPyeMnK1YDy8Fc6aTe0IKgbcd03CYeEk=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y=
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvsekhvalnov/jose2go v1.6.0 h1:Y9gnSnP4qEI0+/uQkHvFXeD2PLPJeXEL+ySMEA2EjTY=
github.com/dvsekhvalnov/jose2go v1.6.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI=
github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us=
github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY=
github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI=
github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog=
github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
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/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU=
github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w=
github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w=
github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94=
github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kocubinski/costor-api v1.1.1 h1:sgfJA7T/8IfZ59zxiMrED0xdjerAFuPNBTqyO90GiEE=
github.com/kocubinski/costor-api v1.1.1/go.mod h1:ESMBMDkKfN+9vvvhhNVdKLhbOmzI3O/i16iXvRM9Tuc=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik=
github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA=
github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM=
github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q=
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.28.1 h1:MijcGUbfYuznzK/5R4CPNoUP/9Xvuo20sXfEm6XxoTA=
github.com/onsi/gomega v1.28.1/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
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/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA=
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw=
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA=
github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU=
github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
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.13 h1:AYeSxdOMacwu7FBmpfloBz5pbFXDmJL33RuwnKtmTjk=
github.com/supranational/blst v0.3.13/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/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U=
github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM=
github.com/zondax/ledger-go v1.0.0 h1:BvNoksIyRqyQTW78rIZP9A44WwAminKiomQa7jXp9EI=
github.com/zondax/ledger-go v1.0.0/go.mod h1:HpgkgFh3Jkwi9iYLDATdyRxc8CxqxcywsFj6QerWzvo=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA=
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8=
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q=
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I=
go.etcd.io/bbolt v1.4.0-alpha.1 h1:3yrqQzbRRPFPdOMWS/QQIVxVnzSkAZQYeWlZFv1kbj4=
go.etcd.io/bbolt v1.4.0-alpha.1/go.mod h1:S/Z/Nm3iuOnyO1W4XuFfPci51Gj6F1Hv0z8hisyYYOw=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk=
go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0=
go.opentelemetry.io/otel/sdk/metric v1.31.0 h1:i9hxxLJF/9kkvfHppyLL55aW7iIJz4JjxTeYusH7zMc=
go.opentelemetry.io/otel/sdk/metric v1.31.0/go.mod h1:CRInTMVvNhUKgSAMbKyTMxqOBC0zgyxzW55lZzX43Y8=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
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/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/arch v0.12.0 h1:UsYJhbzPYGsT0HbEdmYcqtCv8UNGvnaL561NnIUvaKg=
golang.org/x/arch v0.12.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw=
pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -1,606 +0,0 @@
package cometbft
import (
"context"
"errors"
"fmt"
"strings"
abci "github.com/cometbft/cometbft/abci/types"
abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1"
rpchttp "github.com/cometbft/cometbft/rpc/client/http"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
cmtv1beta1 "cosmossdk.io/api/cosmos/base/tendermint/v1beta1"
"cosmossdk.io/core/server"
corestore "cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
storeserver "cosmossdk.io/server/v2/store"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)
type appSimulator[T transaction.Tx] interface {
Simulate(ctx context.Context, tx T) (server.TxResult, corestore.WriterMap, error)
}
// gRPCServiceRegistrar returns a function that registers the CometBFT gRPC service
// Those services are defined for backward compatibility.
// Eventually, they will be removed in favor of the new gRPC services.
func gRPCServiceRegistrar[T transaction.Tx](
clientCtx client.Context,
cfg server.ConfigMap,
cometBFTAppConfig *AppTomlConfig,
txCodec transaction.Codec[T],
consensus abci.Application,
app appSimulator[T],
) func(srv *grpc.Server) error {
return func(srv *grpc.Server) error {
cmtservice.RegisterServiceServer(srv, cmtservice.NewQueryServer(clientCtx.Client, consensus.Query, clientCtx.ConsensusAddressCodec))
txtypes.RegisterServiceServer(srv, txServer[T]{clientCtx, txCodec, app, consensus})
nodeservice.RegisterServiceServer(srv, nodeServer[T]{cfg, cometBFTAppConfig, consensus})
return nil
}
}
type txServer[T transaction.Tx] struct {
clientCtx client.Context
txCodec transaction.Codec[T]
app appSimulator[T]
consensus abci.Application
}
// BroadcastTx implements tx.ServiceServer.
func (t txServer[T]) BroadcastTx(ctx context.Context, req *txtypes.BroadcastTxRequest) (*txtypes.BroadcastTxResponse, error) {
return client.TxServiceBroadcast(ctx, t.clientCtx, req)
}
// GetBlockWithTxs implements tx.ServiceServer.
func (t txServer[T]) GetBlockWithTxs(ctx context.Context, req *txtypes.GetBlockWithTxsRequest) (*txtypes.GetBlockWithTxsResponse, error) {
logger := log.NewNopLogger()
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}
resp, err := t.consensus.Info(ctx, &abci.InfoRequest{})
if err != nil {
return nil, err
}
currentHeight := resp.LastBlockHeight
if req.Height < 1 || req.Height > currentHeight {
return nil, sdkerrors.ErrInvalidHeight.Wrapf("requested height %d but height must not be less than 1 "+
"or greater than the current height %d", req.Height, currentHeight)
}
node, err := t.clientCtx.GetNode()
if err != nil {
return nil, err
}
blockID, block, err := cmtservice.GetProtoBlock(ctx, node, &req.Height)
if err != nil {
return nil, err
}
var offset, limit uint64
if req.Pagination != nil {
offset = req.Pagination.Offset
limit = req.Pagination.Limit
} else {
offset = 0
limit = query.DefaultLimit
}
blockTxs := block.Data.Txs
blockTxsLn := uint64(len(blockTxs))
txs := make([]*txtypes.Tx, 0, limit)
if offset >= blockTxsLn && blockTxsLn != 0 {
return nil, sdkerrors.ErrInvalidRequest.Wrapf("out of range: cannot paginate %d txs with offset %d and limit %d", blockTxsLn, offset, limit)
}
decodeTxAt := func(i uint64) error {
tx := blockTxs[i]
txb, err := t.txCodec.Decode(tx)
if err != nil {
return err
}
// txServer works only with sdk.Tx
p, err := any(txb).(interface{ AsTx() (*txtypes.Tx, error) }).AsTx()
if err != nil {
return err
}
txs = append(txs, p)
return nil
}
if req.Pagination != nil && req.Pagination.Reverse {
for i, count := offset, uint64(0); i > 0 && count != limit; i, count = i-1, count+1 {
if err = decodeTxAt(i); err != nil {
logger.Error("failed to decode tx", "error", err)
}
}
} else {
for i, count := offset, uint64(0); i < blockTxsLn && count != limit; i, count = i+1, count+1 {
if err = decodeTxAt(i); err != nil {
logger.Error("failed to decode tx", "error", err)
}
}
}
return &txtypes.GetBlockWithTxsResponse{
Txs: txs,
BlockId: &blockID,
Block: block,
Pagination: &query.PageResponse{
Total: blockTxsLn,
},
}, nil
}
// GetTx implements tx.ServiceServer.
func (t txServer[T]) GetTx(ctx context.Context, req *txtypes.GetTxRequest) (*txtypes.GetTxResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}
if len(req.Hash) == 0 {
return nil, status.Error(codes.InvalidArgument, "tx hash cannot be empty")
}
result, err := authtx.QueryTx(t.clientCtx, req.Hash)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, status.Errorf(codes.NotFound, "tx not found: %s", req.Hash)
}
return nil, err
}
protoTx, ok := result.Tx.GetCachedValue().(*txtypes.Tx)
if !ok {
return nil, status.Errorf(codes.Internal, "expected %T, got %T", txtypes.Tx{}, result.Tx.GetCachedValue())
}
return &txtypes.GetTxResponse{
Tx: protoTx,
TxResponse: result,
}, nil
}
// GetTxsEvent implements tx.ServiceServer.
func (t txServer[T]) GetTxsEvent(ctx context.Context, req *txtypes.GetTxsEventRequest) (*txtypes.GetTxsEventResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}
orderBy := parseOrderBy(req.OrderBy)
result, err := authtx.QueryTxsByEvents(t.clientCtx, int(req.Page), int(req.Limit), req.Query, orderBy)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
txsList := make([]*txtypes.Tx, len(result.Txs))
for i, tx := range result.Txs {
protoTx, ok := tx.Tx.GetCachedValue().(*txtypes.Tx)
if !ok {
return nil, status.Errorf(codes.Internal, "getting cached value failed expected %T, got %T", txtypes.Tx{}, tx.Tx.GetCachedValue())
}
txsList[i] = protoTx
}
return &txtypes.GetTxsEventResponse{
Txs: txsList,
TxResponses: result.Txs,
Total: result.TotalCount,
}, nil
}
// Simulate implements tx.ServiceServer.
func (t txServer[T]) Simulate(ctx context.Context, req *txtypes.SimulateRequest) (*txtypes.SimulateResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
txBytes := req.TxBytes
if txBytes == nil && req.Tx != nil {
// This block is for backwards-compatibility.
// We used to support passing a `Tx` in req. But if we do that, sig
// verification might not pass, because the .Marshal() below might not
// be the same marshaling done by the client.
var err error
txBytes, err = proto.Marshal(req.Tx)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid tx; %v", err)
}
}
if txBytes == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty txBytes is not allowed")
}
tx, err := t.txCodec.Decode(txBytes)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to decode tx: %v", err)
}
txResult, _, err := t.app.Simulate(ctx, tx)
if err != nil {
return nil, status.Errorf(codes.Unknown, "%v with gas used: '%d'", err, txResult.GasUsed)
}
msgResponses := make([]*codectypes.Any, 0, len(txResult.Resp))
// pack the messages into Any
for _, msg := range txResult.Resp {
anyMsg, err := codectypes.NewAnyWithValue(msg)
if err != nil {
return nil, status.Errorf(codes.Unknown, "failed to pack message response: %v", err)
}
msgResponses = append(msgResponses, anyMsg)
}
event, err := intoABCIEvents(txResult.Events, map[string]struct{}{}, false)
if err != nil {
return nil, status.Errorf(codes.Unknown, "failed to convert events: %v", err)
}
return &txtypes.SimulateResponse{
GasInfo: &sdk.GasInfo{
GasUsed: txResult.GasUsed,
GasWanted: txResult.GasWanted,
},
Result: &sdk.Result{
MsgResponses: msgResponses,
Events: event,
},
}, nil
}
// TxDecode implements tx.ServiceServer.
func (t txServer[T]) TxDecode(ctx context.Context, req *txtypes.TxDecodeRequest) (*txtypes.TxDecodeResponse, error) {
if req.TxBytes == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx bytes")
}
txb, err := t.txCodec.Decode(req.TxBytes)
if err != nil {
return nil, err
}
// txServer works only with sdk.Tx
tx, err := any(txb).(interface{ AsTx() (*txtypes.Tx, error) }).AsTx()
if err != nil {
return nil, err
}
return &txtypes.TxDecodeResponse{
Tx: tx,
}, nil
}
// TxDecodeAmino implements tx.ServiceServer.
func (t txServer[T]) TxDecodeAmino(_ context.Context, req *txtypes.TxDecodeAminoRequest) (*txtypes.TxDecodeAminoResponse, error) {
if req.AminoBinary == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx bytes")
}
var stdTx legacytx.StdTx
err := t.clientCtx.LegacyAmino.Unmarshal(req.AminoBinary, &stdTx)
if err != nil {
return nil, err
}
res, err := t.clientCtx.LegacyAmino.MarshalJSON(stdTx)
if err != nil {
return nil, err
}
return &txtypes.TxDecodeAminoResponse{
AminoJson: string(res),
}, nil
}
// TxEncode implements tx.ServiceServer.
func (t txServer[T]) TxEncode(_ context.Context, req *txtypes.TxEncodeRequest) (*txtypes.TxEncodeResponse, error) {
if req.Tx == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}
bodyBytes, err := t.clientCtx.Codec.Marshal(req.Tx.Body)
if err != nil {
return nil, err
}
authInfoBytes, err := t.clientCtx.Codec.Marshal(req.Tx.AuthInfo)
if err != nil {
return nil, err
}
raw := &txtypes.TxRaw{
BodyBytes: bodyBytes,
AuthInfoBytes: authInfoBytes,
Signatures: req.Tx.Signatures,
}
encodedBytes, err := t.clientCtx.Codec.Marshal(raw)
if err != nil {
return nil, err
}
return &txtypes.TxEncodeResponse{
TxBytes: encodedBytes,
}, nil
}
// TxEncodeAmino implements tx.ServiceServer.
func (t txServer[T]) TxEncodeAmino(_ context.Context, req *txtypes.TxEncodeAminoRequest) (*txtypes.TxEncodeAminoResponse, error) {
if req.AminoJson == "" {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx json")
}
var stdTx legacytx.StdTx
err := t.clientCtx.LegacyAmino.UnmarshalJSON([]byte(req.AminoJson), &stdTx)
if err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("invalid request %s", err))
}
encodedBytes, err := t.clientCtx.LegacyAmino.Marshal(stdTx)
if err != nil {
return nil, err
}
return &txtypes.TxEncodeAminoResponse{
AminoBinary: encodedBytes,
}, nil
}
var _ txtypes.ServiceServer = txServer[transaction.Tx]{}
type nodeServer[T transaction.Tx] struct {
cfg server.ConfigMap
cometBFTAppConfig *AppTomlConfig
consensus abci.Application
}
func (s nodeServer[T]) Config(ctx context.Context, _ *nodeservice.ConfigRequest) (*nodeservice.ConfigResponse, error) {
minGasPricesStr := ""
minGasPrices, ok := s.cfg["server"].(map[string]interface{})["minimum-gas-prices"]
if ok {
minGasPricesStr = minGasPrices.(string)
}
storeCfg, err := storeserver.UnmarshalConfig(s.cfg)
if err != nil {
return nil, err
}
return &nodeservice.ConfigResponse{
MinimumGasPrice: minGasPricesStr,
PruningKeepRecent: fmt.Sprintf("%d", storeCfg.Options.SCPruningOption.KeepRecent),
PruningInterval: fmt.Sprintf("%d", storeCfg.Options.SCPruningOption.Interval),
HaltHeight: s.cometBFTAppConfig.HaltHeight,
}, nil
}
func (s nodeServer[T]) Status(ctx context.Context, _ *nodeservice.StatusRequest) (*nodeservice.StatusResponse, error) {
nodeInfo, err := s.consensus.Info(ctx, &abciproto.InfoRequest{})
if err != nil {
return nil, err
}
return &nodeservice.StatusResponse{
Height: uint64(nodeInfo.LastBlockHeight),
Timestamp: nil,
AppHash: nil,
ValidatorHash: nodeInfo.LastBlockAppHash,
}, nil
}
// CometBFTAutoCLIDescriptor is the auto-generated CLI descriptor for the CometBFT service
var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{
Service: cmtv1beta1.Service_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "GetNodeInfo",
Use: "node-info",
Short: "Query the current node info",
},
{
RpcMethod: "GetSyncing",
Use: "syncing",
Short: "Query node syncing status",
},
{
RpcMethod: "GetLatestBlock",
Use: "block-latest",
Short: "Query for the latest committed block",
},
{
RpcMethod: "GetBlockByHeight",
Use: "block-by-height <height>",
Short: "Query for a committed block by height",
Long: "Query for a specific committed block using the CometBFT RPC `block_by_height` method",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "GetLatestValidatorSet",
Use: "validator-set",
Alias: []string{"validator-set-latest", "comet-validator-set", "cometbft-validator-set", "tendermint-validator-set"},
Short: "Query for the latest validator set",
},
{
RpcMethod: "GetValidatorSetByHeight",
Use: "validator-set-by-height <height>",
Short: "Query for a validator set by height",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "ABCIQuery",
Skip: true,
},
},
}
func parseOrderBy(orderBy txtypes.OrderBy) string {
switch orderBy {
case txtypes.OrderBy_ORDER_BY_ASC:
return "asc"
case txtypes.OrderBy_ORDER_BY_DESC:
return "desc"
default:
return "" // Defaults to CometBFT's default, which is `asc` now.
}
}
func (c *consensus[T]) maybeHandleExternalServices(ctx context.Context, req *abci.QueryRequest) (transaction.Msg, error) {
// Handle comet service
if strings.HasPrefix(req.Path, "/cosmos.base.tendermint.v1beta1.Service") {
rpcClient, _ := rpchttp.New(c.cfg.ConfigTomlConfig.RPC.ListenAddress)
cometQServer := cmtservice.NewQueryServer(rpcClient, c.Query, c.appCodecs.ConsensusAddressCodec)
paths := strings.Split(req.Path, "/")
if len(paths) <= 2 {
return nil, fmt.Errorf("invalid request path: %s", req.Path)
}
var resp transaction.Msg
var err error
switch paths[2] {
case "GetNodeInfo":
resp, err = handleExternalService(ctx, req, cometQServer.GetNodeInfo)
case "GetSyncing":
resp, err = handleExternalService(ctx, req, cometQServer.GetSyncing)
case "GetLatestBlock":
resp, err = handleExternalService(ctx, req, cometQServer.GetLatestBlock)
case "GetBlockByHeight":
resp, err = handleExternalService(ctx, req, cometQServer.GetBlockByHeight)
case "GetLatestValidatorSet":
resp, err = handleExternalService(ctx, req, cometQServer.GetLatestValidatorSet)
case "GetValidatorSetByHeight":
resp, err = handleExternalService(ctx, req, cometQServer.GetValidatorSetByHeight)
case "ABCIQuery":
resp, err = handleExternalService(ctx, req, cometQServer.ABCIQuery)
}
return resp, err
}
// Handle node service
if strings.HasPrefix(req.Path, "/cosmos.base.node.v1beta1.Service") {
nodeQService := nodeServer[T]{c.cfgMap, c.cfg.AppTomlConfig, c}
paths := strings.Split(req.Path, "/")
if len(paths) <= 2 {
return nil, fmt.Errorf("invalid request path: %s", req.Path)
}
var resp transaction.Msg
var err error
switch paths[2] {
case "Config":
resp, err = handleExternalService(ctx, req, nodeQService.Config)
case "Status":
resp, err = handleExternalService(ctx, req, nodeQService.Status)
}
return resp, err
}
// Handle tx service
if strings.HasPrefix(req.Path, "/cosmos.tx.v1beta1.Service") {
rpcClient, _ := client.NewClientFromNode(c.cfg.ConfigTomlConfig.RPC.ListenAddress)
txConfig := authtx.NewTxConfig(
c.appCodecs.AppCodec,
c.appCodecs.AppCodec.InterfaceRegistry().SigningContext().AddressCodec(),
c.appCodecs.AppCodec.InterfaceRegistry().SigningContext().ValidatorAddressCodec(),
authtx.DefaultSignModes,
)
// init simple client context
clientCtx := client.Context{}.
WithLegacyAmino(c.appCodecs.LegacyAmino.(*codec.LegacyAmino)).
WithCodec(c.appCodecs.AppCodec).
WithNodeURI(c.cfg.AppTomlConfig.Address).
WithClient(rpcClient).
WithTxConfig(txConfig)
txService := txServer[T]{
clientCtx: clientCtx,
txCodec: c.appCodecs.TxCodec,
app: c.app,
consensus: c,
}
paths := strings.Split(req.Path, "/")
if len(paths) <= 2 {
return nil, fmt.Errorf("invalid request path: %s", req.Path)
}
var resp transaction.Msg
var err error
switch paths[2] {
case "Simulate":
resp, err = handleExternalService(ctx, req, txService.Simulate)
case "GetTx":
resp, err = handleExternalService(ctx, req, txService.GetTx)
case "BroadcastTx":
return nil, errors.New("can't route a broadcast tx message")
case "GetTxsEvent":
resp, err = handleExternalService(ctx, req, txService.GetTxsEvent)
case "GetBlockWithTxs":
resp, err = handleExternalService(ctx, req, txService.GetBlockWithTxs)
case "TxDecode":
resp, err = handleExternalService(ctx, req, txService.TxDecode)
case "TxEncode":
resp, err = handleExternalService(ctx, req, txService.TxEncode)
case "TxEncodeAmino":
resp, err = handleExternalService(ctx, req, txService.TxEncodeAmino)
case "TxDecodeAmino":
resp, err = handleExternalService(ctx, req, txService.TxDecodeAmino)
}
return resp, err
}
return nil, nil
}
func handleExternalService[T any, PT interface {
*T
proto.Message
},
U any, UT interface {
*U
proto.Message
}](
ctx context.Context,
rawReq *abciproto.QueryRequest,
handler func(ctx context.Context, msg PT) (UT, error),
) (transaction.Msg, error) {
req := PT(new(T))
err := proto.Unmarshal(rawReq.Data, req)
if err != nil {
return nil, err
}
typedResp, err := handler(ctx, req)
if err != nil {
return nil, err
}
return typedResp, nil
}

View File

@ -1,204 +0,0 @@
package handlers
import (
"context"
"errors"
"fmt"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/server/v2/cometbft/mempool"
consensustypes "cosmossdk.io/x/consensus/types"
)
type AppManager[T transaction.Tx] interface {
ValidateTx(ctx context.Context, tx T) (server.TxResult, error)
Query(ctx context.Context, version uint64, request transaction.Msg) (response transaction.Msg, err error)
}
type DefaultProposalHandler[T transaction.Tx] struct {
mempool mempool.Mempool[T]
txSelector TxSelector[T]
}
func NewDefaultProposalHandler[T transaction.Tx](mp mempool.Mempool[T]) *DefaultProposalHandler[T] {
return &DefaultProposalHandler[T]{
mempool: mp,
txSelector: NewDefaultTxSelector[T](),
}
}
func (h *DefaultProposalHandler[T]) PrepareHandler() PrepareHandler[T] {
return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, chainID string) ([]T, error) {
var maxBlockGas uint64
res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{})
if err != nil {
return nil, err
}
paramsResp, ok := res.(*consensustypes.QueryParamsResponse)
if !ok {
return nil, fmt.Errorf("unexpected consensus params response type; expected: %T, got: %T", &consensustypes.QueryParamsResponse{}, res)
}
if b := paramsResp.GetParams().Block; b != nil {
maxBlockGas = uint64(b.MaxGas)
}
txs := decodeTxs(codec, req.Txs)
defer h.txSelector.Clear()
// If the mempool is nil or NoOp we simply return the transactions
// requested from CometBFT, which, by default, should be in FIFO order.
//
// Note, we still need to ensure the transactions returned respect req.MaxTxBytes.
_, isNoOp := h.mempool.(mempool.NoOpMempool[T])
if h.mempool == nil || isNoOp {
for _, tx := range txs {
stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, tx)
if stop {
break
}
}
return h.txSelector.SelectedTxs(ctx), nil
}
iterator := h.mempool.Select(ctx, txs)
for iterator != nil {
memTx := iterator.Tx()
// NOTE: Since transaction verification was already executed in CheckTx,
// which calls mempool.Insert, in theory everything in the pool should be
// valid. But some mempool implementations may insert invalid txs, so we
// check again.
_, err := app.ValidateTx(ctx, memTx)
if err != nil {
err := h.mempool.Remove(memTx)
if err != nil && !errors.Is(err, mempool.ErrTxNotFound) {
return nil, err
}
} else {
stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, memTx)
if stop {
break
}
}
iterator = iterator.Next()
}
return h.txSelector.SelectedTxs(ctx), nil
}
}
func (h *DefaultProposalHandler[T]) ProcessHandler() ProcessHandler[T] {
return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.ProcessProposalRequest, chainID string) error {
// If the mempool is nil we simply return ACCEPT,
// because PrepareProposal may have included txs that could fail verification.
_, isNoOp := h.mempool.(mempool.NoOpMempool[T])
if h.mempool == nil || isNoOp {
return nil
}
res, err := app.Query(ctx, 0, &consensustypes.QueryParamsRequest{})
if err != nil {
return err
}
paramsResp, ok := res.(*consensustypes.QueryParamsResponse)
if !ok {
return fmt.Errorf("unexpected consensus params response type; expected: %T, got: %T", &consensustypes.QueryParamsResponse{}, res)
}
var maxBlockGas uint64
if b := paramsResp.GetParams().Block; b != nil {
maxBlockGas = uint64(b.MaxGas)
}
// Decode request txs bytes
// If there an tx decoded fail, return err
var txs []T
for _, tx := range req.Txs {
decTx, err := codec.Decode(tx)
if err != nil {
return fmt.Errorf("failed to decode tx: %w", err)
}
txs = append(txs, decTx)
}
var totalTxGas uint64
for _, tx := range txs {
_, err := app.ValidateTx(ctx, tx)
if err != nil {
return fmt.Errorf("failed to validate tx: %w", err)
}
if maxBlockGas > 0 {
gaslimit, err := tx.GetGasLimit()
if err != nil {
return errors.New("failed to get gas limit")
}
totalTxGas += gaslimit
if totalTxGas > maxBlockGas {
return fmt.Errorf("total tx gas %d exceeds max block gas %d", totalTxGas, maxBlockGas)
}
}
}
return nil
}
}
// decodeTxs decodes the txs bytes into a decoded txs
// If there a fail decoding tx, remove from the list
// Used for prepare proposal
func decodeTxs[T transaction.Tx](codec transaction.Codec[T], txsBz [][]byte) []T {
var txs []T
for _, tx := range txsBz {
decTx, err := codec.Decode(tx)
if err != nil {
continue
}
txs = append(txs, decTx)
}
return txs
}
// NoOpPrepareProposal defines a no-op PrepareProposal handler. It will always
// return the transactions sent by the client's request.
func NoOpPrepareProposal[T transaction.Tx]() PrepareHandler[T] {
return func(ctx context.Context, app AppManager[T], codec transaction.Codec[T], req *abci.PrepareProposalRequest, chainID string) ([]T, error) {
return decodeTxs(codec, req.Txs), nil
}
}
// NoOpProcessProposal defines a no-op ProcessProposal Handler. It will always
// return ACCEPT.
func NoOpProcessProposal[T transaction.Tx]() ProcessHandler[T] {
return func(context.Context, AppManager[T], transaction.Codec[T], *abci.ProcessProposalRequest, string) error {
return nil
}
}
// NoOpExtendVote defines a no-op ExtendVote handler. It will always return an
// empty byte slice as the vote extension.
func NoOpExtendVote() ExtendVoteHandler {
return func(context.Context, store.ReaderMap, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error) {
return &abci.ExtendVoteResponse{VoteExtension: []byte{}}, nil
}
}
// NoOpVerifyVoteExtensionHandler defines a no-op VerifyVoteExtension handler. It
// will always return an ACCEPT status with no error.
func NoOpVerifyVoteExtensionHandler() VerifyVoteExtensionHandler {
return func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error) {
return &abci.VerifyVoteExtensionResponse{Status: abci.VERIFY_VOTE_EXTENSION_STATUS_ACCEPT}, nil
}
}

View File

@ -1,34 +0,0 @@
package handlers
import (
"context"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
)
type (
// PrepareHandler passes in the list of Txs that are being proposed. The app can then do stateful operations
// over the list of proposed transactions. It can return a modified list of txs to include in the proposal.
PrepareHandler[T transaction.Tx] func(ctx context.Context, app AppManager[T], cdc transaction.Codec[T], req *abci.PrepareProposalRequest, chainID string) ([]T, error)
// ProcessHandler is a function that takes a list of transactions and returns a boolean and an error.
// If the verification of a transaction fails, the boolean is false and the error is non-nil.
ProcessHandler[T transaction.Tx] func(ctx context.Context, app AppManager[T], cdc transaction.Codec[T], req *abci.ProcessProposalRequest, chainID string) error
// VerifyVoteExtensionHandler is a function type that handles the verification of a vote extension request.
// It takes a context, a store reader map, and a request to verify a vote extension.
// It returns a response to verify the vote extension and an error if any.
VerifyVoteExtensionHandler func(context.Context, store.ReaderMap, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error)
// ExtendVoteHandler is a function type that handles the extension of a vote.
// It takes a context, a store reader map, and a request to extend a vote.
// It returns a response to extend the vote and an error if any.
ExtendVoteHandler func(context.Context, store.ReaderMap, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error)
// CheckTxHandler is a function type that handles the execution of a transaction.
CheckTxHandler[T transaction.Tx] func(func(ctx context.Context, tx T) (server.TxResult, error)) (*abci.CheckTxResponse, error)
)

View File

@ -1,76 +0,0 @@
package handlers
import (
"context"
cmttypes "github.com/cometbft/cometbft/types"
"cosmossdk.io/core/transaction"
)
// TxSelector defines a helper type that assists in selecting transactions during
// mempool transaction selection in PrepareProposal. It keeps track of the total
// number of bytes and total gas of the selected transactions. It also keeps
// track of the selected transactions themselves.
type TxSelector[T transaction.Tx] interface {
// SelectedTxs should return a copy of the selected transactions.
SelectedTxs(ctx context.Context) []T
// Clear should clear the TxSelector, nulling out all relevant fields.
Clear()
// SelectTxForProposal should attempt to select a transaction for inclusion in
// a proposal based on inclusion criteria defined by the TxSelector. It must
// return <true> if the caller should halt the transaction selection loop
// (typically over a mempool) or <false> otherwise.
SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, tx T) bool
}
type defaultTxSelector[T transaction.Tx] struct {
totalTxBytes uint64
totalTxGas uint64
selectedTxs []T
}
func NewDefaultTxSelector[T transaction.Tx]() TxSelector[T] {
return &defaultTxSelector[T]{}
}
func (ts *defaultTxSelector[T]) SelectedTxs(_ context.Context) []T {
txs := make([]T, len(ts.selectedTxs))
copy(txs, ts.selectedTxs)
return txs
}
func (ts *defaultTxSelector[T]) Clear() {
ts.totalTxBytes = 0
ts.totalTxGas = 0
ts.selectedTxs = nil
}
func (ts *defaultTxSelector[T]) SelectTxForProposal(_ context.Context, maxTxBytes, maxBlockGas uint64, tx T) bool {
txSize := uint64(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{tx.Bytes()}))
txGasLimit, err := tx.GetGasLimit()
if err != nil {
return false
}
// only add the transaction to the proposal if we have enough capacity
if (txSize + ts.totalTxBytes) <= maxTxBytes {
// If there is a max block gas limit, add the tx only if the limit has
// not been met.
if maxBlockGas > 0 {
if (txGasLimit + ts.totalTxGas) <= maxBlockGas {
ts.totalTxGas += txGasLimit
ts.totalTxBytes += txSize
ts.selectedTxs = append(ts.selectedTxs, tx)
}
} else {
ts.totalTxBytes += txSize
ts.selectedTxs = append(ts.selectedTxs, tx)
}
}
// check if we've reached capacity; if so, we cannot select any more transactions
return ts.totalTxBytes >= maxTxBytes || (maxBlockGas > 0 && (ts.totalTxGas >= maxBlockGas))
}

View File

@ -1,20 +0,0 @@
package mock
import (
"context"
"cosmossdk.io/core/transaction"
"cosmossdk.io/server/v2/cometbft/mempool"
)
var _ mempool.Mempool[transaction.Tx] = (*MockMempool[transaction.Tx])(nil)
// MockMempool implements Mempool
// Used for testing instead of NoOpMempool
type MockMempool[T transaction.Tx] struct{}
func (MockMempool[T]) Insert(context.Context, T) error { return nil }
func (MockMempool[T]) Select(context.Context, []T) mempool.Iterator[T] { return nil }
func (MockMempool[T]) SelectBy(context.Context, []T, func(T) bool) {}
func (MockMempool[T]) CountTx() int { return 0 }
func (MockMempool[T]) Remove(T) error { return nil }

View File

@ -1,65 +0,0 @@
package mock
import (
corestore "cosmossdk.io/core/store"
)
// ReaderMap defines an adapter around a RootStore that only exposes read-only
// operations. This is useful for exposing a read-only view of the RootStore at
// a specific version in history, which could also be the latest state.
type ReaderMap struct {
store *MockStore
version uint64
}
func NewMockReaderMap(v uint64, rs *MockStore) *ReaderMap {
return &ReaderMap{
store: rs,
version: v,
}
}
func (roa *ReaderMap) GetReader(actor []byte) (corestore.Reader, error) {
return NewMockReader(roa.version, roa.store, actor), nil
}
// MockReader represents a read-only adapter for accessing data from the root store.
type MockReader struct {
version uint64 // The version of the data.
store *MockStore // The root store to read data from.
actor []byte // The actor associated with the data.
}
func NewMockReader(v uint64, rs *MockStore, actor []byte) *MockReader {
return &MockReader{
version: v,
store: rs,
actor: actor,
}
}
func (roa *MockReader) Has(key []byte) (bool, error) {
val, err := roa.store.GetStateCommitment().Has(roa.actor, roa.version, key)
if err != nil {
return false, err
}
return val, nil
}
func (roa *MockReader) Get(key []byte) ([]byte, error) {
result, err := roa.store.GetStateCommitment().Get(roa.actor, roa.version, key)
if err != nil {
return nil, err
}
return result, nil
}
func (roa *MockReader) Iterator(start, end []byte) (corestore.Iterator, error) {
return roa.store.GetStateCommitment().Iterator(roa.actor, roa.version, start, end)
}
func (roa *MockReader) ReverseIterator(start, end []byte) (corestore.Iterator, error) {
return roa.store.GetStateCommitment().ReverseIterator(roa.actor, roa.version, start, end)
}

View File

@ -1,109 +0,0 @@
package mock
import (
"crypto/sha256"
"fmt"
"cosmossdk.io/core/log"
corestore "cosmossdk.io/core/store"
storev2 "cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/commitment"
"cosmossdk.io/store/v2/commitment/iavl"
dbm "cosmossdk.io/store/v2/db"
"cosmossdk.io/store/v2/proof"
)
type MockStore struct {
Committer storev2.Committer
}
func NewMockCommiter(logger log.Logger, actors ...string) storev2.Committer {
treeMap := make(map[string]commitment.Tree)
for _, actor := range actors {
tree := iavl.NewIavlTree(dbm.NewMemDB(), logger, iavl.DefaultConfig())
treeMap[actor] = tree
}
sc, _ := commitment.NewCommitStore(treeMap, treeMap, dbm.NewMemDB(), logger)
return sc
}
func NewMockStore(sc storev2.Committer) *MockStore {
return &MockStore{Committer: sc}
}
func (s *MockStore) GetLatestVersion() (uint64, error) {
lastCommitID, err := s.LastCommitID()
if err != nil {
return 0, err
}
return uint64(lastCommitID.Version), nil
}
func (s *MockStore) StateLatest() (uint64, corestore.ReaderMap, error) {
v, err := s.GetLatestVersion()
if err != nil {
return 0, nil, err
}
return v, NewMockReaderMap(v, s), nil
}
func (s *MockStore) Commit(changeset *corestore.Changeset) (corestore.Hash, error) {
err := s.Committer.WriteChangeset(changeset)
if err != nil {
return []byte{}, err
}
_, err = s.Committer.Commit(changeset.Version)
return []byte{}, err
}
func (s *MockStore) StateAt(version uint64) (corestore.ReaderMap, error) {
info, err := s.Committer.GetCommitInfo(version)
if err != nil || info == nil {
return nil, fmt.Errorf("failed to get commit info for version %d: %w", version, err)
}
return NewMockReaderMap(version, s), nil
}
func (s *MockStore) GetStateCommitment() storev2.Committer {
return s.Committer
}
func (s *MockStore) Query(storeKey []byte, version uint64, key []byte, prove bool) (storev2.QueryResult, error) {
state, err := s.StateAt(version)
if err != nil {
return storev2.QueryResult{}, err
}
reader, err := state.GetReader(storeKey)
if err != nil {
return storev2.QueryResult{}, err
}
value, err := reader.Get(key)
if err != nil {
return storev2.QueryResult{}, err
}
res := storev2.QueryResult{
Key: key,
Value: value,
Version: version,
}
return res, err
}
func (s *MockStore) LastCommitID() (proof.CommitID, error) {
v, err := s.GetStateCommitment().GetLatestVersion()
bz := sha256.Sum256([]byte{})
return proof.CommitID{
Version: int64(v),
Hash: bz[:],
}, err
}
func (s *MockStore) SetInitialVersion(v uint64) error {
return s.Committer.SetInitialVersion(v)
}

View File

@ -1,23 +0,0 @@
package log
import (
cmtlog "github.com/cometbft/cometbft/libs/log"
"cosmossdk.io/log"
)
var _ cmtlog.Logger = (*CometLoggerWrapper)(nil)
// CometLoggerWrapper provides a wrapper around a cosmossdk.io/log instance.
// It implements CometBFT's Logger interface.
type CometLoggerWrapper struct {
log.Logger
}
// With returns a new wrapped logger with additional context provided by a set
// of key/value tuples. The number of tuples must be even and the key of the
// tuple must be a string.
func (cmt CometLoggerWrapper) With(keyVals ...interface{}) cmtlog.Logger {
logger := cmt.Logger.With(keyVals...)
return CometLoggerWrapper{logger}
}

View File

@ -1,16 +0,0 @@
package mempool
var DefaultMaxTx = -1
// Config defines the configurations for the SDK built-in app-side mempool implementations.
type Config struct {
// MaxTxs defines the maximum number of transactions that can be in the mempool.
MaxTxs int `mapstructure:"max-txs" toml:"max-txs" comment:"max-txs defines the maximum number of transactions that can be in the mempool. A value of 0 indicates an unbounded mempool, a negative value disables the app-side mempool."`
}
// DefaultConfig returns a default configuration for the SDK built-in app-side mempool implementations.
func DefaultConfig() Config {
return Config{
MaxTxs: DefaultMaxTx,
}
}

View File

@ -1,2 +0,0 @@
// Package mempool defines a few mempool services which can be used in conjunction with your consensus implementation.
package mempool

View File

@ -1,46 +0,0 @@
package mempool
import (
"context"
"errors"
"cosmossdk.io/core/transaction"
)
var (
ErrTxNotFound = errors.New("tx not found in mempool")
ErrMempoolTxMaxCapacity = errors.New("pool reached max tx capacity")
)
// Mempool defines the required methods of an application's mempool.
type Mempool[T transaction.Tx] interface {
// Insert attempts to insert a Tx into the app-side mempool returning
// an error upon failure.
Insert(context.Context, T) error
// Select returns an Iterator over the app-side mempool. If txs are specified,
// then they shall be incorporated into the Iterator. The Iterator is not thread-safe to use.
Select(context.Context, []T) Iterator[T]
// SelectBy use callback to iterate over the mempool, it's thread-safe to use.
SelectBy(context.Context, []T, func(T) bool)
// CountTx returns the number of transactions currently in the mempool.
CountTx() int
// Remove attempts to remove a transaction from the mempool, returning an error
// upon failure.
Remove(T) error
}
// Iterator defines an app-side mempool iterator interface that is as minimal as
// possible. The order of iteration is determined by the app-side mempool
// implementation.
type Iterator[T transaction.Tx] interface {
// Next returns the next transaction from the mempool. If there are no more
// transactions, it returns nil.
Next() Iterator[T]
// Tx returns the transaction at the current position of the iterator.
Tx() T
}

View File

@ -1,28 +0,0 @@
package mempool
import (
"context"
"cosmossdk.io/core/transaction"
sdk "github.com/cosmos/cosmos-sdk/types"
)
var (
_ Mempool[sdk.Tx] = (*NoOpMempool[sdk.Tx])(nil) // verify interface at compile time
_ Mempool[transaction.Tx] = (*NoOpMempool[transaction.Tx])(nil)
)
// NoOpMempool defines a no-op mempool. Transactions are completely discarded and
// ignored when BaseApp interacts with the mempool.
//
// Note: When this mempool is used, it assumed that an application will rely
// on CometBFT's transaction ordering defined in `RequestPrepareProposal`, which
// is FIFO-ordered by default.
type NoOpMempool[T transaction.Tx] struct{}
func (NoOpMempool[T]) Insert(context.Context, T) error { return nil }
func (NoOpMempool[T]) Select(context.Context, []T) Iterator[T] { return nil }
func (NoOpMempool[T]) SelectBy(context.Context, []T, func(T) bool) {}
func (NoOpMempool[T]) CountTx() int { return 0 }
func (NoOpMempool[T]) Remove(T) error { return nil }

View File

@ -1,169 +0,0 @@
package oe
import (
"bytes"
"context"
"encoding/hex"
"math/rand"
"sync"
"time"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
)
// FinalizeBlockFunc is the function that is called by the OE to finalize the
// block. It is the same as the one in the ABCI app.
type FinalizeBlockFunc[T transaction.Tx] func(context.Context, *abci.FinalizeBlockRequest) (*server.BlockResponse, store.WriterMap, []T, error)
// OptimisticExecution is a struct that contains the OE context. It is used to
// run the FinalizeBlock function in a goroutine, and to abort it if needed.
type OptimisticExecution[T transaction.Tx] struct {
finalizeBlockFunc FinalizeBlockFunc[T] // ABCI FinalizeBlock function with a context
logger log.Logger
mtx sync.Mutex
stopCh chan struct{}
request *abci.FinalizeBlockRequest
response *FinalizeBlockResponse[T]
err error
cancelFunc func() // cancel function for the context
initialized bool // A boolean value indicating whether the struct has been initialized
// debugging/testing options
abortRate int // number from 0 to 100 that determines the percentage of OE that should be aborted
}
type FinalizeBlockResponse[T transaction.Tx] struct {
Resp *server.BlockResponse
StateChanges store.WriterMap
DecodedTxs []T
}
// NewOptimisticExecution initializes the Optimistic Execution context but does not start it.
func NewOptimisticExecution[T transaction.Tx](logger log.Logger, fn FinalizeBlockFunc[T], opts ...func(*OptimisticExecution[T])) *OptimisticExecution[T] {
logger = logger.With(log.ModuleKey, "oe")
oe := &OptimisticExecution[T]{logger: logger, finalizeBlockFunc: fn}
for _, opt := range opts {
opt(oe)
}
return oe
}
// WithAbortRate sets the abort rate for the OE. The abort rate is a number from
// 0 to 100 that determines the percentage of OE that should be aborted.
// This is for testing purposes only and must not be used in production.
func WithAbortRate[T transaction.Tx](rate int) func(*OptimisticExecution[T]) {
return func(oe *OptimisticExecution[T]) {
oe.abortRate = rate
}
}
// Reset resets the OE context. Must be called whenever we want to invalidate
// the current OE.
func (oe *OptimisticExecution[T]) Reset() {
oe.mtx.Lock()
defer oe.mtx.Unlock()
oe.request = nil
oe.response = nil
oe.err = nil
oe.initialized = false
}
// Initialized returns true if the OE was initialized, meaning that it contains
// a request and it was run or it is running.
func (oe *OptimisticExecution[T]) Initialized() bool {
if oe == nil {
return false
}
oe.mtx.Lock()
defer oe.mtx.Unlock()
return oe.initialized
}
// Execute initializes the OE and starts it in a goroutine.
func (oe *OptimisticExecution[T]) Execute(req *abci.ProcessProposalRequest) {
oe.mtx.Lock()
defer oe.mtx.Unlock()
oe.stopCh = make(chan struct{})
oe.request = &abci.FinalizeBlockRequest{
Txs: req.Txs,
DecidedLastCommit: req.ProposedLastCommit,
Misbehavior: req.Misbehavior,
Hash: req.Hash,
Height: req.Height,
Time: req.Time,
NextValidatorsHash: req.NextValidatorsHash,
ProposerAddress: req.ProposerAddress,
}
oe.logger.Debug("OE started", "height", req.Height, "hash", hex.EncodeToString(req.Hash), "time", req.Time.String())
ctx, cancel := context.WithCancel(context.Background())
oe.cancelFunc = cancel
oe.initialized = true
go func() {
start := time.Now()
resp, stateChanges, decodedTxs, err := oe.finalizeBlockFunc(ctx, oe.request)
oe.mtx.Lock()
executionTime := time.Since(start)
oe.logger.Debug("OE finished", "duration", executionTime.String(), "height", oe.request.Height, "hash", hex.EncodeToString(oe.request.Hash))
oe.response, oe.err = &FinalizeBlockResponse[T]{
Resp: resp,
StateChanges: stateChanges,
DecodedTxs: decodedTxs,
}, err
close(oe.stopCh)
oe.mtx.Unlock()
}()
}
// AbortIfNeeded aborts the OE if the request hash is not the same as the one in
// the running OE. Returns true if the OE was aborted.
func (oe *OptimisticExecution[T]) AbortIfNeeded(reqHash []byte) bool {
if oe == nil {
return false
}
oe.mtx.Lock()
defer oe.mtx.Unlock()
if !bytes.Equal(oe.request.Hash, reqHash) {
oe.logger.Error("OE aborted due to hash mismatch", "oe_hash", hex.EncodeToString(oe.request.Hash), "req_hash", hex.EncodeToString(reqHash), "oe_height", oe.request.Height, "req_height", oe.request.Height)
oe.cancelFunc()
return true
} else if oe.abortRate > 0 && rand.Intn(100) < oe.abortRate {
// this is for test purposes only, we can emulate a certain percentage of
// OE needed to be aborted.
oe.cancelFunc()
oe.logger.Error("OE aborted due to test abort rate")
return true
}
return false
}
// Abort aborts the OE unconditionally and waits for it to finish.
func (oe *OptimisticExecution[T]) Abort() {
if oe == nil || oe.cancelFunc == nil {
return
}
oe.cancelFunc()
<-oe.stopCh
}
// WaitResult waits for the OE to finish and returns the result.
func (oe *OptimisticExecution[T]) WaitResult() (*FinalizeBlockResponse[T], error) {
<-oe.stopCh
return oe.response, oe.err
}

View File

@ -1,36 +0,0 @@
package oe
import (
"context"
"errors"
"testing"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"github.com/stretchr/testify/assert"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
)
func testFinalizeBlock[T transaction.Tx](context.Context, *abci.FinalizeBlockRequest) (*server.BlockResponse, store.WriterMap, []T, error) {
return nil, nil, nil, errors.New("test error")
}
func TestOptimisticExecution(t *testing.T) {
oe := NewOptimisticExecution[transaction.Tx](log.NewNopLogger(), testFinalizeBlock)
oe.Execute(&abci.ProcessProposalRequest{
Hash: []byte("test"),
})
assert.True(t, oe.Initialized())
resp, err := oe.WaitResult()
assert.Equal(t, &FinalizeBlockResponse[transaction.Tx]{}, resp) // empty response
assert.EqualError(t, err, "test error")
assert.False(t, oe.AbortIfNeeded([]byte("test")))
assert.True(t, oe.AbortIfNeeded([]byte("wrong_hash")))
oe.Reset()
}

View File

@ -1,57 +0,0 @@
package cometbft
import (
cmtcrypto "github.com/cometbft/cometbft/crypto"
cmted22519 "github.com/cometbft/cometbft/crypto/ed25519"
"cosmossdk.io/core/transaction"
"cosmossdk.io/server/v2/cometbft/handlers"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/server/v2/cometbft/types"
"cosmossdk.io/server/v2/streaming"
"cosmossdk.io/store/v2/snapshots"
)
type keyGenF = func() (cmtcrypto.PrivKey, error)
// ServerOptions defines the options for the CometBFT server.
// When an option takes a map[string]any, it can access the app.tom's cometbft section and the config.toml config.
type ServerOptions[T transaction.Tx] struct {
PrepareProposalHandler handlers.PrepareHandler[T]
ProcessProposalHandler handlers.ProcessHandler[T]
CheckTxHandler handlers.CheckTxHandler[T]
VerifyVoteExtensionHandler handlers.VerifyVoteExtensionHandler
ExtendVoteHandler handlers.ExtendVoteHandler
KeygenF keyGenF
// Set mempool for the consensus module.
Mempool func(cfg map[string]any) mempool.Mempool[T]
// Set streaming manager for the consensus module.
StreamingManager streaming.Manager
// Set snapshot options for the consensus module.
SnapshotOptions func(cfg map[string]any) snapshots.SnapshotOptions
// Allows additional snapshotter implementations to be used for creating and restoring snapshots.
SnapshotExtensions []snapshots.ExtensionSnapshotter
AddrPeerFilter types.PeerFilter // filter peers by address and port
IdPeerFilter types.PeerFilter // filter peers by node ID
}
// DefaultServerOptions returns the default server options.
// It defaults to a NoOpMempool and NoOp handlers.
func DefaultServerOptions[T transaction.Tx]() ServerOptions[T] {
return ServerOptions[T]{
PrepareProposalHandler: handlers.NoOpPrepareProposal[T](),
ProcessProposalHandler: handlers.NoOpProcessProposal[T](),
CheckTxHandler: nil,
VerifyVoteExtensionHandler: handlers.NoOpVerifyVoteExtensionHandler(),
ExtendVoteHandler: handlers.NoOpExtendVote(),
Mempool: func(cfg map[string]any) mempool.Mempool[T] { return mempool.NoOpMempool[T]{} },
StreamingManager: streaming.Manager{},
SnapshotOptions: func(cfg map[string]any) snapshots.SnapshotOptions { return snapshots.NewSnapshotOptions(0, 0) },
SnapshotExtensions: []snapshots.ExtensionSnapshotter{},
AddrPeerFilter: nil,
IdPeerFilter: nil,
KeygenF: func() (cmtcrypto.PrivKey, error) { return cmted22519.GenPrivKey(), nil },
}
}

View File

@ -1,135 +0,0 @@
package cometbft
import (
"context"
"strings"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
crypto "github.com/cometbft/cometbft/api/cometbft/crypto/v1"
errorsmod "cosmossdk.io/errors/v2"
cometerrors "cosmossdk.io/server/v2/cometbft/types/errors"
)
func (c *consensus[T]) handleQueryP2P(path []string) (*abci.QueryResponse, error) {
// "/p2p" prefix for p2p queries
if len(path) < 4 {
return nil, errorsmod.Wrap(cometerrors.ErrUnknownRequest, "path should be p2p filter <addr|id> <parameter>")
}
cmd, typ, arg := path[1], path[2], path[3]
if cmd == "filter" {
switch typ {
case "addr":
if c.addrPeerFilter != nil {
return c.addrPeerFilter(arg)
}
case "id":
if c.idPeerFilter != nil {
return c.idPeerFilter(arg)
}
}
return &abci.QueryResponse{}, nil
}
return nil, errorsmod.Wrap(cometerrors.ErrUnknownRequest, "expected second parameter to be 'filter'")
}
// handleQueryApp handles the query requests for the application.
// It expects the path parameter to have at least two elements.
// The second element of the path can be either 'simulate' or 'version'.
// If the second element is 'simulate', it decodes the request data into a transaction,
// simulates the transaction using the application, and returns the simulation result.
// If the second element is 'version', it returns the version of the application.
// If the second element is neither 'simulate' nor 'version', it returns an error indicating an unknown query.
func (c *consensus[T]) handleQueryApp(ctx context.Context, path []string, req *abci.QueryRequest) (*abci.QueryResponse, error) {
if len(path) < 2 {
return nil, errorsmod.Wrap(
cometerrors.ErrUnknownRequest,
"expected second parameter to be either 'simulate' or 'version', neither was present",
)
}
switch path[1] {
case "simulate":
tx, err := c.appCodecs.TxCodec.Decode(req.Data)
if err != nil {
return nil, errorsmod.Wrap(err, "failed to decode tx")
}
txResult, _, err := c.app.Simulate(ctx, tx)
if err != nil {
return nil, errorsmod.Wrap(err, "failed to simulate tx")
}
bz, err := intoABCISimulationResponse(
txResult,
c.indexedABCIEvents,
c.cfg.AppTomlConfig.DisableIndexABCIEvents,
)
if err != nil {
return nil, errorsmod.Wrap(err, "failed to marshal txResult")
}
return &abci.QueryResponse{
Codespace: cometerrors.RootCodespace,
Value: bz,
Height: req.Height,
}, nil
case "version":
return &abci.QueryResponse{
Codespace: cometerrors.RootCodespace,
Value: []byte(c.version),
Height: req.Height,
}, nil
}
return nil, errorsmod.Wrapf(cometerrors.ErrUnknownRequest, "unknown query: %s", path)
}
func (c *consensus[T]) handleQueryStore(path []string, req *abci.QueryRequest) (*abci.QueryResponse, error) {
req.Path = "/" + strings.Join(path[1:], "/")
if req.Height <= 1 && req.Prove {
return nil, errorsmod.Wrap(
cometerrors.ErrInvalidRequest,
"cannot query with proof when height <= 1; please provide a valid height",
)
}
// "/store/<storeName>" for store queries
storeName := path[1]
storeNameBz := []byte(storeName) // TODO fastpath?
qRes, err := c.store.Query(storeNameBz, uint64(req.Height), req.Data, req.Prove)
if err != nil {
return nil, err
}
res := &abci.QueryResponse{
Codespace: cometerrors.RootCodespace,
Height: int64(qRes.Version),
Key: qRes.Key,
Value: qRes.Value,
}
if req.Prove {
for _, proof := range qRes.ProofOps {
bz, err := proof.Proof.Marshal()
if err != nil {
return nil, errorsmod.Wrap(err, "failed to marshal proof")
}
res.ProofOps = &crypto.ProofOps{
Ops: []crypto.ProofOp{
{
Type: proof.Type,
Key: proof.Key,
Data: bz,
},
},
}
}
}
return res, nil
}

View File

@ -1,401 +0,0 @@
package cometbft
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"sync/atomic"
abciserver "github.com/cometbft/cometbft/abci/server"
abci "github.com/cometbft/cometbft/abci/types"
cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands"
cmtcfg "github.com/cometbft/cometbft/config"
"github.com/cometbft/cometbft/node"
"github.com/cometbft/cometbft/p2p"
pvm "github.com/cometbft/cometbft/privval"
"github.com/cometbft/cometbft/proxy"
gogoproto "github.com/cosmos/gogoproto/proto"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"google.golang.org/grpc"
addresscodec "cosmossdk.io/core/address"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/registry"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
"cosmossdk.io/schema/appdata"
"cosmossdk.io/schema/decoding"
"cosmossdk.io/schema/indexer"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/appmanager"
cometlog "cosmossdk.io/server/v2/cometbft/log"
"cosmossdk.io/server/v2/cometbft/mempool"
"cosmossdk.io/server/v2/cometbft/oe"
"cosmossdk.io/server/v2/cometbft/types"
"cosmossdk.io/store/v2/snapshots"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
const ServerName = "comet"
var (
_ serverv2.ServerComponent[transaction.Tx] = (*CometBFTServer[transaction.Tx])(nil)
_ serverv2.HasCLICommands = (*CometBFTServer[transaction.Tx])(nil)
_ serverv2.HasStartFlags = (*CometBFTServer[transaction.Tx])(nil)
)
type CometBFTServer[T transaction.Tx] struct {
Node *node.Node
Consensus abci.Application
logger log.Logger
serverOptions ServerOptions[T]
config Config
cfgOptions []CfgOption
app appmanager.AppManager[T]
txCodec transaction.Codec[T]
store types.Store
}
// AppCodecs contains all codecs that the CometBFT server requires
// provided by the application. They are extracted in struct to not be API
// breaking once amino is completely deprecated or new codecs should be added.
type AppCodecs[T transaction.Tx] struct {
TxCodec transaction.Codec[T]
// The following codecs are only required for the gRPC services
AppCodec codec.Codec
LegacyAmino registry.AminoRegistrar
ConsensusAddressCodec addresscodec.Codec
}
func New[T transaction.Tx](
logger log.Logger,
appName string,
store types.Store,
app appmanager.AppManager[T],
appCodecs AppCodecs[T],
queryHandlers map[string]appmodulev2.Handler,
decoderResolver decoding.DecoderResolver,
serverOptions ServerOptions[T],
cfg server.ConfigMap,
cfgOptions ...CfgOption,
) (*CometBFTServer[T], error) {
srv := &CometBFTServer[T]{
serverOptions: serverOptions,
cfgOptions: cfgOptions,
app: app,
txCodec: appCodecs.TxCodec,
store: store,
}
srv.logger = logger.With(log.ModuleKey, srv.Name())
home, _ := cfg[serverv2.FlagHome].(string)
// get configs (app.toml + config.toml) from viper
appTomlConfig := srv.Config().(*AppTomlConfig)
configTomlConfig := cmtcfg.DefaultConfig().SetRoot(home)
if len(cfg) > 0 {
if err := serverv2.UnmarshalSubConfig(cfg, srv.Name(), &appTomlConfig); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
if err := serverv2.UnmarshalSubConfig(cfg, "", &configTomlConfig); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
}
srv.config = Config{
ConfigTomlConfig: configTomlConfig,
AppTomlConfig: appTomlConfig,
}
chainID, _ := cfg[FlagChainID].(string)
if chainID == "" {
// fallback to genesis chain-id
reader, err := os.Open(srv.config.ConfigTomlConfig.GenesisFile())
if err != nil {
return nil, fmt.Errorf("failed to open genesis file: %w", err)
}
defer reader.Close()
chainID, err = genutiltypes.ParseChainIDFromGenesis(reader)
if err != nil {
return nil, fmt.Errorf("failed to parse chain-id from genesis file: %w", err)
}
}
indexedABCIEvents := make(map[string]struct{}, len(srv.config.AppTomlConfig.IndexABCIEvents))
for _, e := range srv.config.AppTomlConfig.IndexABCIEvents {
indexedABCIEvents[e] = struct{}{}
}
sc := store.GetStateCommitment().(snapshots.CommitSnapshotter)
snapshotStore, err := GetSnapshotStore(srv.config.ConfigTomlConfig.RootDir)
if err != nil {
return nil, err
}
// initialize the indexer
var listener *appdata.Listener
if indexerCfg := srv.config.AppTomlConfig.Indexer; len(indexerCfg.Target) > 0 {
indexingTarget, err := indexer.StartIndexing(indexer.IndexingOptions{
Config: indexerCfg,
Resolver: decoderResolver,
Logger: logger.With(log.ModuleKey, "indexer"),
SyncSource: nil, // TODO: Support catch-up syncs
AddressCodec: appCodecs.AppCodec.InterfaceRegistry().SigningContext().AddressCodec(),
})
if err != nil {
return nil, fmt.Errorf("failed to start indexing: %w", err)
}
listener = &indexingTarget.Listener
}
// snapshot manager
snapshotManager := snapshots.NewManager(
snapshotStore,
srv.serverOptions.SnapshotOptions(cfg),
sc,
nil, // extensions snapshotter registered below
logger,
)
if exts := serverOptions.SnapshotExtensions; len(exts) > 0 {
if err := snapshotManager.RegisterExtensions(serverOptions.SnapshotExtensions...); err != nil {
return nil, fmt.Errorf("failed to register snapshot extensions: %w", err)
}
}
c := &consensus[T]{
appName: appName,
version: getCometBFTServerVersion(),
app: app,
cfg: srv.config,
store: store,
logger: logger,
appCodecs: appCodecs,
listener: listener,
snapshotManager: snapshotManager,
streamingManager: srv.serverOptions.StreamingManager,
mempool: srv.serverOptions.Mempool(cfg),
lastCommittedHeight: atomic.Int64{},
prepareProposalHandler: srv.serverOptions.PrepareProposalHandler,
processProposalHandler: srv.serverOptions.ProcessProposalHandler,
verifyVoteExt: srv.serverOptions.VerifyVoteExtensionHandler,
checkTxHandler: srv.serverOptions.CheckTxHandler,
extendVote: srv.serverOptions.ExtendVoteHandler,
chainID: chainID,
indexedABCIEvents: indexedABCIEvents,
initialHeight: 0,
queryHandlersMap: queryHandlers,
getProtoRegistry: sync.OnceValues(gogoproto.MergedRegistry),
addrPeerFilter: srv.serverOptions.AddrPeerFilter,
idPeerFilter: srv.serverOptions.IdPeerFilter,
cfgMap: cfg,
}
c.optimisticExec = oe.NewOptimisticExecution(
logger,
c.internalFinalizeBlock,
)
srv.Consensus = c
return srv, nil
}
// NewWithConfigOptions creates a new CometBFT server with the provided config options.
// It is *not* a fully functional server (since it has been created without dependencies)
// The returned server should only be used to get and set configuration.
func NewWithConfigOptions[T transaction.Tx](opts ...CfgOption) *CometBFTServer[T] {
return &CometBFTServer[T]{
cfgOptions: opts,
}
}
func (s *CometBFTServer[T]) Name() string {
return ServerName
}
func (s *CometBFTServer[T]) Start(ctx context.Context) error {
wrappedLogger := cometlog.CometLoggerWrapper{Logger: s.logger}
if s.config.AppTomlConfig.Standalone {
svr, err := abciserver.NewServer(s.config.AppTomlConfig.Address, s.config.AppTomlConfig.Transport, s.Consensus)
if err != nil {
return fmt.Errorf("error creating listener: %w", err)
}
svr.SetLogger(wrappedLogger)
return svr.Start()
}
nodeKey, err := p2p.LoadOrGenNodeKey(s.config.ConfigTomlConfig.NodeKeyFile())
if err != nil {
return err
}
pv, err := pvm.LoadOrGenFilePV(
s.config.ConfigTomlConfig.PrivValidatorKeyFile(),
s.config.ConfigTomlConfig.PrivValidatorStateFile(),
s.serverOptions.KeygenF,
)
if err != nil {
return err
}
s.Node, err = node.NewNode(
ctx,
s.config.ConfigTomlConfig,
pv,
nodeKey,
proxy.NewConsensusSyncLocalClientCreator(s.Consensus),
getGenDocProvider(s.config.ConfigTomlConfig),
cmtcfg.DefaultDBProvider,
node.DefaultMetricsProvider(s.config.ConfigTomlConfig.Instrumentation),
wrappedLogger,
)
if err != nil {
return err
}
s.logger.Info("starting consensus server")
return s.Node.Start()
}
func (s *CometBFTServer[T]) Stop(context.Context) error {
if s.Node != nil && s.Node.IsRunning() {
s.logger.Info("stopping consensus server")
return s.Node.Stop()
}
return nil
}
// returns a function which returns the genesis doc from the genesis file.
func getGenDocProvider(cfg *cmtcfg.Config) func() (node.ChecksummedGenesisDoc, error) {
return func() (node.ChecksummedGenesisDoc, error) {
appGenesis, err := genutiltypes.AppGenesisFromFile(cfg.GenesisFile())
if err != nil {
return node.ChecksummedGenesisDoc{
Sha256Checksum: []byte{},
}, err
}
gen, err := appGenesis.ToGenesisDoc()
if err != nil {
return node.ChecksummedGenesisDoc{
Sha256Checksum: []byte{},
}, err
}
genbz, err := gen.AppState.MarshalJSON()
if err != nil {
return node.ChecksummedGenesisDoc{
Sha256Checksum: []byte{},
}, err
}
bz, err := json.Marshal(genbz)
if err != nil {
return node.ChecksummedGenesisDoc{
Sha256Checksum: []byte{},
}, err
}
sum := sha256.Sum256(bz)
return node.ChecksummedGenesisDoc{
GenesisDoc: gen,
Sha256Checksum: sum[:],
}, nil
}
}
func (s *CometBFTServer[T]) StartCmdFlags() *pflag.FlagSet {
flags := pflag.NewFlagSet(s.Name(), pflag.ExitOnError)
flags.String(FlagAddress, "tcp://127.0.0.1:26658", "Listen address")
flags.String(FlagTransport, "socket", "Transport protocol: socket, grpc")
flags.Uint64(FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node")
flags.Uint64(FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node")
flags.Bool(FlagTrace, false, "Provide full stack traces for errors in ABCI Log")
flags.Bool(Standalone, false, "Run app without CometBFT")
flags.Int(FlagMempoolMaxTxs, mempool.DefaultMaxTx, "Sets MaxTx value for the app-side mempool")
// add comet flags, we use an empty command to avoid duplicating CometBFT's AddNodeFlags.
// we can then merge the flag sets.
emptyCmd := &cobra.Command{}
cmtcmd.AddNodeFlags(emptyCmd)
flags.AddFlagSet(emptyCmd.Flags())
return flags
}
func (s *CometBFTServer[T]) CLICommands() serverv2.CLIConfig {
return serverv2.CLIConfig{
Commands: []*cobra.Command{
StatusCommand(),
ShowNodeIDCmd(),
ShowValidatorCmd(),
ShowAddressCmd(),
VersionCmd(),
s.BootstrapStateCmd(),
cmtcmd.ResetAllCmd,
cmtcmd.ResetStateCmd,
},
Queries: []*cobra.Command{
QueryBlockCmd(),
QueryBlocksCmd(),
QueryBlockResultsCmd(),
},
}
}
// CometBFT is a special server, it has config in config.toml and app.toml
// Config returns the (app.toml) server configuration.
func (s *CometBFTServer[T]) Config() any {
if s.config.AppTomlConfig == nil || s.config.AppTomlConfig.Address == "" {
cfg := &Config{AppTomlConfig: DefaultAppTomlConfig()}
// overwrite the default config with the provided options
for _, opt := range s.cfgOptions {
opt(cfg)
}
return cfg.AppTomlConfig
}
return s.config.AppTomlConfig
}
// WriteCustomConfigAt writes the default cometbft config.toml
func (s *CometBFTServer[T]) WriteCustomConfigAt(configPath string) error {
cfg := &Config{ConfigTomlConfig: cmtcfg.DefaultConfig()}
for _, opt := range s.cfgOptions {
opt(cfg)
}
cmtcfg.WriteConfigFile(filepath.Join(configPath, "config.toml"), cfg.ConfigTomlConfig)
return nil
}
// gRPCServiceRegistrar returns a function that registers the CometBFT gRPC service
// Those services are defined for backward compatibility.
// Eventually, they will be removed in favor of the new gRPC services.
func (s *CometBFTServer[T]) GRPCServiceRegistrar(
clientCtx client.Context,
cfg server.ConfigMap,
) func(srv *grpc.Server) error {
return gRPCServiceRegistrar[T](clientCtx, cfg, s.Config().(*AppTomlConfig), s.txCodec, s.Consensus, s.app)
}

View File

@ -1,70 +0,0 @@
package cometbft
import (
"context"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"cosmossdk.io/core/comet"
corecontext "cosmossdk.io/core/context"
)
func contextWithCometInfo(ctx context.Context, info comet.Info) context.Context {
return context.WithValue(ctx, corecontext.CometInfoKey, info)
}
// toCoreEvidence takes comet evidence and returns sdk evidence
func toCoreEvidence(ev []abci.Misbehavior) []comet.Evidence {
evidence := make([]comet.Evidence, len(ev))
for i, e := range ev {
evidence[i] = comet.Evidence{
Type: comet.MisbehaviorType(e.Type),
Height: e.Height,
Time: e.Time,
TotalVotingPower: e.TotalVotingPower,
Validator: comet.Validator{
Address: e.Validator.Address,
Power: e.Validator.Power,
},
}
}
return evidence
}
// toCoreCommitInfo takes comet commit info and returns sdk commit info
func toCoreCommitInfo(commit abci.CommitInfo) comet.CommitInfo {
ci := comet.CommitInfo{
Round: commit.Round,
}
for _, v := range commit.Votes {
ci.Votes = append(ci.Votes, comet.VoteInfo{
Validator: comet.Validator{
Address: v.Validator.Address,
Power: v.Validator.Power,
},
BlockIDFlag: comet.BlockIDFlag(v.BlockIdFlag),
})
}
return ci
}
// toCoreExtendedCommitInfo takes comet extended commit info and returns sdk commit info
func toCoreExtendedCommitInfo(commit abci.ExtendedCommitInfo) comet.CommitInfo {
ci := comet.CommitInfo{
Round: commit.Round,
Votes: make([]comet.VoteInfo, len(commit.Votes)),
}
for i, v := range commit.Votes {
ci.Votes[i] = comet.VoteInfo{
Validator: comet.Validator{
Address: v.Validator.Address,
Power: v.Validator.Power,
},
BlockIDFlag: comet.BlockIDFlag(v.BlockIdFlag),
}
}
return ci
}

View File

@ -1,192 +0,0 @@
package cometbft
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
"github.com/cosmos/gogoproto/proto"
"cosmossdk.io/store/v2/snapshots"
snapshottypes "cosmossdk.io/store/v2/snapshots/types"
)
// GetSnapshotStore returns a snapshot store for the given application options.
// It creates a directory for storing snapshots if it doesn't exist.
// It initializes a GoLevelDB database for storing metadata of the snapshots.
// The snapshot store is then created using the initialized database and directory.
// If any error occurs during the process, it is returned along with a nil snapshot store.
func GetSnapshotStore(rootDir string) (*snapshots.Store, error) {
snapshotDir := filepath.Join(rootDir, "data", "snapshots")
if err := os.MkdirAll(snapshotDir, 0o750); err != nil {
return nil, fmt.Errorf("failed to create snapshots directory: %w", err)
}
snapshotStore, err := snapshots.NewStore(snapshotDir)
if err != nil {
return nil, err
}
return snapshotStore, nil
}
// ApplySnapshotChunk implements types.Application.
func (c *consensus[T]) ApplySnapshotChunk(_ context.Context, req *abci.ApplySnapshotChunkRequest) (*abci.ApplySnapshotChunkResponse, error) {
if c.snapshotManager == nil {
c.logger.Error("snapshot manager not configured")
return &abci.ApplySnapshotChunkResponse{Result: abci.APPLY_SNAPSHOT_CHUNK_RESULT_ABORT}, nil
}
_, err := c.snapshotManager.RestoreChunk(req.Chunk)
switch {
case err == nil:
return &abci.ApplySnapshotChunkResponse{Result: abci.APPLY_SNAPSHOT_CHUNK_RESULT_ACCEPT}, nil
case errors.Is(err, snapshottypes.ErrChunkHashMismatch):
c.logger.Error(
"chunk checksum mismatch; rejecting sender and requesting refetch",
"chunk", req.Index,
"sender", req.Sender,
"err", err,
)
return &abci.ApplySnapshotChunkResponse{
Result: abci.APPLY_SNAPSHOT_CHUNK_RESULT_RETRY,
RefetchChunks: []uint32{req.Index},
RejectSenders: []string{req.Sender},
}, nil
default:
c.logger.Error("failed to restore snapshot", "err", err)
return &abci.ApplySnapshotChunkResponse{Result: abci.APPLY_SNAPSHOT_CHUNK_RESULT_ABORT}, nil
}
}
// ListSnapshots implements types.Application.
func (c *consensus[T]) ListSnapshots(_ context.Context, ctx *abci.ListSnapshotsRequest) (*abci.ListSnapshotsResponse, error) {
if c.snapshotManager == nil {
return nil, nil
}
snapshots, err := c.snapshotManager.List()
if err != nil {
c.logger.Error("failed to list snapshots", "err", err)
return nil, err
}
resp := &abci.ListSnapshotsResponse{}
for _, snapshot := range snapshots {
abciSnapshot, err := snapshotToABCI(snapshot)
if err != nil {
c.logger.Error("failed to convert ABCI snapshots", "err", err)
return nil, err
}
resp.Snapshots = append(resp.Snapshots, &abciSnapshot)
}
return resp, nil
}
// LoadSnapshotChunk implements types.Application.
func (c *consensus[T]) LoadSnapshotChunk(_ context.Context, req *abci.LoadSnapshotChunkRequest) (*abci.LoadSnapshotChunkResponse, error) {
if c.snapshotManager == nil {
return &abci.LoadSnapshotChunkResponse{}, nil
}
chunk, err := c.snapshotManager.LoadChunk(req.Height, req.Format, req.Chunk)
if err != nil {
c.logger.Error(
"failed to load snapshot chunk",
"height", req.Height,
"format", req.Format,
"chunk", req.Chunk,
"err", err,
)
return nil, err
}
return &abci.LoadSnapshotChunkResponse{Chunk: chunk}, nil
}
// OfferSnapshot implements types.Application.
func (c *consensus[T]) OfferSnapshot(_ context.Context, req *abci.OfferSnapshotRequest) (*abci.OfferSnapshotResponse, error) {
if c.snapshotManager == nil {
c.logger.Error("snapshot manager not configured")
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_ABORT}, nil
}
if req.Snapshot == nil {
c.logger.Error("received nil snapshot")
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_REJECT}, nil
}
snapshot, err := snapshotFromABCI(req.Snapshot)
if err != nil {
c.logger.Error("failed to decode snapshot metadata", "err", err)
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_REJECT}, nil
}
err = c.snapshotManager.Restore(snapshot)
switch {
case err == nil:
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_ACCEPT}, nil
case errors.Is(err, snapshottypes.ErrUnknownFormat):
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_REJECT_FORMAT}, nil
case errors.Is(err, snapshottypes.ErrInvalidMetadata):
c.logger.Error(
"rejecting invalid snapshot",
"height", req.Snapshot.Height,
"format", req.Snapshot.Format,
"err", err,
)
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_REJECT}, nil
default:
c.logger.Error(
"failed to restore snapshot",
"height", req.Snapshot.Height,
"format", req.Snapshot.Format,
"err", err,
)
// We currently don't support resetting the IAVL stores and retrying a
// different snapshot, so we ask CometBFT to abort all snapshot restoration.
return &abci.OfferSnapshotResponse{Result: abci.OFFER_SNAPSHOT_RESULT_ABORT}, nil
}
}
// Converts an ABCI snapshot to a snapshot. Mainly to decode the SDK metadata.
func snapshotFromABCI(in *abci.Snapshot) (snapshottypes.Snapshot, error) {
snapshot := snapshottypes.Snapshot{
Height: in.Height,
Format: in.Format,
Chunks: in.Chunks,
Hash: in.Hash,
}
err := proto.Unmarshal(in.Metadata, &snapshot.Metadata)
if err != nil {
return snapshottypes.Snapshot{}, fmt.Errorf("failed to unmarshal snapshot metadata: %w", err)
}
return snapshot, nil
}
// Converts a Snapshot to its ABCI representation. Mainly to encode the SDK metadata.
func snapshotToABCI(s *snapshottypes.Snapshot) (abci.Snapshot, error) {
out := abci.Snapshot{
Height: s.Height,
Format: s.Format,
Chunks: s.Chunks,
Hash: s.Hash,
}
var err error
out.Metadata, err = proto.Marshal(&s.Metadata)
if err != nil {
return abci.Snapshot{}, fmt.Errorf("failed to marshal snapshot metadata: %w", err)
}
return out, nil
}

View File

@ -1,142 +0,0 @@
package cometbft
import (
"context"
"encoding/json"
"cosmossdk.io/core/event"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
errorsmod "cosmossdk.io/errors/v2"
"cosmossdk.io/schema/appdata"
"cosmossdk.io/server/v2/streaming"
)
// streamDeliverBlockChanges will stream all the changes happened during deliver block.
func (c *consensus[T]) streamDeliverBlockChanges(
ctx context.Context,
height int64,
txs [][]byte,
decodedTxs []T,
txResults []server.TxResult,
events []event.Event,
stateChanges []store.StateChanges,
) error {
// convert txresults to streaming txresults
streamingTxResults := make([]*streaming.ExecTxResult, len(txResults))
for i, txResult := range txResults {
space, code, log := errorsmod.ABCIInfo(txResult.Error, c.cfg.AppTomlConfig.Trace)
events, err := streaming.IntoStreamingEvents(txResult.Events)
if err != nil {
return err
}
streamingTxResults[i] = &streaming.ExecTxResult{
Code: code,
Codespace: space,
Log: log,
GasWanted: uint64ToInt64(txResult.GasWanted),
GasUsed: uint64ToInt64(txResult.GasUsed),
Events: events,
}
}
for _, streamingListener := range c.streamingManager.Listeners {
events, err := streaming.IntoStreamingEvents(events)
if err != nil {
return err
}
if err := streamingListener.ListenDeliverBlock(ctx, streaming.ListenDeliverBlockRequest{
BlockHeight: height,
Txs: txs,
TxResults: streamingTxResults,
Events: events,
}); err != nil {
c.logger.Error("ListenDeliverBlock listening hook failed", "height", height, "err", err)
}
if err := streamingListener.ListenStateChanges(ctx, intoStreamingKVPairs(stateChanges)); err != nil {
c.logger.Error("ListenStateChanges listening hook failed", "height", height, "err", err)
}
}
if c.listener == nil {
return nil
}
// stream the StartBlockData to the listener.
if c.listener.StartBlock != nil {
if err := c.listener.StartBlock(appdata.StartBlockData{
Height: uint64(height),
HeaderBytes: nil, // TODO: https://github.com/cosmos/cosmos-sdk/issues/22009
HeaderJSON: nil, // TODO: https://github.com/cosmos/cosmos-sdk/issues/22009
}); err != nil {
return err
}
}
// stream the TxData to the listener.
if c.listener.OnTx != nil {
for i, tx := range txs {
if err := c.listener.OnTx(appdata.TxData{
BlockNumber: uint64(height),
TxIndex: int32(i),
Bytes: func() ([]byte, error) { return tx, nil },
JSON: func() (json.RawMessage, error) {
return json.Marshal(decodedTxs[i])
},
}); err != nil {
return err
}
}
}
// stream the EventData to the listener.
if c.listener.OnEvent != nil {
if err := c.listener.OnEvent(appdata.EventData{Events: events}); err != nil {
return err
}
}
// stream the KVPairData to the listener.
if c.listener.OnKVPair != nil {
if err := c.listener.OnKVPair(appdata.KVPairData{Updates: stateChanges}); err != nil {
return err
}
}
// stream the CommitData to the listener.
if c.listener.Commit != nil {
if completionCallback, err := c.listener.Commit(appdata.CommitData{}); err != nil {
return err
} else if completionCallback != nil {
if err := completionCallback(); err != nil {
return err
}
}
}
return nil
}
func intoStreamingKVPairs(stateChanges []store.StateChanges) []*streaming.StoreKVPair {
// Calculate the total number of KV pairs to preallocate the slice with the required capacity.
totalKvPairs := 0
for _, accounts := range stateChanges {
totalKvPairs += len(accounts.StateChanges)
}
// Preallocate the slice with the required capacity.
streamKvPairs := make([]*streaming.StoreKVPair, 0, totalKvPairs)
for _, accounts := range stateChanges {
// Reducing the scope of address variable.
address := accounts.Actor
for _, kv := range accounts.StateChanges {
streamKvPairs = append(streamKvPairs, &streaming.StoreKVPair{
Address: address,
Key: kv.Key,
Value: kv.Value,
Delete: kv.Remove,
})
}
}
return streamKvPairs
}

View File

@ -1,17 +0,0 @@
package errors
import (
errorsmod "cosmossdk.io/errors/v2"
)
// RootCodespace is the codespace for all errors defined in this package
const RootCodespace = "cometbft-sdk"
var (
// ErrUnknownRequest to doc
ErrUnknownRequest = errorsmod.Register(RootCodespace, 1, "unknown request")
// ErrInvalidRequest defines an ABCI typed error where the request contains
// invalid data.
ErrInvalidRequest = errorsmod.Register(RootCodespace, 2, "invalid request")
)

View File

@ -1,6 +0,0 @@
package types
import abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
// PeerFilter responds to p2p filtering queries from Tendermint
type PeerFilter func(info string) (*abci.QueryResponse, error)

View File

@ -1,31 +0,0 @@
package types
import (
"cosmossdk.io/core/store"
storev2 "cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/proof"
)
type Store interface {
storev2.Backend
// GetLatestVersion returns the latest version that consensus has been made on
GetLatestVersion() (uint64, error)
// StateLatest returns a readonly view over the latest
// committed state of the store. Alongside the version
// associated with it.
StateLatest() (uint64, store.ReaderMap, error)
// SetInitialVersion sets the initial version of the store.
SetInitialVersion(uint64) error
// Commit commits the provided changeset and returns
// the new state root of the state.
Commit(*store.Changeset) (store.Hash, error)
// Query is a key/value query directly to the underlying database. This skips the appmanager
Query(storeKey []byte, version uint64, key []byte, prove bool) (storev2.QueryResult, error)
// LastCommitID returns a CommitID pertaining to the last commitment.
LastCommitID() (proof.CommitID, error)
}

View File

@ -1,13 +0,0 @@
package types
import (
"context"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
)
// VoteExtensionsHandler defines how to implement vote extension handlers
type VoteExtensionsHandler interface {
ExtendVote(context.Context, *abci.ExtendVoteRequest) (*abci.ExtendVoteResponse, error)
VerifyVoteExtension(context.Context, *abci.VerifyVoteExtensionRequest) (*abci.VerifyVoteExtensionResponse, error)
}

View File

@ -1,652 +0,0 @@
package cometbft
import (
"bytes"
"context"
"crypto/sha256"
"errors"
"fmt"
"math"
"slices"
"strings"
"time"
abci "github.com/cometbft/cometbft/api/cometbft/abci/v1"
cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
cryptoenc "github.com/cometbft/cometbft/crypto/encoding"
protoio "github.com/cosmos/gogoproto/io"
gogoproto "github.com/cosmos/gogoproto/proto"
gogoany "github.com/cosmos/gogoproto/types/any"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/event"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
errorsmod "cosmossdk.io/errors" // we aren't using errors/v2 as it doesn't support grpc status codes
"cosmossdk.io/server/v2/cometbft/handlers"
"cosmossdk.io/x/consensus/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
func queryResponse(res transaction.Msg, height int64) (*abci.QueryResponse, error) {
// this is a tied to protobuf due to client responses always being handled in protobuf
bz, err := gogoproto.Marshal(res)
if err != nil {
return nil, err
}
return &abci.QueryResponse{
Value: bz,
Height: height,
}, nil
}
// responseExecTxResultWithEvents returns an ABCI ExecTxResult object with fields
// filled in from the given error, gas values and events.
func responseExecTxResultWithEvents(err error, gw, gu uint64, events []abci.Event, debug bool) *abci.ExecTxResult {
space, code, log := errorsmod.ABCIInfo(err, debug)
return &abci.ExecTxResult{
Codespace: space,
Code: code,
Log: log,
GasWanted: int64(gw),
GasUsed: int64(gu),
Events: events,
}
}
// splitABCIQueryPath splits a string path using the delimiter '/'.
//
// e.g. "this/is/funny" becomes []string{"this", "is", "funny"}
func splitABCIQueryPath(requestPath string) (path []string) {
path = strings.Split(requestPath, "/")
// first element is empty string
if len(path) > 0 && path[0] == "" {
path = path[1:]
}
return path
}
func finalizeBlockResponse(
in *server.BlockResponse,
cp *cmtproto.ConsensusParams,
appHash []byte,
indexSet map[string]struct{},
cfg *AppTomlConfig,
) (*abci.FinalizeBlockResponse, error) {
events := make([]abci.Event, 0)
if !cfg.DisableABCIEvents {
var err error
events, err = intoABCIEvents(
append(in.BeginBlockEvents, in.EndBlockEvents...),
indexSet,
cfg.DisableIndexABCIEvents,
)
if err != nil {
return nil, err
}
}
txResults, err := intoABCITxResults(in.TxResults, indexSet, cfg)
if err != nil {
return nil, err
}
resp := &abci.FinalizeBlockResponse{
Events: events,
TxResults: txResults,
ValidatorUpdates: intoABCIValidatorUpdates(in.ValidatorUpdates),
AppHash: appHash,
ConsensusParamUpdates: cp,
}
return resp, nil
}
func intoABCIValidatorUpdates(updates []appmodulev2.ValidatorUpdate) []abci.ValidatorUpdate {
valsetUpdates := make([]abci.ValidatorUpdate, len(updates))
for i, v := range updates {
valsetUpdates[i] = abci.ValidatorUpdate{
PubKeyBytes: v.PubKey,
PubKeyType: v.PubKeyType,
Power: v.Power,
}
}
return valsetUpdates
}
func intoABCITxResults(
results []server.TxResult,
indexSet map[string]struct{},
cfg *AppTomlConfig,
) ([]*abci.ExecTxResult, error) {
res := make([]*abci.ExecTxResult, len(results))
for i := range results {
var err error
events := make([]abci.Event, 0)
if !cfg.DisableABCIEvents {
events, err = intoABCIEvents(results[i].Events, indexSet, cfg.DisableIndexABCIEvents)
if err != nil {
return nil, err
}
}
res[i] = responseExecTxResultWithEvents(
results[i].Error,
results[i].GasWanted,
results[i].GasUsed,
events,
cfg.Trace,
)
}
return res, nil
}
func intoABCIEvents(events []event.Event, indexSet map[string]struct{}, indexNone bool) ([]abci.Event, error) {
indexAll := len(indexSet) == 0
abciEvents := make([]abci.Event, len(events))
for i, e := range events {
attrs, err := e.Attributes()
if err != nil {
return nil, err
}
abciEvents[i] = abci.Event{
Type: e.Type,
Attributes: make([]abci.EventAttribute, len(attrs)),
}
for j, attr := range attrs {
_, index := indexSet[fmt.Sprintf("%s.%s", e.Type, attr.Key)]
abciEvents[i].Attributes[j] = abci.EventAttribute{
Key: attr.Key,
Value: attr.Value,
Index: !indexNone && (index || indexAll),
}
}
}
return abciEvents, nil
}
func intoABCISimulationResponse(txRes server.TxResult, indexSet map[string]struct{}, indexNone bool) ([]byte, error) {
abciEvents, err := intoABCIEvents(txRes.Events, indexSet, indexNone)
if err != nil {
return nil, err
}
msgResponses := make([]*gogoany.Any, len(txRes.Resp))
for i, resp := range txRes.Resp {
// use this hack to maintain the protov2 API here for now
anyMsg, err := gogoany.NewAnyWithCacheWithValue(resp)
if err != nil {
return nil, err
}
msgResponses[i] = anyMsg
}
errMsg := ""
if txRes.Error != nil {
errMsg = txRes.Error.Error()
}
res := &sdk.SimulationResponse{
GasInfo: sdk.GasInfo{
GasWanted: txRes.GasWanted,
GasUsed: txRes.GasUsed,
},
Result: &sdk.Result{
Data: []byte{},
Log: errMsg,
Events: abciEvents,
MsgResponses: msgResponses,
},
}
return gogoproto.Marshal(res)
}
// ToSDKEvidence takes comet evidence and returns sdk evidence
func ToSDKEvidence(ev []abci.Misbehavior) []*comet.Evidence {
evidence := make([]*comet.Evidence, len(ev))
for i, e := range ev {
evidence[i] = &comet.Evidence{
Type: comet.MisbehaviorType(e.Type),
Height: e.Height,
Time: e.Time,
TotalVotingPower: e.TotalVotingPower,
Validator: comet.Validator{
Address: e.Validator.Address,
Power: e.Validator.Power,
},
}
}
return evidence
}
// ToSDKCommitInfo takes comet commit info and returns sdk commit info
func ToSDKCommitInfo(commit abci.CommitInfo) *comet.CommitInfo {
ci := comet.CommitInfo{
Round: commit.Round,
}
for _, v := range commit.Votes {
ci.Votes = append(ci.Votes, comet.VoteInfo{
Validator: comet.Validator{
Address: v.Validator.Address,
Power: v.Validator.Power,
},
BlockIDFlag: comet.BlockIDFlag(v.BlockIdFlag),
})
}
return &ci
}
// ToSDKExtendedCommitInfo takes comet extended commit info and returns sdk commit info
func ToSDKExtendedCommitInfo(commit abci.ExtendedCommitInfo) comet.CommitInfo {
ci := comet.CommitInfo{
Round: commit.Round,
}
for _, v := range commit.Votes {
ci.Votes = append(ci.Votes, comet.VoteInfo{
Validator: comet.Validator{
Address: v.Validator.Address,
Power: v.Validator.Power,
},
BlockIDFlag: comet.BlockIDFlag(v.BlockIdFlag),
})
}
return ci
}
// queryResult returns a ResponseQuery from an error. It will try to parse ABCI info from the error.
func queryResult(err error, debug bool) *abci.QueryResponse {
space, code, log := errorsmod.ABCIInfo(err, debug)
return &abci.QueryResponse{
Codespace: space,
Code: code,
Log: log,
}
}
func gRPCErrorToSDKError(err error) *abci.QueryResponse {
toQueryResp := func(sdkErr *errorsmod.Error, err error) *abci.QueryResponse {
res := &abci.QueryResponse{
Code: sdkErr.ABCICode(),
Codespace: sdkErr.Codespace(),
}
type grpcStatus interface{ GRPCStatus() *grpcstatus.Status }
if grpcErr, ok := err.(grpcStatus); ok {
res.Log = grpcErr.GRPCStatus().Message()
} else {
res.Log = err.Error()
}
return res
}
status, ok := grpcstatus.FromError(err)
if !ok {
return toQueryResp(sdkerrors.ErrInvalidRequest, err)
}
switch status.Code() {
case codes.NotFound:
return toQueryResp(sdkerrors.ErrKeyNotFound, err)
case codes.InvalidArgument:
return toQueryResp(sdkerrors.ErrInvalidRequest, err)
case codes.FailedPrecondition:
return toQueryResp(sdkerrors.ErrInvalidRequest, err)
case codes.Unauthenticated:
return toQueryResp(sdkerrors.ErrUnauthorized, err)
default:
return toQueryResp(sdkerrors.ErrUnknownRequest, err)
}
}
func (c *consensus[T]) validateFinalizeBlockHeight(req *abci.FinalizeBlockRequest) error {
if req.Height < 1 {
return fmt.Errorf("invalid height: %d", req.Height)
}
lastBlockHeight, _, err := c.store.StateLatest()
if err != nil {
return err
}
// expectedHeight holds the expected height to validate
var expectedHeight uint64
if lastBlockHeight == 0 && c.initialHeight > 1 {
// In this case, we're validating the first block of the chain, i.e no
// previous commit. The height we're expecting is the initial height.
expectedHeight = c.initialHeight
} else {
// This case can mean two things:
//
// - Either there was already a previous commit in the store, in which
// case we increment the version from there.
// - Or there was no previous commit, in which case we start at version 1.
expectedHeight = lastBlockHeight + 1
}
if req.Height != int64(expectedHeight) {
return fmt.Errorf("invalid height: %d; expected: %d", req.Height, expectedHeight)
}
return nil
}
// GetConsensusParams makes a query to the consensus module in order to get the latest consensus
// parameters from committed state
func GetConsensusParams[T transaction.Tx](ctx context.Context, app handlers.AppManager[T]) (*cmtproto.ConsensusParams, error) {
res, err := app.Query(ctx, 0, &types.QueryParamsRequest{})
if err != nil {
return nil, err
}
if r, ok := res.(*types.QueryParamsResponse); !ok {
return nil, errors.New("failed to query consensus params")
} else {
// convert our params to cometbft params
return r.Params, nil
}
}
func (c *consensus[T]) GetBlockRetentionHeight(cp *cmtproto.ConsensusParams, commitHeight int64) int64 {
// pruning is disabled if minRetainBlocks is zero
if c.cfg.AppTomlConfig.MinRetainBlocks == 0 {
return 0
}
minNonZero := func(x, y int64) int64 {
switch {
case x == 0:
return y
case y == 0:
return x
case x < y:
return x
default:
return y
}
}
// Define retentionHeight as the minimum value that satisfies all non-zero
// constraints. All blocks below (commitHeight-retentionHeight) are pruned
// from CometBFT.
var retentionHeight int64
// Define the number of blocks needed to protect against misbehaving validators
// which allows light clients to operate safely. Note, we piggy back of the
// evidence parameters instead of computing an estimated number of blocks based
// on the unbonding period and block commitment time as the two should be
// equivalent.
if cp.Evidence != nil && cp.Evidence.MaxAgeNumBlocks > 0 {
retentionHeight = commitHeight - cp.Evidence.MaxAgeNumBlocks
}
if c.snapshotManager != nil {
snapshotRetentionHeights := c.snapshotManager.GetSnapshotBlockRetentionHeights()
if snapshotRetentionHeights > 0 {
retentionHeight = minNonZero(retentionHeight, commitHeight-snapshotRetentionHeights)
}
}
v := commitHeight - int64(c.cfg.AppTomlConfig.MinRetainBlocks)
retentionHeight = minNonZero(retentionHeight, v)
if retentionHeight <= 0 {
// prune nothing in the case of a non-positive height
return 0
}
return retentionHeight
}
// checkHalt checks if height or time exceeds halt-height or halt-time respectively.
func (c *consensus[T]) checkHalt(height int64, time time.Time) error {
var halt bool
switch {
case c.cfg.AppTomlConfig.HaltHeight > 0 && uint64(height) >= c.cfg.AppTomlConfig.HaltHeight:
halt = true
case c.cfg.AppTomlConfig.HaltTime > 0 && time.Unix() >= int64(c.cfg.AppTomlConfig.HaltTime):
halt = true
}
if halt {
return fmt.Errorf("halt per configuration height %d time %d", c.cfg.AppTomlConfig.HaltHeight, c.cfg.AppTomlConfig.HaltTime)
}
return nil
}
// uint64ToInt64 converts a uint64 to an int64, returning math.MaxInt64 if the uint64 is too large.
func uint64ToInt64(u uint64) int64 {
if u > uint64(math.MaxInt64) {
return math.MaxInt64
}
return int64(u)
}
// RawTx allows access to the raw bytes of a transaction even if it failed
// to decode.
func RawTx(tx []byte) transaction.Tx {
return InjectedTx(tx)
}
type InjectedTx []byte
var _ transaction.Tx = InjectedTx{}
func (tx InjectedTx) Bytes() []byte {
return tx
}
func (tx InjectedTx) Hash() [32]byte {
return sha256.Sum256(tx)
}
func (tx InjectedTx) GetGasLimit() (uint64, error) {
return 0, nil
}
func (tx InjectedTx) GetMessages() ([]transaction.Msg, error) {
return nil, nil
}
func (tx InjectedTx) GetSenders() ([]transaction.Identity, error) {
return [][]byte{[]byte("cometbft")}, nil
}
// ValidateVoteExtensions defines a helper function for verifying vote extension
// signatures that may be passed or manually injected into a block proposal from
// a proposer in PrepareProposal. It returns an error if any signature is invalid
// or if unexpected vote extensions and/or signatures are found or less than 2/3
// power is received.
// If commitInfo is nil, this function can be used to check a set of vote extensions
// without comparing them to a commit.
func ValidateVoteExtensions[T transaction.Tx](
ctx context.Context,
app handlers.AppManager[T],
chainID string,
validatorStore func(context.Context, []byte) (cryptotypes.PubKey, error),
extCommit abci.ExtendedCommitInfo,
currentHeight int64,
commitInfo *abci.CommitInfo,
) error {
cp, err := GetConsensusParams(ctx, app)
if err != nil {
return err
}
if commitInfo != nil {
// Check that both extCommit + commit are ordered in accordance with vp/address.
if err := validateExtendedCommitAgainstLastCommit(extCommit, *commitInfo); err != nil {
return err
}
}
// Start checking vote extensions only **after** the vote extensions enable
// height, because when `currentHeight == VoteExtensionsEnableHeight`
// PrepareProposal doesn't get any vote extensions in its request.
extsEnabled := cp.Feature != nil && cp.Feature.VoteExtensionsEnableHeight != nil && currentHeight > cp.Feature.VoteExtensionsEnableHeight.Value && cp.Feature.VoteExtensionsEnableHeight.Value != 0
if !extsEnabled {
extsEnabled = cp.Abci != nil && currentHeight > cp.Abci.VoteExtensionsEnableHeight && cp.Abci.VoteExtensionsEnableHeight != 0
}
if !extsEnabled {
return nil
}
marshalDelimitedFn := func(msg gogoproto.Message) ([]byte, error) {
var buf bytes.Buffer
if err := protoio.NewDelimitedWriter(&buf).WriteMsg(msg); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
var (
// Total voting power of all vote extensions.
totalVP int64
// Total voting power of all validators that submitted valid vote extensions.
sumVP int64
)
for _, vote := range extCommit.Votes {
totalVP += vote.Validator.Power
// Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the
// previous block (the block the vote is for) could not have been committed.
if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit {
continue
}
if !extsEnabled {
if len(vote.VoteExtension) > 0 {
return fmt.Errorf("vote extensions disabled; received non-empty vote extension at height %d", currentHeight)
}
if len(vote.ExtensionSignature) > 0 {
return fmt.Errorf("vote extensions disabled; received non-empty vote extension signature at height %d", currentHeight)
}
continue
}
if len(vote.ExtensionSignature) == 0 {
return fmt.Errorf("vote extensions enabled; received empty vote extension signature at height %d", currentHeight)
}
valConsAddr := sdk.ConsAddress(vote.Validator.Address)
pubKeyProto, err := validatorStore(ctx, valConsAddr)
if err != nil {
return fmt.Errorf("failed to get validator %X public key: %w", valConsAddr, err)
}
cmtpk, err := cryptocodec.ToCmtProtoPublicKey(pubKeyProto)
if err != nil {
return fmt.Errorf("failed to convert validator %X public key: %w", valConsAddr, err)
}
cmtPubKey, err := cryptoenc.PubKeyFromProto(cmtpk)
if err != nil {
return fmt.Errorf("failed to convert validator %X public key: %w", valConsAddr, err)
}
cve := cmtproto.CanonicalVoteExtension{
Extension: vote.VoteExtension,
Height: currentHeight - 1, // the vote extension was signed in the previous height
Round: int64(extCommit.Round),
ChainId: chainID,
}
extSignBytes, err := marshalDelimitedFn(&cve)
if err != nil {
return fmt.Errorf("failed to encode CanonicalVoteExtension: %w", err)
}
if !cmtPubKey.VerifySignature(extSignBytes, vote.ExtensionSignature) {
return fmt.Errorf("failed to verify validator %X vote extension signature", valConsAddr)
}
sumVP += vote.Validator.Power
}
// This check is probably unnecessary, but better safe than sorry.
if totalVP <= 0 {
return fmt.Errorf("total voting power must be positive, got: %d", totalVP)
}
// If the sum of the voting power has not reached (2/3 + 1) we need to error.
if requiredVP := ((totalVP * 2) / 3) + 1; sumVP < requiredVP {
return fmt.Errorf(
"insufficient cumulative voting power received to verify vote extensions; got: %d, expected: >=%d",
sumVP, requiredVP,
)
}
return nil
}
// validateExtendedCommitAgainstLastCommit validates an ExtendedCommitInfo against a LastCommit. Specifically,
// it checks that the ExtendedCommit + LastCommit (for the same height), are consistent with each other + that
// they are ordered correctly (by voting power) in accordance with
// [comet](https://github.com/cometbft/cometbft/blob/4ce0277b35f31985bbf2c25d3806a184a4510010/types/validator_set.go#L784).
func validateExtendedCommitAgainstLastCommit(ec abci.ExtendedCommitInfo, lc abci.CommitInfo) error {
// check that the rounds are the same
if ec.Round != lc.Round {
return fmt.Errorf("extended commit round %d does not match last commit round %d", ec.Round, lc.Round)
}
// check that the # of votes are the same
if len(ec.Votes) != len(lc.Votes) {
return fmt.Errorf("extended commit votes length %d does not match last commit votes length %d", len(ec.Votes), len(lc.Votes))
}
// check sort order of extended commit votes
if !slices.IsSortedFunc(ec.Votes, func(vote1, vote2 abci.ExtendedVoteInfo) int {
if vote1.Validator.Power == vote2.Validator.Power {
return bytes.Compare(vote1.Validator.Address, vote2.Validator.Address) // addresses sorted in ascending order (used to break vp conflicts)
}
return -int(vote1.Validator.Power - vote2.Validator.Power) // vp sorted in descending order
}) {
return errors.New("extended commit votes are not sorted by voting power")
}
addressCache := make(map[string]struct{}, len(ec.Votes))
// check consistency between LastCommit and ExtendedCommit
for i, vote := range ec.Votes {
// cache addresses to check for duplicates
if _, ok := addressCache[string(vote.Validator.Address)]; ok {
return fmt.Errorf("extended commit vote address %X is duplicated", vote.Validator.Address)
}
addressCache[string(vote.Validator.Address)] = struct{}{}
if !bytes.Equal(vote.Validator.Address, lc.Votes[i].Validator.Address) {
return fmt.Errorf("extended commit vote address %X does not match last commit vote address %X", vote.Validator.Address, lc.Votes[i].Validator.Address)
}
if vote.Validator.Power != lc.Votes[i].Validator.Power {
return fmt.Errorf("extended commit vote power %d does not match last commit vote power %d", vote.Validator.Power, lc.Votes[i].Validator.Power)
}
}
return nil
}

View File

@ -1,26 +0,0 @@
package cometbft
import "runtime/debug"
var Version = ""
func getCometBFTServerVersion() string {
deps, ok := debug.ReadBuildInfo()
if !ok {
return Version
}
var serverVersion string
for _, dep := range deps.Deps {
if dep.Path == "cosmossdk.io/server/v2/cometbft" {
if dep.Replace != nil && dep.Replace.Version != "(devel)" {
serverVersion = dep.Replace.Version
} else {
serverVersion = dep.Version
}
}
}
Version = serverVersion
return serverVersion
}

View File

@ -1 +0,0 @@
/simapp.test

View File

@ -1,8 +0,0 @@
---
sidebar_position: 1
---
# `SimApp/v2`
SimApp is an application built using the Cosmos SDK for testing and educational purposes.
`SimApp/v2` demonstrate a runtime/v2, server/v2 and store/v2 wiring.

View File

@ -1,298 +0,0 @@
//nolint:unused,nolintlint // ignore unused code linting
package simapp
import (
"time"
"google.golang.org/protobuf/types/known/durationpb"
accountsmodulev1 "cosmossdk.io/api/cosmos/accounts/module/v1"
runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2"
appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1"
authzmodulev1 "cosmossdk.io/api/cosmos/authz/module/v1"
bankmodulev1 "cosmossdk.io/api/cosmos/bank/module/v1"
circuitmodulev1 "cosmossdk.io/api/cosmos/circuit/module/v1"
consensusmodulev1 "cosmossdk.io/api/cosmos/consensus/module/v1"
distrmodulev1 "cosmossdk.io/api/cosmos/distribution/module/v1"
epochsmodulev1 "cosmossdk.io/api/cosmos/epochs/module/v1"
evidencemodulev1 "cosmossdk.io/api/cosmos/evidence/module/v1"
feegrantmodulev1 "cosmossdk.io/api/cosmos/feegrant/module/v1"
genutilmodulev1 "cosmossdk.io/api/cosmos/genutil/module/v1"
govmodulev1 "cosmossdk.io/api/cosmos/gov/module/v1"
groupmodulev1 "cosmossdk.io/api/cosmos/group/module/v1"
mintmodulev1 "cosmossdk.io/api/cosmos/mint/module/v1"
nftmodulev1 "cosmossdk.io/api/cosmos/nft/module/v1"
poolmodulev1 "cosmossdk.io/api/cosmos/protocolpool/module/v1"
slashingmodulev1 "cosmossdk.io/api/cosmos/slashing/module/v1"
stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1"
txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1"
upgrademodulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1"
validatemodulev1 "cosmossdk.io/api/cosmos/validate/module/v1"
vestingmodulev1 "cosmossdk.io/api/cosmos/vesting/module/v1"
"cosmossdk.io/depinject/appconfig"
"cosmossdk.io/x/accounts"
"cosmossdk.io/x/authz"
_ "cosmossdk.io/x/authz/module" // import for side-effects
_ "cosmossdk.io/x/bank" // import for side-effects
banktypes "cosmossdk.io/x/bank/types"
_ "cosmossdk.io/x/circuit" // import for side-effects
circuittypes "cosmossdk.io/x/circuit/types"
_ "cosmossdk.io/x/consensus" // import for side-effects
consensustypes "cosmossdk.io/x/consensus/types"
_ "cosmossdk.io/x/distribution" // import for side-effects
distrtypes "cosmossdk.io/x/distribution/types"
_ "cosmossdk.io/x/epochs" // import for side-effects
epochstypes "cosmossdk.io/x/epochs/types"
_ "cosmossdk.io/x/evidence" // import for side-effects
evidencetypes "cosmossdk.io/x/evidence/types"
"cosmossdk.io/x/feegrant"
_ "cosmossdk.io/x/feegrant/module" // import for side-effects
_ "cosmossdk.io/x/gov" // import for side-effects
govtypes "cosmossdk.io/x/gov/types"
"cosmossdk.io/x/group"
_ "cosmossdk.io/x/group/module" // import for side-effects
_ "cosmossdk.io/x/mint" // import for side-effects
minttypes "cosmossdk.io/x/mint/types"
"cosmossdk.io/x/nft"
_ "cosmossdk.io/x/nft/module" // import for side-effects
_ "cosmossdk.io/x/protocolpool" // import for side-effects
pooltypes "cosmossdk.io/x/protocolpool/types"
_ "cosmossdk.io/x/slashing" // import for side-effects
slashingtypes "cosmossdk.io/x/slashing/types"
_ "cosmossdk.io/x/staking" // import for side-effects
stakingtypes "cosmossdk.io/x/staking/types"
_ "cosmossdk.io/x/upgrade" // import for side-effects
upgradetypes "cosmossdk.io/x/upgrade/types"
"github.com/cosmos/cosmos-sdk/runtime"
_ "github.com/cosmos/cosmos-sdk/x/auth" // import for side-effects
authtxconfig "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
_ "github.com/cosmos/cosmos-sdk/x/auth/vesting" // import for side-effects
vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/cosmos-sdk/x/validate"
)
var (
// module account permissions
moduleAccPerms = []*authmodulev1.ModuleAccountPermission{
{Account: authtypes.FeeCollectorName},
{Account: distrtypes.ModuleName},
{Account: pooltypes.ModuleName},
{Account: pooltypes.StreamAccount},
{Account: pooltypes.ProtocolPoolDistrAccount},
{Account: minttypes.ModuleName, Permissions: []string{authtypes.Minter}},
{Account: stakingtypes.BondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}},
{Account: stakingtypes.NotBondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}},
{Account: govtypes.ModuleName, Permissions: []string{authtypes.Burner}},
{Account: nft.ModuleName},
}
// blocked account addresses
blockAccAddrs = []string{
authtypes.FeeCollectorName,
distrtypes.ModuleName,
minttypes.ModuleName,
stakingtypes.BondedPoolName,
stakingtypes.NotBondedPoolName,
nft.ModuleName,
// We allow the following module accounts to receive funds:
// govtypes.ModuleName
// pooltypes.ModuleName
}
// ModuleConfig is the application module configuration used by depinject
ModuleConfig = &appv1alpha1.Config{
Modules: []*appv1alpha1.ModuleConfig{
{
Name: runtime.ModuleName,
Config: appconfig.WrapAny(&runtimev2.Module{
AppName: "SimAppV2",
// NOTE: upgrade module is required to be prioritized
PreBlockers: []string{
upgradetypes.ModuleName,
},
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
// NOTE: staking module is required if HistoricalEntries param > 0
BeginBlockers: []string{
minttypes.ModuleName,
distrtypes.ModuleName,
pooltypes.ModuleName,
slashingtypes.ModuleName,
evidencetypes.ModuleName,
stakingtypes.ModuleName,
authz.ModuleName,
epochstypes.ModuleName,
},
EndBlockers: []string{
govtypes.ModuleName,
stakingtypes.ModuleName,
feegrant.ModuleName,
group.ModuleName,
pooltypes.ModuleName,
},
OverrideStoreKeys: []*runtimev2.StoreKeyConfig{
{
ModuleName: authtypes.ModuleName,
KvStoreKey: "acc",
},
{
ModuleName: accounts.ModuleName,
KvStoreKey: accounts.StoreKey,
},
},
// NOTE: The genutils module must occur after staking so that pools are
// properly initialized with tokens from genesis accounts.
// NOTE: The genutils module must also occur after auth so that it can access the params from auth.
InitGenesis: []string{
consensustypes.ModuleName,
accounts.ModuleName,
authtypes.ModuleName,
banktypes.ModuleName,
distrtypes.ModuleName,
stakingtypes.ModuleName,
slashingtypes.ModuleName,
govtypes.ModuleName,
minttypes.ModuleName,
genutiltypes.ModuleName,
evidencetypes.ModuleName,
authz.ModuleName,
feegrant.ModuleName,
nft.ModuleName,
group.ModuleName,
upgradetypes.ModuleName,
vestingtypes.ModuleName,
circuittypes.ModuleName,
pooltypes.ModuleName,
epochstypes.ModuleName,
},
// When ExportGenesis is not specified, the export genesis module order
// is equal to the init genesis order
// ExportGenesis: []string{},
// Uncomment if you want to set a custom migration order here.
// OrderMigrations: []string{},
// TODO GasConfig was added to the config in runtimev2. Where/how was it set in v1?
GasConfig: &runtimev2.GasConfig{
ValidateTxGasLimit: 10_000_000,
QueryGasLimit: 100_000,
SimulationGasLimit: 100_000,
},
// SkipStoreKeys is an optional list of store keys to skip when constructing the
// module's keeper. This is useful when a module does not have a store key.
SkipStoreKeys: []string{
authtxconfig.DepinjectModuleName,
validate.ModuleName,
},
}),
},
{
Name: authtxconfig.DepinjectModuleName, // x/auth/tx/config depinject module (not app module), use to provide tx configuration
Config: appconfig.WrapAny(&txconfigv1.Config{}),
},
{
Name: validate.ModuleName,
Config: appconfig.WrapAny(&validatemodulev1.Module{}),
},
{
Name: authtypes.ModuleName,
Config: appconfig.WrapAny(&authmodulev1.Module{
Bech32Prefix: "cosmos",
ModuleAccountPermissions: moduleAccPerms,
// By default modules authority is the governance module. This is configurable with the following:
// Authority: "group", // A custom module authority can be set using a module name
// Authority: "cosmos1cwwv22j5ca08ggdv9c2uky355k908694z577tv", // or a specific address
}),
},
{
Name: vestingtypes.ModuleName,
Config: appconfig.WrapAny(&vestingmodulev1.Module{}),
},
{
Name: banktypes.ModuleName,
Config: appconfig.WrapAny(&bankmodulev1.Module{
BlockedModuleAccountsOverride: blockAccAddrs,
}),
},
{
Name: stakingtypes.ModuleName,
Config: appconfig.WrapAny(&stakingmodulev1.Module{
// NOTE: specifying a prefix is only necessary when using bech32 addresses
// If not specified, the auth Bech32Prefix appended with "valoper" and "valcons" is used by default
Bech32PrefixValidator: "cosmosvaloper",
Bech32PrefixConsensus: "cosmosvalcons",
}),
},
{
Name: slashingtypes.ModuleName,
Config: appconfig.WrapAny(&slashingmodulev1.Module{}),
},
{
Name: genutiltypes.ModuleName,
Config: appconfig.WrapAny(&genutilmodulev1.Module{}),
},
{
Name: authz.ModuleName,
Config: appconfig.WrapAny(&authzmodulev1.Module{}),
},
{
Name: upgradetypes.ModuleName,
Config: appconfig.WrapAny(&upgrademodulev1.Module{}),
},
{
Name: distrtypes.ModuleName,
Config: appconfig.WrapAny(&distrmodulev1.Module{}),
},
{
Name: evidencetypes.ModuleName,
Config: appconfig.WrapAny(&evidencemodulev1.Module{}),
},
{
Name: minttypes.ModuleName,
Config: appconfig.WrapAny(&mintmodulev1.Module{}),
},
{
Name: group.ModuleName,
Config: appconfig.WrapAny(&groupmodulev1.Module{
MaxExecutionPeriod: durationpb.New(time.Second * 1209600),
MaxMetadataLen: 255,
}),
},
{
Name: nft.ModuleName,
Config: appconfig.WrapAny(&nftmodulev1.Module{}),
},
{
Name: feegrant.ModuleName,
Config: appconfig.WrapAny(&feegrantmodulev1.Module{}),
},
{
Name: govtypes.ModuleName,
Config: appconfig.WrapAny(&govmodulev1.Module{}),
},
{
Name: consensustypes.ModuleName,
Config: appconfig.WrapAny(&consensusmodulev1.Module{}),
},
{
Name: accounts.ModuleName,
Config: appconfig.WrapAny(&accountsmodulev1.Module{}),
},
{
Name: circuittypes.ModuleName,
Config: appconfig.WrapAny(&circuitmodulev1.Module{}),
},
{
Name: pooltypes.ModuleName,
Config: appconfig.WrapAny(&poolmodulev1.Module{}),
},
{
Name: epochstypes.ModuleName,
Config: appconfig.WrapAny(&epochsmodulev1.Module{}),
},
},
}
)

View File

@ -1,228 +0,0 @@
package simapp
import (
_ "embed"
"fmt"
_ "github.com/jackc/pgx/v5/stdlib" // Import and register pgx driver
"cosmossdk.io/core/registry"
"cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/depinject/appconfig"
_ "cosmossdk.io/indexer/postgres" // register the postgres indexer
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
serverstore "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/root"
basedepinject "cosmossdk.io/x/accounts/defaults/base/depinject"
lockupdepinject "cosmossdk.io/x/accounts/defaults/lockup/depinject"
multisigdepinject "cosmossdk.io/x/accounts/defaults/multisig/depinject"
stakingkeeper "cosmossdk.io/x/staking/keeper"
upgradekeeper "cosmossdk.io/x/upgrade/keeper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
_ "github.com/cosmos/cosmos-sdk/x/genutil"
)
// SimApp extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type SimApp[T transaction.Tx] struct {
*runtime.App[T]
legacyAmino registry.AminoRegistrar
appCodec codec.Codec
txConfig client.TxConfig
interfaceRegistry codectypes.InterfaceRegistry
store store.RootStore
// required keepers during wiring
// others keepers are all in the app
UpgradeKeeper *upgradekeeper.Keeper
StakingKeeper *stakingkeeper.Keeper
AuthKeeper authkeeper.AccountKeeper
}
// AppConfig returns the default app config.
func AppConfig() depinject.Config {
return depinject.Configs(
appconfig.Compose(ModuleConfig), // Alternatively use appconfig.LoadYAML(AppConfigYAML)
runtime.DefaultServiceBindings(),
codec.DefaultProviders,
depinject.Provide(
ProvideRootStoreConfig,
// inject desired account types:
multisigdepinject.ProvideAccount,
basedepinject.ProvideAccount,
lockupdepinject.ProvideAllLockupAccounts,
// provide base account options
basedepinject.ProvideSecp256K1PubKey,
),
depinject.Invoke(
std.RegisterInterfaces,
std.RegisterLegacyAminoCodec,
),
)
}
func NewSimApp[T transaction.Tx](
config depinject.Config,
outputs ...any,
) (*SimApp[T], error) {
var (
app = &SimApp[T]{}
appBuilder *runtime.AppBuilder[T]
storeBuilder root.Builder
logger log.Logger
// merge the AppConfig and other configuration in one config
appConfig = depinject.Configs(
AppConfig(),
config,
depinject.Supply(
// ADVANCED CONFIGURATION
//
// AUTH
//
// For providing a custom function required in auth to generate custom account types
// add it below. By default the auth module uses simulation.RandomGenesisAccounts.
//
// authtypes.RandomGenesisAccountsFn(simulation.RandomGenesisAccounts),
//
// For providing a custom a base account type add it below.
// By default the auth module uses authtypes.ProtoBaseAccount().
//
// func() sdk.AccountI { return authtypes.ProtoBaseAccount() },
//
// For providing a different address codec, add it below.
// By default the auth module uses a Bech32 address codec,
// with the prefix defined in the auth module configuration.
//
// func() address.Codec { return <- custom address codec type -> }
//
// STAKING
//
// For provinding a different validator and consensus address codec, add it below.
// By default the staking module uses the bech32 prefix provided in the auth config,
// and appends "valoper" and "valcons" for validator and consensus addresses respectively.
// When providing a custom address codec in auth, custom address codecs must be provided here as well.
//
// func() runtime.ValidatorAddressCodec { return <- custom validator address codec type -> }
// func() runtime.ConsensusAddressCodec { return <- custom consensus address codec type -> }
//
// MINT
//
// For providing a custom inflation function for x/mint add here your
// custom function that implements the minttypes.InflationCalculationFn
// interface.
),
depinject.Provide(
// if you want to provide a custom public key you
// can do it from here.
// Example:
// basedepinject.ProvideCustomPubkey[Ed25519PublicKey]()
//
// You can also provide a custom public key with a custom validation function:
//
// basedepinject.ProvideCustomPubKeyAndValidationFunc(func(pub Ed25519PublicKey) error {
// if len(pub.Key) != 64 {
// return fmt.Errorf("invalid pub key size")
// }
// })
),
)
)
outputs = append(outputs,
&logger,
&storeBuilder,
&appBuilder,
&app.appCodec,
&app.legacyAmino,
&app.txConfig,
&app.interfaceRegistry,
&app.UpgradeKeeper,
&app.StakingKeeper,
&app.AuthKeeper,
)
if err := depinject.Inject(appConfig, outputs...); err != nil {
return nil, err
}
var err error
app.App, err = appBuilder.Build()
if err != nil {
return nil, err
}
app.store = storeBuilder.Get()
if app.store == nil {
return nil, fmt.Errorf("store builder did not return a db")
}
/**** Store Metrics ****/
/*
// In order to set store metrics uncomment the below
storeMetrics, err := metrics.NewMetrics([][]string{{"module", "store"}})
if err != nil {
return nil, err
}
app.store.SetMetrics(storeMetrics)
*/
/**** Module Options ****/
// RegisterUpgradeHandlers is used for registering any on-chain upgrades.
app.RegisterUpgradeHandlers()
if err = app.LoadLatest(); err != nil {
return nil, err
}
return app, nil
}
// AppCodec returns SimApp's app codec.
//
// NOTE: This is solely to be used for testing purposes as it may be desirable
// for modules to register their own custom testing types.
func (app *SimApp[T]) AppCodec() codec.Codec {
return app.appCodec
}
// InterfaceRegistry returns SimApp's InterfaceRegistry.
func (app *SimApp[T]) InterfaceRegistry() server.InterfaceRegistry {
return app.interfaceRegistry
}
// TxConfig returns SimApp's TxConfig.
func (app *SimApp[T]) TxConfig() client.TxConfig {
return app.txConfig
}
// Store returns the root store.
func (app *SimApp[T]) Store() store.RootStore {
return app.store
}
// Close overwrites the base Close method to close the stores.
func (app *SimApp[T]) Close() error {
if err := app.store.Close(); err != nil {
return err
}
return app.App.Close()
}
func ProvideRootStoreConfig(config runtime.GlobalConfig) (*root.Config, error) {
return serverstore.UnmarshalConfig(config)
}

View File

@ -1,165 +0,0 @@
package simapp
import (
"context"
"crypto/sha256"
"encoding/json"
"testing"
"time"
"github.com/cometbft/cometbft/types"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/comet"
context2 "cosmossdk.io/core/context"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
serverv2store "cosmossdk.io/server/v2/store"
"cosmossdk.io/store/v2/db"
banktypes "cosmossdk.io/x/bank/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
"github.com/cosmos/cosmos-sdk/testutil/mock"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
func NewTestApp(t *testing.T) (*SimApp[transaction.Tx], context.Context) {
t.Helper()
logger := log.NewTestLogger(t)
vp := viper.New()
vp.Set(serverv2store.FlagAppDBBackend, string(db.DBTypeGoLevelDB))
vp.Set(serverv2.FlagHome, t.TempDir())
app, err := NewSimApp[transaction.Tx](depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(vp.AllSettings()))),
)
require.NoError(t, err)
genesis := app.ModuleManager().DefaultGenesis()
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
require.NoError(t, err)
// create validator set with single validator
validator := types.NewValidator(pubKey, 1)
valSet := types.NewValidatorSet([]*types.Validator{validator})
// generate genesis account
senderPrivKey := secp256k1.GenPrivKey()
acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0)
accAddr, err := app.txConfig.SigningContext().AddressCodec().BytesToString(acc.GetAddress())
require.NoError(t, err)
balance := banktypes.Balance{
Address: accAddr,
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000))),
}
genesis, err = simtestutil.GenesisStateWithValSet(
app.AppCodec(),
genesis,
valSet,
[]authtypes.GenesisAccount{acc},
balance,
)
require.NoError(t, err)
genesisBytes, err := json.Marshal(genesis)
require.NoError(t, err)
st := app.Store()
ci, err := st.LastCommitID()
require.NoError(t, err)
bz := sha256.Sum256([]byte{})
ctx := context.Background()
_, newState, err := app.InitGenesis(
ctx,
&server.BlockRequest[transaction.Tx]{
Time: time.Now(),
Hash: bz[:],
ChainId: "theChain",
AppHash: ci.Hash,
IsGenesis: true,
Height: 1,
},
genesisBytes,
nil,
)
require.NoError(t, err)
changes, err := newState.GetStateChanges()
require.NoError(t, err)
_, err = st.Commit(&store.Changeset{Version: 1, Changes: changes})
require.NoError(t, err)
return app, ctx
}
func MoveNextBlock(t *testing.T, app *SimApp[transaction.Tx], ctx context.Context) {
t.Helper()
bz := sha256.Sum256([]byte{})
st := app.Store()
ci, err := st.LastCommitID()
require.NoError(t, err)
height, err := app.LoadLatestHeight()
height++
require.NoError(t, err)
// TODO: this is a hack to set the comet info in the context for distribution module dependency.
ctx = context.WithValue(ctx, context2.CometInfoKey, comet.Info{
Evidence: nil,
ValidatorsHash: nil,
ProposerAddress: nil,
LastCommit: comet.CommitInfo{},
})
_, newState, err := app.DeliverBlock(
ctx,
&server.BlockRequest[transaction.Tx]{
Height: height,
Time: time.Now(),
Hash: bz[:],
AppHash: ci.Hash,
})
require.NoError(t, err)
changes, err := newState.GetStateChanges()
require.NoError(t, err)
_, err = st.Commit(&store.Changeset{Version: height, Changes: changes})
require.NoError(t, err)
}
func TestSimAppExportAndBlockedAddrs_WithOneBlockProduced(t *testing.T) {
app, ctx := NewTestApp(t)
MoveNextBlock(t, app, ctx)
_, err := app.ExportAppStateAndValidators(false, nil)
require.NoError(t, err)
}
func TestSimAppExportAndBlockedAddrs_NoBlocksProduced(t *testing.T) {
app, _ := NewTestApp(t)
_, err := app.ExportAppStateAndValidators(false, nil)
require.NoError(t, err)
}

View File

@ -1,39 +0,0 @@
//go:build benchmark
package simapp
import (
runtimev2 "cosmossdk.io/api/cosmos/app/runtime/v2"
appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1"
benchmarkmodulev1 "cosmossdk.io/api/cosmos/benchmark/module/v1"
"cosmossdk.io/depinject/appconfig"
benchmark "cosmossdk.io/tools/benchmark/module"
"fmt"
)
func init() {
// WARNING!
// Enabling this module will produce 3M keys in the genesis state for the benchmark module.
// Will also enable processing of benchmark transactions which can easily overwhelm the system.
ModuleConfig.Modules = append(ModuleConfig.Modules, &appv1alpha1.ModuleConfig{
Name: benchmark.ModuleName,
Config: appconfig.WrapAny(&benchmarkmodulev1.Module{
GenesisParams: &benchmarkmodulev1.GeneratorParams{
Seed: 34,
BucketCount: 3,
GenesisCount: 3_000_000,
KeyMean: 64,
KeyStdDev: 12,
ValueMean: 1024,
ValueStdDev: 256,
},
}),
})
runtimeConfig := &runtimev2.Module{}
err := ModuleConfig.Modules[0].Config.UnmarshalTo(runtimeConfig)
if err != nil {
panic(fmt.Errorf("benchmark init: failed to unmarshal runtime module config: %w", err))
}
runtimeConfig.InitGenesis = append(runtimeConfig.InitGenesis, benchmark.ModuleName)
ModuleConfig.Modules[0].Config = appconfig.WrapAny(runtimeConfig)
}

View File

@ -1,46 +0,0 @@
{ lib
, buildGoApplication
, rocksdb
, stdenv
, static ? stdenv.hostPlatform.isStatic
, rev ? "dev"
}:
let
pname = "simd";
version = "v0.0.1";
tags = [ "ledger" "netgo" "rocksdb" "grocksdb_no_link" ];
ldflags = lib.concatStringsSep "\n" ([
"-X github.com/cosmos/cosmos-sdk/version.Name=${pname}"
"-X github.com/cosmos/cosmos-sdk/version.AppName=${pname}"
"-X github.com/cosmos/cosmos-sdk/version.Version=${version}"
"-X github.com/cosmos/cosmos-sdk/version.BuildTags=${lib.concatStringsSep "," tags}"
"-X github.com/cosmos/cosmos-sdk/version.Commit=${rev}"
]);
in
buildGoApplication rec {
inherit pname version ldflags tags;
src = ./.;
pwd = src;
modules = ./gomod2nix.toml;
subPackages = [ "simd" ];
doCheck = false;
buildInputs = [ rocksdb ];
CGO_ENABLED = "1";
CGO_LDFLAGS =
if static then "-lrocksdb -pthread -lstdc++ -ldl -lzstd -lsnappy -llz4 -lbz2 -lz"
else if stdenv.hostPlatform.isWindows then "-lrocksdb-shared"
else "-lrocksdb -pthread -lstdc++ -ldl";
postFixup = lib.optionalString stdenv.isDarwin ''
${stdenv.cc.targetPrefix}install_name_tool -change "@rpath/librocksdb.8.dylib" "${rocksdb}/lib/librocksdb.dylib" $out/bin/${pname}
'';
meta = with lib; {
description = "example chain binary in cosmos-sdk repo";
homepage = "https://github.com/cosmos/cosmos-sdk";
license = licenses.asl20;
mainProgram = pname + stdenv.hostPlatform.extensions.executable;
platforms = platforms.all;
};
}

View File

@ -1,54 +0,0 @@
package simapp
import (
"context"
"cosmossdk.io/runtime/v2/services"
"cosmossdk.io/x/staking"
v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2"
)
// ExportAppStateAndValidators exports the state of the application for a genesis
// file.
// This is a demonstation of how to export a genesis file. Export may need extended at
// the user discretion for cleaning the genesis state at the end provided with jailAllowedAddrs
// Same applies for forZeroHeight preprocessing.
func (app *SimApp[T]) ExportAppStateAndValidators(
forZeroHeight bool,
jailAllowedAddrs []string,
) (v2.ExportedApp, error) {
ctx := context.Background()
var exportedApp v2.ExportedApp
latestHeight, err := app.LoadLatestHeight()
if err != nil {
return exportedApp, err
}
genesis, err := app.ExportGenesis(ctx, latestHeight)
if err != nil {
return exportedApp, err
}
readerMap, err := app.Store().StateAt(latestHeight)
if err != nil {
return exportedApp, err
}
genesisCtx := services.NewGenesisContext(readerMap)
err = genesisCtx.Read(ctx, func(ctx context.Context) error {
exportedApp.Validators, err = staking.WriteValidators(ctx, app.StakingKeeper)
return err
})
if err != nil {
return exportedApp, err
}
exportedApp.AppState = genesis
exportedApp.Height = int64(latestHeight)
if forZeroHeight {
exportedApp.Height = 0
}
return exportedApp, nil
}

View File

@ -1,47 +0,0 @@
package simapp
import (
"errors"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
var _ authtypes.GenesisAccount = (*SimGenesisAccount)(nil)
// SimGenesisAccount defines a type that implements the GenesisAccount interface
// to be used for simulation accounts in the genesis state.
type SimGenesisAccount struct {
*authtypes.BaseAccount
// vesting account fields
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // total vesting coins upon initialization
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // delegated vested coins at time of delegation
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // delegated vesting coins at time of delegation
StartTime int64 `json:"start_time" yaml:"start_time"` // vesting start time (UNIX Epoch time)
EndTime int64 `json:"end_time" yaml:"end_time"` // vesting end time (UNIX Epoch time)
// module account fields
ModuleName string `json:"module_name" yaml:"module_name"` // name of the module account
ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"` // permissions of module account
}
// Validate checks for errors on the vesting and module account parameters
func (sga SimGenesisAccount) Validate() error {
if !sga.OriginalVesting.IsZero() {
if sga.StartTime >= sga.EndTime {
return errors.New("vesting start-time cannot be after end-time")
}
}
if sga.ModuleName != "" {
ma := authtypes.ModuleAccount{
BaseAccount: sga.BaseAccount, Name: sga.ModuleName, Permissions: sga.ModulePermissions,
}
if err := ma.Validate(); err != nil {
return err
}
}
return sga.BaseAccount.Validate()
}

View File

@ -1,88 +0,0 @@
package simapp_test
import (
"testing"
"time"
"github.com/cometbft/cometbft/crypto"
"github.com/stretchr/testify/require"
"cosmossdk.io/simapp/v2"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
func TestSimGenesisAccountValidate(t *testing.T) {
pubkey := secp256k1.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
vestingStart := time.Now().UTC()
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 1000))
baseAcc := authtypes.NewBaseAccount(addr, pubkey, 0, 0)
testCases := []struct {
name string
sga simapp.SimGenesisAccount
wantErr bool
}{
{
"valid basic account",
simapp.SimGenesisAccount{
BaseAccount: baseAcc,
},
false,
},
{
"invalid basic account with mismatching address/pubkey",
simapp.SimGenesisAccount{
BaseAccount: authtypes.NewBaseAccount(addr, secp256k1.GenPrivKey().PubKey(), 0, 0),
},
true,
},
{
"valid basic account with module name",
simapp.SimGenesisAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, 0, 0),
ModuleName: "testmod",
},
false,
},
{
"valid basic account with invalid module name/pubkey pair",
simapp.SimGenesisAccount{
BaseAccount: baseAcc,
ModuleName: "testmod",
},
true,
},
{
"valid basic account with valid vesting attributes",
simapp.SimGenesisAccount{
BaseAccount: baseAcc,
OriginalVesting: coins,
StartTime: vestingStart.Unix(),
EndTime: vestingStart.Add(1 * time.Hour).Unix(),
},
false,
},
{
"valid basic account with invalid vesting end time",
simapp.SimGenesisAccount{
BaseAccount: baseAcc,
OriginalVesting: coins,
StartTime: vestingStart.Add(2 * time.Hour).Unix(),
EndTime: vestingStart.Add(1 * time.Hour).Unix(),
},
true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
require.Equal(t, tc.wantErr, tc.sga.Validate() != nil)
})
}
}

View File

@ -1,274 +0,0 @@
module cosmossdk.io/simapp/v2
go 1.23.4
require (
cosmossdk.io/api v0.8.2
cosmossdk.io/client/v2 v2.10.0-beta.1
cosmossdk.io/core v1.0.0 // main
cosmossdk.io/core/testing v0.0.1 // indirect; main
cosmossdk.io/depinject v1.1.0
cosmossdk.io/indexer/postgres v0.1.0
cosmossdk.io/log v1.5.0
cosmossdk.io/math v1.5.0
cosmossdk.io/runtime/v2 v2.0.0-beta.1 // main
cosmossdk.io/server/v2 v2.0.0-beta.2 // main
cosmossdk.io/server/v2/appmanager v1.0.0-beta.2
cosmossdk.io/server/v2/cometbft v1.0.0-beta.1
cosmossdk.io/store/v2 v2.0.0-beta.1.0.20250113105648-064c9ba6385a // main
cosmossdk.io/tools/benchmark v0.2.0-rc.1
cosmossdk.io/tools/confix v0.2.0-rc.1
cosmossdk.io/x/accounts v0.2.0-rc.1
cosmossdk.io/x/accounts/defaults/base v0.2.0-rc.1
cosmossdk.io/x/accounts/defaults/lockup v0.2.0-rc.1
cosmossdk.io/x/accounts/defaults/multisig v0.2.0-rc.1
cosmossdk.io/x/authz v0.2.0-rc.1
cosmossdk.io/x/bank v0.2.0-rc.1
cosmossdk.io/x/circuit v0.2.0-rc.1
cosmossdk.io/x/consensus v0.2.0-rc.1
cosmossdk.io/x/distribution v0.2.0-rc.1
cosmossdk.io/x/epochs v0.2.0-rc.1
cosmossdk.io/x/evidence v0.2.0-rc.1
cosmossdk.io/x/feegrant v0.2.0-rc.1
cosmossdk.io/x/gov v0.2.0-rc.1
cosmossdk.io/x/group v0.2.0-rc.1
cosmossdk.io/x/mint v0.2.0-rc.1
cosmossdk.io/x/nft v0.2.0-rc.1
cosmossdk.io/x/protocolpool v0.2.0-rc.1
cosmossdk.io/x/slashing v0.2.0-rc.1
cosmossdk.io/x/staking v0.2.0-rc.1
cosmossdk.io/x/upgrade v0.2.0-rc.1
github.com/cometbft/cometbft v1.0.0
github.com/cometbft/cometbft/api v1.0.0
// this version is not used as it is always replaced by the latest Cosmos SDK version
github.com/cosmos/cosmos-sdk v0.52.0
github.com/jackc/pgx/v5 v5.7.1
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0
google.golang.org/protobuf v1.36.2
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.2-20241120201313-68e42a58b301.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.2-20240130113600-88ef6483f90f.1 // indirect
cloud.google.com/go v0.115.0 // indirect
cloud.google.com/go/auth v0.5.1 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
cloud.google.com/go/iam v1.1.8 // indirect
cloud.google.com/go/storage v1.42.0 // indirect
cosmossdk.io/collections v1.0.0 // indirect; main
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/errors/v2 v2.0.0 // indirect
cosmossdk.io/schema v1.0.0 // indirect
cosmossdk.io/server/v2/stf v1.0.0-beta.2 // indirect; main
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 // indirect; main
cosmossdk.io/x/tx v1.0.0 // indirect; main
filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect
github.com/DataDog/datadog-go v4.8.3+incompatible // indirect
github.com/DataDog/zstd v1.5.6 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/aws/aws-sdk-go v1.54.6 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.2.0 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/cockroachdb/errors v1.11.3 // indirect
github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.2 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/cometbft/cometbft-db v1.0.1 // indirect
github.com/cosmos/btcutil v1.0.5 // indirect
github.com/cosmos/cosmos-db v1.1.1 // indirect
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/go-bip39 v1.0.0 // indirect
github.com/cosmos/gogogateway v1.2.0 // indirect
github.com/cosmos/gogoproto v1.7.0 // indirect
github.com/cosmos/iavl v1.3.5 // indirect
github.com/cosmos/ics23/go v0.11.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.14.0 // indirect
github.com/creachadair/atomicfile v0.3.4 // indirect
github.com/creachadair/tomledit v0.0.26 // indirect
github.com/danieljoos/wincred v1.2.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/dgraph-io/badger/v4 v4.5.0 // indirect
github.com/dgraph-io/ristretto/v2 v2.0.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.6.0 // indirect
github.com/emicklei/dot v1.6.2 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/getsentry/sentry-go v0.29.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v24.3.25+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.5 // indirect
github.com/gorilla/handlers v1.5.2 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-metrics v0.5.4 // indirect
github.com/hashicorp/go-plugin v1.6.2 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hdevalence/ed25519consensus v0.2.0 // indirect
github.com/huandu/skiplist v1.2.1 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
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.3 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mdp/qrterminal/v3 v3.2.0 // indirect
github.com/minio/highwayhash v1.0.3 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
github.com/muesli/termenv v0.15.2 // indirect
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/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_golang v1.20.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.61.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/cors v1.11.1 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/supranational/blst v0.3.13 // 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/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/zondax/hid v0.9.2 // indirect
github.com/zondax/ledger-go v1.0.0 // indirect
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
go.etcd.io/bbolt v1.4.0-alpha.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.52.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.12.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.27.0 // indirect
google.golang.org/api v0.185.0 // indirect
google.golang.org/genproto v0.0.0-20240617180043-68d350f18fd4 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
google.golang.org/grpc v1.69.4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
pgregory.net/rapid v1.1.0 // indirect
rsc.io/qr v0.2.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
require (
github.com/aybabtme/uniplot v0.0.0-20151203143629-039c559e5e7e // indirect
github.com/bvinc/go-sqlite-lite v0.6.1 // indirect
github.com/cosmos/iavl/v2 v2.0.0-alpha.4 // indirect
github.com/kocubinski/costor-api v1.1.1 // indirect
)
// Here are the short-lived replace from the SimApp
// Replace here are pending PRs, or version to be tagged
// replace (
// <temporary replace>
// )
replace cosmossdk.io/server/v2/cometbft => ../../server/v2/cometbft
// Below are the long-lived replace of the SimApp
replace (
// use cosmos fork of keyring
github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0
// Simapp always use the latest version of the cosmos-sdk
github.com/cosmos/cosmos-sdk => ../../.
// Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.1
// replace broken goleveldb
github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
)

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
//go:build sims
package simapp
import (
"github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
"testing"
)
func BenchmarkFullAppSimulation(b *testing.B) {
b.ReportAllocs()
cfg := cli.NewConfigFromFlags()
cfg.ChainID = SimAppChainID
for i := 0; i < b.N; i++ {
RunWithSeed[Tx](b, NewSimApp[Tx], AppConfig, cfg, 1)
}
}

View File

@ -1,23 +0,0 @@
//go:build sims
package simapp
import (
simsxv2 "github.com/cosmos/cosmos-sdk/simsx/v2"
simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
"testing"
)
func FuzzFullAppSimulation(f *testing.F) {
cfg := simcli.NewConfigFromFlags()
cfg.ChainID = SimAppChainID
f.Fuzz(func(t *testing.T, rawSeed []byte) {
if len(rawSeed) < 8 {
t.Skip()
return
}
randSource := simsxv2.NewByteSource(cfg.FuzzSeed, cfg.Seed)
RunWithRandSource[Tx](t, NewSimApp[Tx], AppConfig, cfg, randSource)
})
}

View File

@ -1,563 +0,0 @@
package simapp
import (
"context"
"encoding/json"
"fmt"
"iter"
"maps"
"math/rand"
"slices"
"testing"
"time"
cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
cmttypes "github.com/cometbft/cometbft/types"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/appmodule"
appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/comet"
corecontext "cosmossdk.io/core/context"
"cosmossdk.io/core/server"
"cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
"cosmossdk.io/server/v2/appmanager"
storev2 "cosmossdk.io/store/v2"
consensustypes "cosmossdk.io/x/consensus/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simsx"
simsxv2 "github.com/cosmos/cosmos-sdk/simsx/v2"
simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)
type Tx = transaction.Tx
type (
HasWeightedOperationsX = simsx.HasWeightedOperationsX
HasWeightedOperationsXWithProposals = simsx.HasWeightedOperationsXWithProposals
HasProposalMsgsX = simsx.HasProposalMsgsX
)
const SimAppChainID = "simulation-app"
// DefaultSeeds list of seeds was imported from the original simulation runner: https://github.com/cosmos/tools/blob/v1.0.0/cmd/runsim/main.go#L32
var DefaultSeeds = []int64{
1, 2, 4, 7,
32, 123, 124, 582, 1893, 2989,
3012, 4728, 37827, 981928, 87821, 891823782,
989182, 89182391, 11, 22, 44, 77, 99, 2020,
3232, 123123, 124124, 582582, 18931893,
29892989, 30123012, 47284728, 7601778, 8090485,
977367484, 491163361, 424254581, 673398983,
}
const (
maxTimePerBlock = 10_000 * time.Second
minTimePerBlock = maxTimePerBlock / 2
timeRangePerBlock = maxTimePerBlock - minTimePerBlock
)
type (
AuthKeeper interface {
simsx.ModuleAccountSource
simsx.AccountSource
}
BankKeeper interface {
simsx.BalanceSource
GetBlockedAddresses() map[string]bool
}
StakingKeeper interface {
UnbondingTime(ctx context.Context) (time.Duration, error)
}
ModuleManager interface {
Modules() map[string]appmodulev2.AppModule
}
// SimulationApp abstract blockchain app
SimulationApp[T Tx] interface {
appmanager.TransactionFuzzer[T]
InitGenesis(
ctx context.Context,
blockRequest *server.BlockRequest[T],
initGenesisJSON []byte,
txDecoder transaction.Codec[T],
) (*server.BlockResponse, store.WriterMap, error)
GetApp() *runtime.App[T]
TxConfig() client.TxConfig
AppCodec() codec.Codec
DefaultGenesis() map[string]json.RawMessage
Store() storev2.RootStore
Close() error
}
// TestInstance system under test
TestInstance[T Tx] struct {
RandSource simsxv2.RandSource
App SimulationApp[T]
TxDecoder transaction.Codec[T]
BankKeeper BankKeeper
AuthKeeper AuthKeeper
StakingKeeper StakingKeeper
TXBuilder simsxv2.TXBuilder[T]
AppManager appmanager.AppManager[T]
ModuleManager ModuleManager
}
AppFactory[T Tx, V SimulationApp[T]] func(config depinject.Config, outputs ...any) (V, error)
AppConfigFactory func() depinject.Config
)
// SetupTestInstance initializes and returns the system under test.
func SetupTestInstance[T Tx, V SimulationApp[T]](
tb testing.TB,
appFactory AppFactory[T, V],
appConfigFactory AppConfigFactory,
randSource simsxv2.RandSource,
) TestInstance[T] {
tb.Helper()
vp := viper.New()
vp.Set("store.app-db-backend", "memdb")
vp.Set("home", tb.TempDir())
depInjCfg := depinject.Configs(
depinject.Supply(log.NewNopLogger(), runtime.GlobalConfig(vp.AllSettings())),
appConfigFactory(),
)
var (
bankKeeper BankKeeper
authKeeper AuthKeeper
stKeeper StakingKeeper
)
err := depinject.Inject(depInjCfg,
&authKeeper,
&bankKeeper,
&stKeeper,
)
require.NoError(tb, err)
xapp, err := appFactory(depinject.Configs(depinject.Supply(log.NewNopLogger(), runtime.GlobalConfig(vp.AllSettings()))))
require.NoError(tb, err)
return TestInstance[T]{
RandSource: randSource,
App: xapp,
BankKeeper: bankKeeper,
AuthKeeper: authKeeper,
StakingKeeper: stKeeper,
AppManager: xapp.GetApp(),
ModuleManager: xapp.GetApp().ModuleManager(),
TxDecoder: simsxv2.NewGenericTxDecoder[T](xapp.TxConfig()),
TXBuilder: simsxv2.NewSDKTXBuilder[T](xapp.TxConfig(), simsxv2.DefaultGenTxGas),
}
}
// InitializeChain sets up the blockchain with an initial state, validator set, and history using the provided genesis data.
func (ti TestInstance[T]) InitializeChain(
tb testing.TB,
ctx context.Context,
chainID string,
genesisTimestamp time.Time,
initialHeight uint64,
genesisAppState json.RawMessage,
) ChainState[T] {
tb.Helper()
initRsp, stateRoot := doChainInitWithGenesis(
tb,
ctx,
chainID,
genesisTimestamp,
initialHeight,
genesisAppState,
ti,
)
activeValidatorSet := simsxv2.NewValSet().Update(initRsp.ValidatorUpdates)
valsetHistory := simsxv2.NewValSetHistory(initialHeight)
valsetHistory.Add(genesisTimestamp, activeValidatorSet)
return ChainState[T]{
ChainID: chainID,
BlockTime: genesisTimestamp,
BlockHeight: initialHeight,
ActiveValidatorSet: activeValidatorSet,
ValsetHistory: valsetHistory,
AppHash: stateRoot,
}
}
// RunWithSeeds runs a series of subtests for each of the given set of seeds for deterministic simulation testing.
func RunWithSeeds[T Tx, V SimulationApp[T]](
t *testing.T,
appFactory AppFactory[T, V],
appConfigFactory AppConfigFactory,
seeds []int64,
postRunActions ...func(t testing.TB, cs ChainState[T], app TestInstance[T], accs []simtypes.Account),
) {
t.Helper()
cfg := cli.NewConfigFromFlags()
cfg.ChainID = SimAppChainID
for _, seed := range seeds {
t.Run(fmt.Sprintf("seed: %d", seed), func(t *testing.T) {
t.Parallel()
RunWithSeed(t, appFactory, appConfigFactory, cfg, seed, postRunActions...)
})
}
}
// RunWithSeed initializes and executes a simulation run with the given seed, generating blocks and transactions.
func RunWithSeed[T Tx, V SimulationApp[T]](
tb testing.TB,
appFactory AppFactory[T, V],
appConfigFactory AppConfigFactory,
tCfg simtypes.Config,
seed int64,
postRunActions ...func(t testing.TB, cs ChainState[T], app TestInstance[T], accs []simtypes.Account),
) {
tb.Helper()
RunWithRandSource(tb, appFactory, appConfigFactory, tCfg, simsxv2.NewSeededRandSource(seed), postRunActions...)
}
// RunWithRandSource initializes and executes a simulation run with the given rand source, generating blocks and transactions.
func RunWithRandSource[T Tx, V SimulationApp[T]](
tb testing.TB,
appFactory AppFactory[T, V],
appConfigFactory AppConfigFactory,
tCfg simtypes.Config,
randSource simsxv2.RandSource,
postRunActions ...func(t testing.TB, cs ChainState[T], app TestInstance[T], accs []simtypes.Account),
) {
tb.Helper()
initialBlockHeight := tCfg.InitialBlockHeight
require.NotEmpty(tb, initialBlockHeight, "initial block height must not be 0")
setupFn := func(ctx context.Context, r *rand.Rand) (TestInstance[T], ChainState[T], []simtypes.Account) {
testInstance := SetupTestInstance[T, V](tb, appFactory, appConfigFactory, randSource)
accounts, genesisAppState, chainID, genesisTimestamp := prepareInitialGenesisState(
testInstance.App,
r,
testInstance.BankKeeper,
tCfg,
testInstance.ModuleManager,
)
cs := testInstance.InitializeChain(
tb,
ctx,
chainID,
genesisTimestamp,
initialBlockHeight,
genesisAppState,
)
return testInstance, cs, accounts
}
RunWithRandSourceX(tb, tCfg, setupFn, randSource, postRunActions...)
}
// RunWithRandSourceX entrypoint for custom chain setups.
// The function runs the full simulation test circle for the specified random source and setup function, followed by optional post-run actions.
// when tb implements ResetTimer, the method is called after setup, before jumping into the main loop
func RunWithRandSourceX[T Tx](
tb testing.TB,
tCfg simtypes.Config,
setupChainStateFn func(ctx context.Context, r *rand.Rand) (TestInstance[T], ChainState[T], []simtypes.Account),
randSource rand.Source,
postRunActions ...func(t testing.TB, cs ChainState[T], app TestInstance[T], accs []simtypes.Account),
) {
tb.Helper()
r := rand.New(randSource)
rootCtx, done := context.WithCancel(context.Background())
defer done()
testInstance, chainState, accounts := setupChainStateFn(rootCtx, r)
emptySimParams := make(map[string]json.RawMessage) // todo read sims params from disk as before
modules := testInstance.ModuleManager.Modules()
msgFactoriesFn := prepareSimsMsgFactories(r, modules, simsx.ParamWeightSource(emptySimParams))
if b, ok := tb.(interface{ ResetTimer() }); ok {
b.ResetTimer()
}
doMainLoop(
tb,
rootCtx,
testInstance,
&chainState,
msgFactoriesFn,
r,
tCfg,
accounts,
)
for _, step := range postRunActions {
step(tb, chainState, testInstance, accounts)
}
require.NoError(tb, testInstance.App.Close(), "closing app")
}
// prepareInitialGenesisState initializes the genesis state for simulation by generating accounts, app state, chain ID, and timestamp.
// It uses a random seed, configuration parameters, and module manager to customize the state.
// Blocked accounts are removed from the simulation accounts list based on the bank keeper's configuration.
func prepareInitialGenesisState[T Tx](
app SimulationApp[T],
r *rand.Rand,
bankKeeper BankKeeper,
tCfg simtypes.Config,
moduleManager ModuleManager,
) ([]simtypes.Account, json.RawMessage, string, time.Time) {
txConfig := app.TxConfig()
// todo: replace legacy testdata functions ?
appStateFn := simtestutil.AppStateFn(
app.AppCodec(),
txConfig.SigningContext().AddressCodec(),
txConfig.SigningContext().ValidatorAddressCodec(),
toLegacySimsModule(moduleManager.Modules()),
app.DefaultGenesis(),
)
params := simulation.RandomParams(r)
accounts := slices.DeleteFunc(simtypes.RandomAccounts(r, params.NumKeys()),
func(acc simtypes.Account) bool { // remove blocked accounts
return bankKeeper.GetBlockedAddresses()[acc.AddressBech32]
})
appState, accounts, chainID, genesisTimestamp := appStateFn(r, accounts, tCfg)
return accounts, appState, chainID, genesisTimestamp
}
// doChainInitWithGenesis initializes the blockchain state with the provided genesis data and returns the initial block response and state root.
func doChainInitWithGenesis[T Tx](
tb testing.TB,
ctx context.Context,
chainID string,
genesisTimestamp time.Time,
initialHeight uint64,
genesisAppState json.RawMessage,
testInstance TestInstance[T],
) (*server.BlockResponse, store.Hash) {
tb.Helper()
app := testInstance.App
txDecoder := testInstance.TxDecoder
appStore := testInstance.App.Store()
genesisReq := &server.BlockRequest[T]{
Height: initialHeight,
Time: genesisTimestamp,
Hash: make([]byte, 32),
ChainId: chainID,
AppHash: make([]byte, 32),
IsGenesis: true,
}
initialConsensusParams := &consensustypes.MsgUpdateParams{
Block: &cmtproto.BlockParams{
MaxBytes: 200000,
MaxGas: 100_000_000,
},
Evidence: &cmtproto.EvidenceParams{
MaxAgeNumBlocks: 302400,
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
MaxBytes: 10000,
},
Validator: &cmtproto.ValidatorParams{PubKeyTypes: []string{cmttypes.ABCIPubKeyTypeEd25519, cmttypes.ABCIPubKeyTypeSecp256k1}},
}
genesisCtx := context.WithValue(ctx, corecontext.CometParamsInitInfoKey, initialConsensusParams)
initRsp, genesisStateChanges, err := app.InitGenesis(genesisCtx, genesisReq, genesisAppState, txDecoder)
require.NoError(tb, err)
require.NoError(tb, appStore.SetInitialVersion(initialHeight-1))
changeSet, err := genesisStateChanges.GetStateChanges()
require.NoError(tb, err)
stateRoot, err := appStore.Commit(&store.Changeset{Changes: changeSet, Version: initialHeight - 1})
require.NoError(tb, err)
return initRsp, stateRoot
}
// ChainState represents the state of a blockchain during a simulation run.
type ChainState[T Tx] struct {
ChainID string
BlockTime time.Time
BlockHeight uint64
ActiveValidatorSet simsxv2.WeightedValidators
ValsetHistory *simsxv2.ValSetHistory
AppHash store.Hash
}
// doMainLoop executes the main simulation loop after chain setup with genesis block.
// Based on the initial seed and configurations, a deterministic set of messages is generated
// and executed. Events like validators missing votes or double signing are included in this
// process. The runtime tracks the validator's state and history.
func doMainLoop[T Tx](
tb testing.TB,
rootCtx context.Context,
testInstance TestInstance[T],
cs *ChainState[T],
nextMsgFactory func() simsx.SimMsgFactoryX,
r *rand.Rand,
tCfg simtypes.Config,
accounts []simtypes.Account,
) {
tb.Helper()
if len(cs.ActiveValidatorSet) == 0 {
tb.Fatal("no active validators in chain setup")
return
}
numBlocks := tCfg.NumBlocks
maxTXPerBlock := tCfg.BlockSize
var (
txSkippedCounter int
txTotalCounter int
)
rootReporter := simsx.NewBasicSimulationReporter()
futureOpsReg := simsxv2.NewFutureOpsRegistry()
for end := cs.BlockHeight + numBlocks; cs.BlockHeight < end; cs.BlockHeight++ {
if len(cs.ActiveValidatorSet) == 0 {
tb.Skipf("run out of validators in block: %d\n", cs.BlockHeight)
return
}
cs.BlockTime = cs.BlockTime.Add(minTimePerBlock).
Add(time.Duration(int64(r.Intn(int(timeRangePerBlock/time.Second)))) * time.Second)
cs.ValsetHistory.Add(cs.BlockTime, cs.ActiveValidatorSet)
blockReqN := &server.BlockRequest[T]{
Height: cs.BlockHeight,
Time: cs.BlockTime,
Hash: cs.AppHash,
AppHash: cs.AppHash,
ChainId: cs.ChainID,
}
cometInfo := comet.Info{
ValidatorsHash: nil,
Evidence: cs.ValsetHistory.MissBehaviour(r),
ProposerAddress: cs.ActiveValidatorSet[0].Address, // todo: pick random one
LastCommit: cs.ActiveValidatorSet.NewCommitInfo(r),
}
fOps, pos := futureOpsReg.PopScheduledFor(cs.BlockTime), 0
addressCodec := testInstance.App.TxConfig().SigningContext().AddressCodec()
simsCtx := context.WithValue(rootCtx, corecontext.CometInfoKey, cometInfo) // required for ContextAwareCometInfoService
resultHandlers := make([]simsx.SimDeliveryResultHandler, 0, maxTXPerBlock)
var txPerBlockCounter int
blockRsp, updates, err := testInstance.App.DeliverSims(simsCtx, blockReqN, func(ctx context.Context) iter.Seq[T] {
return func(yield func(T) bool) {
unbondingTime, err := testInstance.StakingKeeper.UnbondingTime(ctx)
require.NoError(tb, err)
cs.ValsetHistory.SetMaxHistory(minBlocksInUnbondingPeriod(unbondingTime))
testData := simsx.NewChainDataSource(ctx, r, testInstance.AuthKeeper, testInstance.BankKeeper, addressCodec, accounts...)
for txPerBlockCounter < maxTXPerBlock {
txPerBlockCounter++
mergedMsgFactory := func() simsx.SimMsgFactoryX {
if pos < len(fOps) {
pos++
return fOps[pos-1]
}
return nextMsgFactory()
}()
reporter := rootReporter.WithScope(mergedMsgFactory.MsgType())
if fx, ok := mergedMsgFactory.(simsx.HasFutureOpsRegistry); ok {
fx.SetFutureOpsRegistry(futureOpsReg)
continue
}
// the stf context is required to access state via keepers
signers, msg := mergedMsgFactory.Create()(ctx, testData, reporter)
if reporter.IsSkipped() {
txSkippedCounter++
require.NoError(tb, reporter.Close())
continue
}
resultHandlers = append(resultHandlers, mergedMsgFactory.DeliveryResultHandler())
reporter.Success(msg)
require.NoError(tb, reporter.Close())
tx, err := testInstance.TXBuilder.Build(ctx, testInstance.AuthKeeper, signers, msg, r, cs.ChainID)
require.NoError(tb, err)
if !yield(tx) {
return
}
}
}
})
require.NoError(tb, err, "%d, %s", blockReqN.Height, blockReqN.Time)
changeSet, err := updates.GetStateChanges()
require.NoError(tb, err)
cs.AppHash, err = testInstance.App.Store().Commit(&store.Changeset{
Version: blockReqN.Height,
Changes: changeSet,
})
require.NoError(tb, err)
require.Equal(tb, len(resultHandlers), len(blockRsp.TxResults), "txPerBlockCounter: %d, totalSkipped: %d", txPerBlockCounter, txSkippedCounter)
for i, v := range blockRsp.TxResults {
require.NoError(tb, resultHandlers[i](v.Error))
}
txTotalCounter += txPerBlockCounter
cs.ActiveValidatorSet = cs.ActiveValidatorSet.Update(blockRsp.ValidatorUpdates)
}
fmt.Println("+++ reporter:\n" + rootReporter.Summary().String())
fmt.Printf("Tx total: %d skipped: %d\n", txTotalCounter, txSkippedCounter)
}
// prepareSimsMsgFactories constructs and returns a function to retrieve simulation message factories for all modules.
// It initializes proposal and factory registries, registers proposals and weighted operations, and sorts deterministically.
func prepareSimsMsgFactories(
r *rand.Rand,
modules map[string]appmodulev2.AppModule,
weights simsx.WeightSource,
) func() simsx.SimMsgFactoryX {
moduleNames := slices.Collect(maps.Keys(modules))
slices.Sort(moduleNames) // make deterministic
// get all proposal types
proposalRegistry := simsx.NewUniqueTypeRegistry()
for _, n := range moduleNames {
switch xm := modules[n].(type) { // nolint: gocritic // extended in the future
case HasProposalMsgsX:
xm.ProposalMsgsX(weights, proposalRegistry)
// todo: register legacy and v1 msg proposals
}
}
// register all msg factories
factoryRegistry := simsx.NewUnorderedRegistry()
for _, n := range moduleNames {
switch xm := modules[n].(type) {
case HasWeightedOperationsX:
xm.WeightedOperationsX(weights, factoryRegistry)
case HasWeightedOperationsXWithProposals:
xm.WeightedOperationsX(weights, factoryRegistry, proposalRegistry.Iterator(), nil)
}
}
return simsxv2.NextFactoryFn(factoryRegistry.Elements(), r)
}
func toLegacySimsModule(modules map[string]appmodule.AppModule) []module.AppModuleSimulation {
r := make([]module.AppModuleSimulation, 0, len(modules))
names := slices.Collect(maps.Keys(modules))
slices.Sort(names) // make deterministic
for _, v := range names {
if m, ok := modules[v].(module.AppModuleSimulation); ok {
r = append(r, m)
}
}
return r
}
func minBlocksInUnbondingPeriod(unbondingTime time.Duration) int {
maxblocks := unbondingTime / maxTimePerBlock
return max(int(maxblocks)-1, 1)
}

View File

@ -1,108 +0,0 @@
//go:build sims
package simapp
import (
"bytes"
"context"
"math/rand"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
genutil "github.com/cosmos/cosmos-sdk/x/genutil/v2"
simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli"
)
func init() {
simcli.GetSimulatorFlags()
}
func TestFullAppSimulation(t *testing.T) {
RunWithSeeds[Tx](t, NewSimApp[Tx], AppConfig, DefaultSeeds)
}
// Scenario:
//
// Run 3 times a fresh node with the same seed,
// then the app hash should always be the same after n blocks
func TestAppStateDeterminism(t *testing.T) {
var seeds []int64
if s := simcli.NewConfigFromFlags().Seed; s != simcli.DefaultSeedValue {
// override defaults with user data
seeds = []int64{s, s, s} // run same simulation 3 times
} else {
seeds = []int64{ // some random seeds, tripled to ensure same app-hash on all runs
1, 1, 1,
3, 3, 3,
5, 5, 5,
}
}
var mx sync.Mutex
appHashResults := make(map[int64][]byte)
captureAndCheckHash := func(tb testing.TB, cs ChainState[Tx], ti TestInstance[Tx], _ []simtypes.Account) {
tb.Helper()
mx.Lock()
defer mx.Unlock()
seed := ti.RandSource.GetSeed()
otherHashes, ok := appHashResults[seed]
if !ok {
appHashResults[seed] = cs.AppHash
return
}
if !bytes.Equal(otherHashes, cs.AppHash) {
tb.Fatalf("non-determinism in seed %d", seed)
}
}
// run simulations
RunWithSeeds(t, NewSimApp[Tx], AppConfig, seeds, captureAndCheckHash)
}
// ExportableApp defines an interface for exporting application state and validator set.
type ExportableApp interface {
ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs []string) (genutil.ExportedApp, error)
}
// Scenario:
//
// Start a fresh node and run n blocks, export state
// set up a new node instance, Init chain from exported genesis
// run new instance for n blocks
func TestAppSimulationAfterImport(t *testing.T) {
appFactory := NewSimApp[Tx]
cfg := simcli.NewConfigFromFlags()
cfg.ChainID = SimAppChainID
exportAndStartChainFromGenesisPostAction := func(tb testing.TB, cs ChainState[Tx], ti TestInstance[Tx], accs []simtypes.Account) {
tb.Helper()
tb.Log("exporting genesis...\n")
app, ok := ti.App.(ExportableApp)
require.True(tb, ok)
exported, err := app.ExportAppStateAndValidators(false, []string{})
require.NoError(tb, err)
genesisTimestamp := cs.BlockTime.Add(24 * time.Hour)
startHeight := uint64(exported.Height + 1)
chainID := SimAppChainID + "_2"
importGenesisChainStateFactory := func(ctx context.Context, r *rand.Rand) (TestInstance[Tx], ChainState[Tx], []simtypes.Account) {
testInstance := SetupTestInstance(tb, appFactory, AppConfig, ti.RandSource)
newCs := testInstance.InitializeChain(
tb,
ctx,
chainID,
genesisTimestamp,
startHeight,
exported.AppState,
)
return testInstance, newCs, accs
}
// run sims with new app setup from exported genesis
RunWithRandSourceX[Tx](tb, cfg, importGenesisChainStateFactory, ti.RandSource)
}
RunWithSeeds[Tx, *SimApp[Tx]](t, appFactory, AppConfig, DefaultSeeds, exportAndStartChainFromGenesisPostAction)
}

View File

@ -1,281 +0,0 @@
package cmd
import (
"context"
"io"
"github.com/spf13/cobra"
"cosmossdk.io/client/v2/offchain"
coreserver "cosmossdk.io/core/server"
"cosmossdk.io/core/transaction"
"cosmossdk.io/log"
runtimev2 "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
grpcserver "cosmossdk.io/server/v2/api/grpc"
"cosmossdk.io/server/v2/api/grpcgateway"
"cosmossdk.io/server/v2/api/rest"
"cosmossdk.io/server/v2/api/telemetry"
"cosmossdk.io/server/v2/cometbft"
serverstore "cosmossdk.io/server/v2/store"
"cosmossdk.io/simapp/v2"
confixcmd "cosmossdk.io/tools/confix/cmd"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
sdktelemetry "github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/version"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli"
)
// CommandDependencies is a struct that contains all the dependencies needed to initialize the root command.
// an alternative design could fetch these even later from the command context
type CommandDependencies[T transaction.Tx] struct {
GlobalConfig coreserver.ConfigMap
TxConfig client.TxConfig
ModuleManager *runtimev2.MM[T]
SimApp *simapp.SimApp[T]
// could generally be more generic with serverv2.ServerComponent[T]
// however, we want to register extra grpc handlers
ConsensusServer *cometbft.CometBFTServer[T]
ClientContext client.Context
}
func InitRootCmd[T transaction.Tx](
rootCmd *cobra.Command,
logger log.Logger,
deps CommandDependencies[T],
) (serverv2.ConfigWriter, error) {
cfg := sdk.GetConfig()
cfg.Seal()
rootCmd.AddCommand(
genutilcli.InitCmd(deps.ModuleManager),
genesisCommand(deps.ModuleManager, deps.SimApp),
NewTestnetCmd(deps.ModuleManager),
debug.Cmd(),
confixcmd.ConfigCommand(),
// add keybase, auxiliary RPC, query, genesis, and tx child commands
queryCommand(),
txCommand(),
keys.Commands(),
offchain.OffChain(),
version.NewVersionCommand(),
)
// build CLI skeleton for initial config parsing or a client application invocation
if deps.SimApp == nil {
if deps.ConsensusServer == nil {
deps.ConsensusServer = cometbft.NewWithConfigOptions[T](initCometConfig())
}
return serverv2.AddCommands[T](
rootCmd,
logger,
io.NopCloser(nil),
deps.GlobalConfig,
initServerConfig(),
deps.ConsensusServer,
&grpcserver.Server[T]{},
&serverstore.Server[T]{},
&telemetry.Server[T]{},
&rest.Server[T]{},
&grpcgateway.Server[T]{},
)
}
// build full app!
simApp := deps.SimApp
// store component (not a server)
storeComponent, err := serverstore.New[T](simApp.Store(), deps.GlobalConfig)
if err != nil {
return nil, err
}
restServer, err := rest.New[T](logger, simApp.App.AppManager, deps.GlobalConfig)
if err != nil {
return nil, err
}
// consensus component
if deps.ConsensusServer == nil {
deps.ConsensusServer, err = cometbft.New(
logger,
simApp.Name(),
simApp.Store(),
simApp.App.AppManager,
cometbft.AppCodecs[T]{
AppCodec: simApp.AppCodec(),
TxCodec: &client.DefaultTxDecoder[T]{TxConfig: deps.TxConfig},
LegacyAmino: deps.ClientContext.LegacyAmino,
ConsensusAddressCodec: deps.ClientContext.ConsensusAddressCodec,
},
simApp.App.QueryHandlers(),
simApp.App.SchemaDecoderResolver(),
initCometOptions[T](),
deps.GlobalConfig,
)
if err != nil {
return nil, err
}
}
telemetryServer, err := telemetry.New[T](deps.GlobalConfig, logger, sdktelemetry.EnableTelemetry)
if err != nil {
return nil, err
}
grpcServer, err := grpcserver.New[T](
logger,
simApp.InterfaceRegistry(),
simApp.QueryHandlers(),
simApp.Query,
deps.GlobalConfig,
grpcserver.WithExtraGRPCHandlers[T](
deps.ConsensusServer.GRPCServiceRegistrar(
deps.ClientContext,
deps.GlobalConfig,
),
),
)
if err != nil {
return nil, err
}
grpcgatewayServer, err := grpcgateway.New[T](
logger,
deps.GlobalConfig,
simApp.InterfaceRegistry(),
simApp.App.AppManager,
)
if err != nil {
return nil, err
}
registerGRPCGatewayRoutes[T](deps, grpcgatewayServer)
// wire server commands
return serverv2.AddCommands[T](
rootCmd,
logger,
simApp,
deps.GlobalConfig,
initServerConfig(),
deps.ConsensusServer,
grpcServer,
storeComponent,
telemetryServer,
restServer,
grpcgatewayServer,
)
}
// genesisCommand builds genesis-related `simd genesis` command.
func genesisCommand[T transaction.Tx](
moduleManager *runtimev2.MM[T],
app *simapp.SimApp[T],
) *cobra.Command {
var genTxValidator func([]transaction.Msg) error
if moduleManager != nil {
genTxValidator = moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule).GenTxValidator()
}
cmd := v2.Commands(
genTxValidator,
moduleManager,
app,
)
return cmd
}
func queryCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
Aliases: []string{"q"},
Short: "Querying subcommands",
DisableFlagParsing: false,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
cmd.AddCommand(
rpc.QueryEventForTxCmd(),
authcmd.QueryTxsByEventsCmd(),
authcmd.QueryTxCmd(),
)
return cmd
}
func txCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "tx",
Short: "Transactions subcommands",
DisableFlagParsing: false,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
cmd.AddCommand(
authcmd.GetSignCommand(),
authcmd.GetSignBatchCommand(),
authcmd.GetMultiSignCommand(),
authcmd.GetMultiSignBatchCmd(),
authcmd.GetValidateSignaturesCommand(),
authcmd.GetBroadcastCommand(),
authcmd.GetEncodeCommand(),
authcmd.GetDecodeCommand(),
authcmd.GetSimulateCmd(),
)
return cmd
}
func RootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command, []string) error {
return func(cmd *cobra.Command, args []string) error {
// set the default command outputs
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())
clientCtx = clientCtx.WithCmdContext(cmd.Context())
clientCtx, err := client.ReadPersistentCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(
clientCtx, customClientTemplate, customClientConfig)
if err != nil {
return err
}
if err = client.SetCmdClientContextHandler(clientCtx, cmd); err != nil {
return err
}
return nil
}
}
// registerGRPCGatewayRoutes registers the gRPC gateway routes for all modules and other components
// TODO(@julienrbrt): Eventually, this should removed and directly done within the grpcgateway.Server
// ref: https://github.com/cosmos/cosmos-sdk/pull/22701#pullrequestreview-2470651390
func registerGRPCGatewayRoutes[T transaction.Tx](
deps CommandDependencies[T],
server *grpcgateway.Server[T],
) {
// those are the extra services that the CometBFT server implements (server/v2/cometbft/grpc.go)
cmtservice.RegisterGRPCGatewayRoutes(deps.ClientContext, server.GRPCGatewayRouter)
_ = nodeservice.RegisterServiceHandlerClient(context.Background(), server.GRPCGatewayRouter, nodeservice.NewServiceClient(deps.ClientContext))
_ = txtypes.RegisterServiceHandlerClient(context.Background(), server.GRPCGatewayRouter, txtypes.NewServiceClient(deps.ClientContext))
}

View File

@ -1,112 +0,0 @@
package cmd
import (
"strings"
"time"
cmtcfg "github.com/cometbft/cometbft/config"
"cosmossdk.io/core/transaction"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/cometbft"
clientconfig "github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)
// initAppConfig helps to override default client config template and configs.
// return "", nil if no custom configuration is required for the application.
func initClientConfig() (string, interface{}) {
type GasConfig struct {
GasAdjustment float64 `mapstructure:"gas-adjustment"`
}
type CustomClientConfig struct {
clientconfig.Config `mapstructure:",squash"`
GasConfig GasConfig `mapstructure:"gas"`
}
// Optionally allow the chain developer to overwrite the SDK's default client config.
clientCfg := clientconfig.DefaultConfig()
// The SDK's default keyring backend is set to "os".
// This is more secure than "test" and is the recommended value.
//
// In simapp, we set the default keyring backend to test, as SimApp is meant
// to be an example and testing application.
clientCfg.KeyringBackend = keyring.BackendTest
// Now we set the custom config default values.
customClientConfig := CustomClientConfig{
Config: *clientCfg,
GasConfig: GasConfig{
GasAdjustment: 1.5,
},
}
// The default SDK app template is defined in serverconfig.DefaultConfigTemplate.
// We append the custom config template to the default one.
// And we set the default config to the custom app template.
customClientConfigTemplate := clientconfig.DefaultClientConfigTemplate + strings.TrimSpace(`
# This is default the gas adjustment factor used in tx commands.
# It can be overwritten by the --gas-adjustment flag in each tx command.
gas-adjustment = {{ .GasConfig.GasAdjustment }}
`)
return customClientConfigTemplate, customClientConfig
}
// Allow the chain developer to overwrite the server default app toml config.
func initServerConfig() serverv2.ServerConfig {
serverCfg := serverv2.DefaultServerConfig()
// The server's default minimum gas price is set to "0stake" inside
// app.toml. However, the chain developer can set a default app.toml value for their
// validators here. Please update value based on chain denom.
//
// In summary:
// - if you set serverCfg.MinGasPrices value, validators CAN tweak their
// own app.toml to override, or use this default value.
//
// In simapp, we set the min gas prices to 0.
serverCfg.MinGasPrices = "0stake"
return serverCfg
}
// initCometConfig helps to override default comet config template and configs.
func initCometConfig() cometbft.CfgOption {
cfg := cmtcfg.DefaultConfig()
// display only warn logs by default except for p2p and state
cfg.LogLevel = "*:warn,p2p:info,state:info,server:info,telemetry:info,grpc:info,rest:info,grpc-gateway:info,comet:info,store:info"
// increase block timeout
cfg.Consensus.TimeoutCommit = 5 * time.Second
// overwrite default pprof listen address
cfg.RPC.PprofListenAddress = "localhost:6060"
// use previous db backend
cfg.DBBackend = "goleveldb"
return cometbft.OverwriteDefaultConfigTomlConfig(cfg)
}
func initCometOptions[T transaction.Tx]() cometbft.ServerOptions[T] {
serverOptions := cometbft.DefaultServerOptions[T]()
// Implement custom handlers (e.g. for Vote Extensions)
// serverOptions.PrepareProposalHandler = CustomPrepareProposal[T]()
// serverOptions.ProcessProposalHandler = CustomProcessProposalHandler[T]()
// serverOptions.ExtendVoteHandler = CustomExtendVoteHandler[T]()
// overwrite app mempool, using max-txs option
// serverOptions.Mempool = func(cfg map[string]any) mempool.Mempool[T] {
// if maxTxs := cast.ToInt(cfg[cometbft.FlagMempoolMaxTxs]); maxTxs >= 0 {
// return sdkmempool.NewSenderNonceMempool(
// sdkmempool.SenderNonceMaxTxOpt(maxTxs),
// )
// }
// return mempool.NoOpMempool[T]{}
// }
return serverOptions
}

View File

@ -1,69 +0,0 @@
package cmd
import (
"os"
"cosmossdk.io/core/address"
"cosmossdk.io/core/registry"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtxconfig "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
// ProvideClientContext is a depinject Provider function which assembles and returns a client.Context.
func ProvideClientContext(
configMap runtime.GlobalConfig,
appCodec codec.Codec,
interfaceRegistry codectypes.InterfaceRegistry,
txConfigOpts tx.ConfigOptions,
legacyAmino registry.AminoRegistrar,
addressCodec address.Codec,
validatorAddressCodec address.ValidatorAddressCodec,
consensusAddressCodec address.ConsensusAddressCodec,
) client.Context {
var err error
amino, ok := legacyAmino.(*codec.LegacyAmino)
if !ok {
panic("registry.AminoRegistrar must be an *codec.LegacyAmino instance for legacy ClientContext")
}
homeDir, ok := configMap[serverv2.FlagHome].(string)
if !ok {
panic("server.ConfigMap must contain a string value for serverv2.FlagHome")
}
clientCtx := client.Context{}.
WithCodec(appCodec).
WithInterfaceRegistry(interfaceRegistry).
WithLegacyAmino(amino).
WithInput(os.Stdin).
WithAccountRetriever(types.AccountRetriever{}).
WithAddressCodec(addressCodec).
WithValidatorAddressCodec(validatorAddressCodec).
WithConsensusAddressCodec(consensusAddressCodec).
WithHomeDir(homeDir).
WithViper("") // uses by default the binary name as prefix
// Read the config to overwrite the default values with the values from the config file
customClientTemplate, customClientConfig := initClientConfig()
clientCtx, err = config.CreateClientConfig(clientCtx, customClientTemplate, customClientConfig)
if err != nil {
panic(err)
}
// textual is enabled by default, we need to re-create the tx config grpc instead of bank keeper.
txConfigOpts.TextualCoinMetadataQueryFn = authtxconfig.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfig, err := tx.NewTxConfigWithOptions(clientCtx.Codec, txConfigOpts)
if err != nil {
panic(err)
}
clientCtx = clientCtx.WithTxConfig(txConfig)
return clientCtx
}

View File

@ -1,113 +0,0 @@
package cmd
import (
"errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"cosmossdk.io/client/v2/autocli"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/simapp/v2"
"github.com/cosmos/cosmos-sdk/client"
)
func NewRootCmd[T transaction.Tx](
args ...string,
) (*cobra.Command, error) {
rootCommand := &cobra.Command{
Use: "simdv2",
SilenceErrors: true,
}
configWriter, err := InitRootCmd(rootCommand, log.NewNopLogger(), CommandDependencies[T]{})
if err != nil {
return nil, err
}
factory, err := serverv2.NewCommandFactory(
serverv2.WithConfigWriter(configWriter),
serverv2.WithStdDefaultHomeDir(".simappv2"),
serverv2.WithLoggerFactory(serverv2.NewLogger),
)
if err != nil {
return nil, err
}
var autoCliOpts autocli.AppOptions
if err := depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinject.Supply(runtime.GlobalConfig{}, log.NewNopLogger())),
&autoCliOpts,
); err != nil {
return nil, err
}
if err = autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
subCommand, configMap, logger, err := factory.ParseCommand(rootCommand, args)
if err != nil {
if errors.Is(err, pflag.ErrHelp) {
return rootCommand, nil
}
return nil, err
}
var (
moduleManager *runtime.MM[T]
clientCtx client.Context
simApp *simapp.SimApp[T]
depinjectConfig = depinject.Configs(
depinject.Supply(logger, runtime.GlobalConfig(configMap)),
depinject.Provide(ProvideClientContext),
)
)
if serverv2.IsAppRequired(subCommand) {
// server construction
simApp, err = simapp.NewSimApp[T](depinjectConfig, &autoCliOpts, &moduleManager, &clientCtx)
if err != nil {
return nil, err
}
} else {
// client construction
if err = depinject.Inject(
depinject.Configs(
simapp.AppConfig(),
depinjectConfig,
),
&autoCliOpts, &moduleManager, &clientCtx,
); err != nil {
return nil, err
}
}
commandDeps := CommandDependencies[T]{
GlobalConfig: configMap,
TxConfig: clientCtx.TxConfig,
ModuleManager: moduleManager,
SimApp: simApp,
ClientContext: clientCtx,
}
rootCommand = &cobra.Command{
Use: "simdv2",
Short: "simulation app",
SilenceErrors: true,
PersistentPreRunE: RootCommandPersistentPreRun(clientCtx),
}
factory.EnhanceRootCommand(rootCommand)
_, err = InitRootCmd(rootCommand, logger, commandDeps)
if err != nil {
return nil, err
}
if err := autoCliOpts.EnhanceRootCommand(rootCommand); err != nil {
return nil, err
}
return rootCommand, nil
}

View File

@ -1,67 +0,0 @@
package cmd_test
import (
"bytes"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/transaction"
"cosmossdk.io/simapp/v2/simdv2/cmd"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
)
func TestInitCmd(t *testing.T) {
args := []string{
"init", // Test the init cmd
"simapp-test", // Moniker
fmt.Sprintf("--%s=%s", cli.FlagOverwrite, "true"), // Overwrite genesis.json, in case it already exists
}
rootCmd, err := cmd.NewRootCmd[transaction.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}
func TestHomeFlagRegistration(t *testing.T) {
homeDir := "/tmp/foo"
args := []string{
"query",
fmt.Sprintf("--%s", flags.FlagHome),
homeDir,
}
rootCmd, err := cmd.NewRootCmd[transaction.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
result, err := rootCmd.Flags().GetString(flags.FlagHome)
require.NoError(t, err)
require.Equal(t, result, homeDir)
}
func TestHelpRequested(t *testing.T) {
argz := [][]string{
{"query", "--help"},
{"query", "tx", "-h"},
{"--help"},
{"start", "-h"},
}
for _, args := range argz {
rootCmd, err := cmd.NewRootCmd[transaction.Tx](args...)
require.NoError(t, err)
var out bytes.Buffer
rootCmd.SetArgs(args)
rootCmd.SetOut(&out)
require.NoError(t, rootCmd.Execute())
require.Contains(t, out.String(), args[0])
require.Contains(t, out.String(), "--help")
require.Contains(t, out.String(), "Usage:")
}
}

View File

@ -1,526 +0,0 @@
package cmd
import (
"bufio"
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"time"
cmtconfig "github.com/cometbft/cometbft/config"
cmttime "github.com/cometbft/cometbft/types/time"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"cosmossdk.io/core/transaction"
"cosmossdk.io/math"
"cosmossdk.io/math/unsafe"
runtimev2 "cosmossdk.io/runtime/v2"
serverv2 "cosmossdk.io/server/v2"
"cosmossdk.io/server/v2/api/grpc"
"cosmossdk.io/server/v2/api/grpcgateway"
"cosmossdk.io/server/v2/api/rest"
"cosmossdk.io/server/v2/api/telemetry"
"cosmossdk.io/server/v2/cometbft"
"cosmossdk.io/server/v2/store"
banktypes "cosmossdk.io/x/bank/types"
stakingtypes "cosmossdk.io/x/staking/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/crypto/hd"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
)
var (
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "validator-count"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagListenIPAddress = "listen-ip-address"
flagStakingDenom = "staking-denom"
flagCommitTimeout = "commit-timeout"
flagSingleHost = "single-host"
)
type initArgs struct {
algo string
chainID string
keyringBackend string
minGasPrices string
nodeDaemonHome string
nodeDirPrefix string
numValidators int
outputDir string
startingIPAddress string
listenIPAddress string
singleMachine bool
bondTokenDenom string
}
func addTestnetFlagsToCmd(cmd *cobra.Command) {
cmd.Flags().IntP(flagNumValidators, "n", 4, "Number of validators to initialize the testnet with")
cmd.Flags().StringP(flagOutputDir, "o", "./.testnets", "Directory to store initialization data for the testnet")
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().String(serverv2.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
cmd.Flags().String(flags.FlagKeyType, string(hd.Secp256k1Type), "Key signing algorithm to generate keys for")
// support old flags name for backwards compatibility
cmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
if name == flags.FlagKeyAlgorithm {
name = flags.FlagKeyType
}
return pflag.NormalizedName(name)
})
}
// NewTestnetCmd creates a root testnet command with subcommands to run an in-process testnet or initialize
// validator configuration files for running a multi-validator testnet in a separate process
func NewTestnetCmd[T transaction.Tx](mm *runtimev2.MM[T]) *cobra.Command {
testnetCmd := &cobra.Command{
Use: "testnet",
Short: "subcommands for starting or configuring local testnets",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
testnetCmd.AddCommand(testnetInitFilesCmd(mm))
return testnetCmd
}
// testnetInitFilesCmd returns a cmd to initialize all files for CometBFT testnet and application
func testnetInitFilesCmd[T transaction.Tx](mm *runtimev2.MM[T]) *cobra.Command {
cmd := &cobra.Command{
Use: "init-files",
Short: "Initialize config directories & files for a multi-validator testnet running locally via separate processes (e.g. Docker Compose or similar)",
Long: fmt.Sprintf(`init-files will setup one directory per validator and populate each with
necessary files (private validator, genesis, config, etc.) for running validator nodes.
Booting up a network with these validator folders is intended to be used with Docker Compose,
or a similar setup where each node has a manually configurable IP address.
Note, strict routability for addresses is turned off in the config file.
Example:
%s testnet init-files --validator-count 4 --output-dir ./.testnets --starting-ip-address 192.168.10.2
`, version.AppName),
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
config := client.GetConfigFromCmd(cmd)
args := initArgs{}
args.outputDir, _ = cmd.Flags().GetString(flagOutputDir)
args.keyringBackend, _ = cmd.Flags().GetString(flags.FlagKeyringBackend)
args.chainID, _ = cmd.Flags().GetString(flags.FlagChainID)
args.minGasPrices, _ = cmd.Flags().GetString(serverv2.FlagMinGasPrices)
args.nodeDirPrefix, _ = cmd.Flags().GetString(flagNodeDirPrefix)
args.nodeDaemonHome, _ = cmd.Flags().GetString(flagNodeDaemonHome)
args.startingIPAddress, _ = cmd.Flags().GetString(flagStartingIPAddress)
args.listenIPAddress, _ = cmd.Flags().GetString(flagListenIPAddress)
args.numValidators, _ = cmd.Flags().GetInt(flagNumValidators)
args.algo, _ = cmd.Flags().GetString(flags.FlagKeyType)
args.bondTokenDenom, _ = cmd.Flags().GetString(flagStakingDenom)
args.singleMachine, _ = cmd.Flags().GetBool(flagSingleHost)
config.Consensus.TimeoutCommit, err = cmd.Flags().GetDuration(flagCommitTimeout)
if err != nil {
return err
}
return initTestnetFiles(clientCtx, cmd, config, mm, args)
},
}
addTestnetFlagsToCmd(cmd)
cmd.Flags().String(flagNodeDirPrefix, "node", "Prefix for the name of per-validator subdirectories (to be number-suffixed like node0, node1, ...)")
cmd.Flags().String(flagNodeDaemonHome, "simdv2", "Home directory of the node's daemon configuration")
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String(flagListenIPAddress, "127.0.0.1", "TCP or UNIX socket IP address for the RPC server to listen on")
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
cmd.Flags().Duration(flagCommitTimeout, 5*time.Second, "Time to wait after a block commit before starting on the new height")
cmd.Flags().Bool(flagSingleHost, false, "Cluster runs on a single host machine with different ports")
cmd.Flags().String(flagStakingDenom, sdk.DefaultBondDenom, "Default staking token denominator")
return cmd
}
const nodeDirPerm = 0o755
// initTestnetFiles initializes testnet files for a testnet to be run in a separate process
func initTestnetFiles[T transaction.Tx](
clientCtx client.Context,
cmd *cobra.Command,
nodeConfig *cmtconfig.Config,
mm *runtimev2.MM[T],
args initArgs,
) error {
if args.chainID == "" {
args.chainID = "chain-" + unsafe.Str(6)
}
nodeIDs := make([]string, args.numValidators)
valPubKeys := make([]cryptotypes.PubKey, args.numValidators)
var (
genAccounts []authtypes.GenesisAccount
genBalances []banktypes.Balance
genFiles []string
)
const (
rpcPort = 26657
apiPort = 1317
grpcPort = 9090
restPort = 8080
telemetryPort = 7180
)
p2pPortStart := 26656
inBuf := bufio.NewReader(cmd.InOrStdin())
// generate private keys, node IDs, and initial transactions
for i := 0; i < args.numValidators; i++ {
var portOffset int
grpcConfig := grpc.DefaultConfig()
grpcgatewayConfig := grpcgateway.DefaultConfig()
restConfig := rest.DefaultConfig()
telemetryConfig := telemetry.DefaultConfig()
if args.singleMachine {
portOffset = i
p2pPortStart = 16656 // use different start point to not conflict with rpc port
nodeConfig.P2P.AddrBookStrict = false
nodeConfig.P2P.PexReactor = false
nodeConfig.P2P.AllowDuplicateIP = true
grpcConfig = &grpc.Config{
Enable: true,
Address: fmt.Sprintf("127.0.0.1:%d", grpcPort+portOffset),
MaxRecvMsgSize: grpc.DefaultConfig().MaxRecvMsgSize,
MaxSendMsgSize: grpc.DefaultConfig().MaxSendMsgSize,
}
grpcgatewayConfig = &grpcgateway.Config{
Enable: true,
Address: fmt.Sprintf("127.0.0.1:%d", apiPort+portOffset),
}
restConfig = &rest.Config{
Enable: true,
Address: fmt.Sprintf("127.0.0.1:%d", restPort+portOffset),
}
telemetryConfig = &telemetry.Config{
Enable: true,
Address: fmt.Sprintf("127.0.0.1:%d", telemetryPort+portOffset),
}
}
nodeDirName := fmt.Sprintf("%s%d", args.nodeDirPrefix, i)
nodeDir := filepath.Join(args.outputDir, nodeDirName, args.nodeDaemonHome)
cmd.Println("Node dir", nodeDir)
gentxsDir := filepath.Join(args.outputDir, "gentxs")
nodeConfig.SetRoot(nodeDir)
nodeConfig.Moniker = nodeDirName
nodeConfig.RPC.ListenAddress = fmt.Sprintf("tcp://%s:%d", args.listenIPAddress, rpcPort+portOffset)
if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
var (
err error
ip string
)
if args.singleMachine {
ip = "127.0.0.1"
} else {
ip, err = getIP(i, args.startingIPAddress)
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
}
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(nodeConfig, args.algo)
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
memo := fmt.Sprintf("%s@%s:%d", nodeIDs[i], ip, p2pPortStart+portOffset)
genFiles = append(genFiles, nodeConfig.GenesisFile())
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, clientCtx.Codec)
if err != nil {
return err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(args.algo, keyringAlgos)
if err != nil {
return err
}
addr, secret, err := testutil.GenerateSaveCoinKey(kb, nodeDirName, "", true, algo, sdk.GetFullBIP44Path())
if err != nil {
_ = os.RemoveAll(args.outputDir)
return err
}
info := map[string]string{"secret": secret}
cliPrint, err := json.Marshal(info)
if err != nil {
return err
}
// save private key seed words
if err := writeFile(fmt.Sprintf("%v.json", "key_seed"), nodeDir, cliPrint); err != nil {
return err
}
accTokens := sdk.TokensFromConsensusPower(1000, sdk.DefaultPowerReduction)
accStakingTokens := sdk.TokensFromConsensusPower(500, sdk.DefaultPowerReduction)
coins := sdk.Coins{
sdk.NewCoin("testtoken", accTokens),
sdk.NewCoin(args.bondTokenDenom, accStakingTokens),
}
addrStr, err := clientCtx.AddressCodec.BytesToString(addr)
if err != nil {
return err
}
genBalances = append(genBalances, banktypes.Balance{Address: addrStr, Coins: coins.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
valStr, err := clientCtx.ValidatorAddressCodec.BytesToString(addr)
if err != nil {
return err
}
valTokens := sdk.TokensFromConsensusPower(100, sdk.DefaultPowerReduction)
createValMsg, err := stakingtypes.NewMsgCreateValidator(
valStr,
valPubKeys[i],
sdk.NewCoin(args.bondTokenDenom, valTokens),
stakingtypes.NewDescription(nodeDirName, "", "", "", ""),
stakingtypes.NewCommissionRates(math.LegacyOneDec(), math.LegacyOneDec(), math.LegacyOneDec()),
math.OneInt(),
)
if err != nil {
return err
}
txBuilder := clientCtx.TxConfig.NewTxBuilder()
if err := txBuilder.SetMsgs(createValMsg); err != nil {
return err
}
txBuilder.SetMemo(memo)
txBuilder.SetGasLimit(flags.DefaultGasLimit)
txBuilder.SetFeePayer(addr)
txFactory := tx.Factory{}
txFactory = txFactory.
WithChainID(args.chainID).
WithMemo(memo).
WithKeybase(kb).
WithTxConfig(clientCtx.TxConfig)
if err := tx.Sign(clientCtx, txFactory, nodeDirName, txBuilder, true); err != nil {
return err
}
txBz, err := clientCtx.TxConfig.TxJSONEncoder()(txBuilder.GetTx())
if err != nil {
return err
}
if err := writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz); err != nil {
return err
}
serverCfg := serverv2.DefaultServerConfig()
serverCfg.MinGasPrices = args.minGasPrices
cometServer := cometbft.NewWithConfigOptions[T](cometbft.OverwriteDefaultConfigTomlConfig(nodeConfig))
storeServer := &store.Server[T]{}
grpcServer := grpc.NewWithConfigOptions[T](grpc.OverwriteDefaultConfig(grpcConfig))
grpcgatewayServer := grpcgateway.NewWithConfigOptions[T](grpcgateway.OverwriteDefaultConfig(grpcgatewayConfig))
restServer := rest.NewWithConfigOptions[T](rest.OverwriteDefaultConfig(restConfig))
telemetryServer := telemetry.NewWithConfigOptions[T](telemetry.OverwriteDefaultConfig(telemetryConfig))
server := serverv2.NewServer[T](serverCfg, cometServer, storeServer, grpcServer, grpcgatewayServer, restServer, telemetryServer)
err = server.WriteConfig(filepath.Join(nodeDir, "config"))
if err != nil {
return err
}
}
if err := initGenFiles(clientCtx, mm, args.chainID, genAccounts, genBalances, genFiles, args.numValidators); err != nil {
return err
}
err := collectGenFiles(
clientCtx, nodeConfig, args.chainID, nodeIDs, valPubKeys, args.numValidators,
args.outputDir, args.nodeDirPrefix, args.nodeDaemonHome,
rpcPort, p2pPortStart, args.singleMachine,
)
if err != nil {
return err
}
serverv2.GetViperFromCmd(cmd).Set(flags.FlagHome, nodeConfig.RootDir)
cmd.PrintErrf("Successfully initialized %d node directories\n", args.numValidators)
return nil
}
func initGenFiles[T transaction.Tx](
clientCtx client.Context, mm *runtimev2.MM[T], chainID string,
genAccounts []authtypes.GenesisAccount, genBalances []banktypes.Balance,
genFiles []string, numValidators int,
) error {
appGenState := mm.DefaultGenesis()
// set the accounts in the genesis state
var authGenState authtypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[authtypes.ModuleName], &authGenState)
accounts, err := authtypes.PackAccounts(genAccounts)
if err != nil {
return err
}
authGenState.Accounts = accounts
appGenState[authtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&authGenState)
// set the balances in the genesis state
var bankGenState banktypes.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[banktypes.ModuleName], &bankGenState)
bankGenState.Balances, err = banktypes.SanitizeGenesisBalances(genBalances, clientCtx.AddressCodec)
if err != nil {
return err
}
for _, bal := range bankGenState.Balances {
bankGenState.Supply = bankGenState.Supply.Add(bal.Coins...)
}
appGenState[banktypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&bankGenState)
appGenStateJSON, err := json.MarshalIndent(appGenState, "", " ")
if err != nil {
return err
}
appGenesis := genutiltypes.NewAppGenesisWithVersion(chainID, appGenStateJSON)
// generate empty genesis files for each validator and save
for i := 0; i < numValidators; i++ {
if err := appGenesis.SaveAs(genFiles[i]); err != nil {
return err
}
}
return nil
}
func collectGenFiles(
clientCtx client.Context, nodeConfig *cmtconfig.Config, chainID string,
nodeIDs []string, valPubKeys []cryptotypes.PubKey, numValidators int,
outputDir, nodeDirPrefix, nodeDaemonHome string,
rpcPortStart, p2pPortStart int,
singleMachine bool,
) error {
var appState json.RawMessage
genTime := cmttime.Now()
for i := 0; i < numValidators; i++ {
if singleMachine {
portOffset := i
nodeConfig.RPC.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", rpcPortStart+portOffset)
nodeConfig.P2P.ListenAddress = fmt.Sprintf("tcp://127.0.0.1:%d", p2pPortStart+portOffset)
}
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
gentxsDir := filepath.Join(outputDir, "gentxs")
nodeConfig.Moniker = nodeDirName
nodeConfig.SetRoot(nodeDir)
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
initCfg := genutiltypes.NewInitConfig(chainID, gentxsDir, nodeID, valPubKey)
appGenesis, err := genutiltypes.AppGenesisFromFile(nodeConfig.GenesisFile())
if err != nil {
return err
}
nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, appGenesis, genutiltypes.DefaultMessageValidator,
clientCtx.ValidatorAddressCodec, clientCtx.AddressCodec)
if err != nil {
return err
}
if appState == nil {
// set the canonical application state (they should not differ)
appState = nodeAppState
}
genFile := nodeConfig.GenesisFile()
// overwrite each validator's genesis file to have a canonical genesis time
if err := genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime); err != nil {
return err
}
}
return nil
}
func getIP(i int, startingIPAddr string) (ip string, err error) {
if len(startingIPAddr) == 0 {
ip, err = serverv2.ExternalIP()
if err != nil {
return "", err
}
return ip, nil
}
return calculateIP(startingIPAddr, i)
}
func calculateIP(ip string, i int) (string, error) {
ipv4 := net.ParseIP(ip).To4()
if ipv4 == nil {
return "", fmt.Errorf("%v: non ipv4 address", ip)
}
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
}
func writeFile(name, dir string, contents []byte) error {
file := filepath.Join(dir, name)
if err := os.MkdirAll(dir, 0o755); err != nil {
return fmt.Errorf("could not create directory %q: %w", dir, err)
}
return os.WriteFile(file, contents, 0o600)
}

View File

@ -1,26 +0,0 @@
package cmd_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/transaction"
"cosmossdk.io/simapp/v2/simdv2/cmd"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
)
func TestInitTestFilesCmd(t *testing.T) {
args := []string{
"testnet", // Test the testnet init-files command
"init-files",
fmt.Sprintf("--%s=%s", flags.FlagKeyringBackend, keyring.BackendTest), // Set keyring-backend to test
}
rootCmd, err := cmd.NewRootCmd[transaction.Tx](args...)
require.NoError(t, err)
rootCmd.SetArgs(args)
require.NoError(t, rootCmd.Execute())
}

View File

@ -1,29 +0,0 @@
package main
import (
"errors"
"fmt"
"os"
"cosmossdk.io/core/transaction"
"cosmossdk.io/simapp/v2/simdv2/cmd"
)
func main() {
// reproduce default cobra behavior so that eager parsing of flags is possible.
// see: https://github.com/spf13/cobra/blob/e94f6d0dd9a5e5738dca6bce03c4b1207ffbc0ec/command.go#L1082
args := os.Args[1:]
rootCmd, err := cmd.NewRootCmd[transaction.Tx](args...)
if err != nil {
if _, pErr := fmt.Fprintln(os.Stderr, err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
if err = rootCmd.Execute(); err != nil {
if _, pErr := fmt.Fprintln(rootCmd.OutOrStderr(), err); pErr != nil {
panic(errors.Join(err, pErr))
}
os.Exit(1)
}
}

View File

@ -1,53 +0,0 @@
package simapp
import (
"context"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/core/store"
"cosmossdk.io/runtime/v2"
"cosmossdk.io/x/accounts"
epochstypes "cosmossdk.io/x/epochs/types"
protocolpooltypes "cosmossdk.io/x/protocolpool/types"
upgradetypes "cosmossdk.io/x/upgrade/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
)
// UpgradeName defines the on-chain upgrade name for the sample SimApp upgrade
// from v0.50.x to v2
//
// NOTE: This upgrade defines a reference implementation of what an upgrade
// could look like when an application is migrating from Cosmos SDK version
// v0.50.x to v2.
const UpgradeName = "v050-to-v2"
func (app *SimApp[T]) RegisterUpgradeHandlers() {
app.UpgradeKeeper.SetUpgradeHandler(
UpgradeName,
func(ctx context.Context, _ upgradetypes.Plan, fromVM appmodule.VersionMap) (appmodule.VersionMap, error) {
if err := authkeeper.MigrateAccountNumberUnsafe(ctx, &app.AuthKeeper); err != nil {
return nil, err
}
return app.ModuleManager().RunMigrations(ctx, fromVM)
},
)
upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(err)
}
if upgradeInfo.Name == UpgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
storeUpgrades := store.StoreUpgrades{
Added: []string{
accounts.ModuleName,
epochstypes.StoreKey,
protocolpooltypes.ModuleName,
},
Deleted: []string{"crisis"}, // The SDK discontinued the crisis module in v0.52.0
}
app.SetStoreLoader(runtime.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
}
}

View File

@ -6,7 +6,7 @@ sonar.project.monorepo.enabled=true
sonar.sources=.
sonar.exclusions=**/*_test.go,**/*.pb.go,**/*.pulsar.go,**/*.pb.gw.go,**/*.java
sonar.coverage.exclusions=**/*_test.go,**/testutil/**,**/*.pb.go,**/*.pb.gw.go,**/*.pulsar.go,docs/**,server/v2/**,store/v2/**,x/tx/**,tools/**,simapp/**,testutil/**,test_helpers.go,tests/**,test_helpers.go,docs/**,store/**,tests/**,orm/**,client/v2/**,runtime/v2/**,core/**,store/**,x/evidence/**,x/feegrant/**,x/authz/**,x/auth/**,x/bank/**,api,x/gov/**,x/staking/**,x/group/**,x/nft/**,x/epochs/**,x/upgrade/**,x/slashing/**,x/distribution/**,x/upgrade/**,x/protocolpool/**,x/mint/**,collections
sonar.coverage.exclusions=**/*_test.go,**/testutil/**,**/*.pb.go,**/*.pb.gw.go,**/*.pulsar.go,docs/**,x/tx/**,tools/**,simapp/**,testutil/**,test_helpers.go,tests/**,test_helpers.go,docs/**,store/**,tests/**,orm/**,client/v2/**,core/**,store/**,x/evidence/**,x/feegrant/**,x/authz/**,x/auth/**,x/bank/**,api,x/gov/**,x/staking/**,x/group/**,x/nft/**,x/epochs/**,x/upgrade/**,x/slashing/**,x/distribution/**,x/upgrade/**,x/protocolpool/**,x/mint/**,collections
sonar.tests=.
sonar.test.inclusions=**/*_test.go,tests/**,**/testutil/**
sonar.go.coverage.reportPaths=coverage.out,*profile.out

View File

@ -9,8 +9,6 @@ require (
cosmossdk.io/depinject v1.1.0
cosmossdk.io/log v1.5.0
cosmossdk.io/math v1.5.0
cosmossdk.io/runtime/v2 v2.0.0-20241107153845-4e240908dd60
cosmossdk.io/server/v2/stf v0.0.0-20241107153845-4e240908dd60
cosmossdk.io/simapp v0.0.0-20230309163709-87da587416ba
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43
cosmossdk.io/x/evidence v0.2.0-rc.1
@ -33,7 +31,6 @@ require (
)
require (
cosmossdk.io/store/v2 v2.0.0-20241209145349-34f407d6367a
cosmossdk.io/x/accounts v0.2.0-rc.1
cosmossdk.io/x/accounts/defaults/base v0.2.0-rc.1
cosmossdk.io/x/accounts/defaults/lockup v0.2.0-rc.1
@ -53,7 +50,7 @@ require (
github.com/google/gofuzz v1.2.0
github.com/jhump/protoreflect v1.17.0
github.com/spf13/viper v1.19.0
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
)
require (
@ -72,10 +69,8 @@ require (
cloud.google.com/go/storage v1.42.0 // indirect
cosmossdk.io/client/v2 v2.10.0-beta.1 // indirect
cosmossdk.io/errors v1.0.1 // indirect
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect
cosmossdk.io/indexer/postgres v0.1.0 // indirect
cosmossdk.io/schema v1.0.0 // indirect
cosmossdk.io/server/v2/appmanager v0.0.0-20241107153845-4e240908dd60 // indirect
cosmossdk.io/tools/benchmark v0.2.0-rc.1 // indirect
cosmossdk.io/x/circuit v0.2.0-rc.1 // indirect
cosmossdk.io/x/epochs v0.2.0-rc.1 // indirect
@ -178,7 +173,6 @@ require (
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/minio/highwayhash v1.0.3 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect

View File

@ -204,26 +204,16 @@ cosmossdk.io/depinject v1.1.0 h1:wLan7LG35VM7Yo6ov0jId3RHWCGRhe8E8bsuARorl5E=
cosmossdk.io/depinject v1.1.0/go.mod h1:kkI5H9jCGHeKeYWXTqYdruogYrEeWvBQCw1Pj4/eCFI=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U=
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 h1:IQNdY2kB+k+1OM2DvqFG1+UgeU1JzZrWtwuWzI3ZfwA=
cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5/go.mod h1:0CuYKkFHxc1vw2JC+t21THBCALJVROrWVR/3PQ1urpc=
cosmossdk.io/indexer/postgres v0.1.0 h1:BlHRa6g3taQ6HehZnVkvy2F2aq812fCZdizUEDYo+EA=
cosmossdk.io/indexer/postgres v0.1.0/go.mod h1:uinVfbarely9QIJjwgrIs+BzUMHHneXPimQZ/DsMOxU=
cosmossdk.io/log v1.5.0 h1:dVdzPJW9kMrnAYyMf1duqacoidB9uZIl+7c6z0mnq0g=
cosmossdk.io/log v1.5.0/go.mod h1:Tr46PUJjiUthlwQ+hxYtUtPn4D/oCZXAkYevBeh5+FI=
cosmossdk.io/math v1.5.0 h1:sbOASxee9Zxdjd6OkzogvBZ25/hP929vdcYcBJQbkLc=
cosmossdk.io/math v1.5.0/go.mod h1:AAwwBmUhqtk2nlku174JwSll+/DepUXW3rWIXN5q+Nw=
cosmossdk.io/runtime/v2 v2.0.0-20241107153845-4e240908dd60 h1:305IbyP2jaJeKNRglxBtEAY/JKz8rD3l+081zrAThGY=
cosmossdk.io/runtime/v2 v2.0.0-20241107153845-4e240908dd60/go.mod h1:zXxA8bHeShGxzTLR9m3OdF+aJ/IEmWSnrz343Ri6Me8=
cosmossdk.io/schema v1.0.0 h1:/diH4XJjpV1JQwuIozwr+A4uFuuwanFdnw2kKeiXwwQ=
cosmossdk.io/schema v1.0.0/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ=
cosmossdk.io/server/v2/appmanager v0.0.0-20241107153845-4e240908dd60 h1:M26/YrNRru59kzRkW/Mm7bnpEEsnR9rIFdNFGTXicGQ=
cosmossdk.io/server/v2/appmanager v0.0.0-20241107153845-4e240908dd60/go.mod h1:mONOF8GRbxs5R04zMscuQQI1gx/XHTY7imKjcwLI5uo=
cosmossdk.io/server/v2/stf v0.0.0-20241107153845-4e240908dd60 h1:+PYG1Wjsu8ZX5vvINPu7UjRxzT9m9sJ9SlS8MVApmOU=
cosmossdk.io/server/v2/stf v0.0.0-20241107153845-4e240908dd60/go.mod h1:njNsfl5hKTylxDgSiBTLuOM1tic04aPk0k5Af6ybPN0=
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 h1:glZ6MpmD+5AhwJYV4jzx+rn7cgUB2owHgk9o+93luz0=
cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43/go.mod h1:XCWpgfueHSBY+B7Cf2Aq/CcsU+6XoFH+EmseCKglFrU=
cosmossdk.io/store/v2 v2.0.0-20241108144957-78b5cd4dbd08 h1:7dIhcS/VhEM/vnZWDVtDKqCF/OGaq8Gx+5ekD9GT71k=
cosmossdk.io/store/v2 v2.0.0-20241108144957-78b5cd4dbd08/go.mod h1:A2aW375561viy3GcD8GhUwUWnow+R2Du6yCSpAGwsgY=
cosmossdk.io/x/tx v1.0.0 h1:pUUKRvHiMUZC/MnO8v747k1lUEA1DfAq0j0y0Mqrz/o=
cosmossdk.io/x/tx v1.0.0/go.mod h1:AXYJ47btzkcWuT1OtA3M44dv1iiYbKomtopHEbQGgH4=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
@ -679,8 +669,6 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q=
github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=

View File

@ -1,411 +0,0 @@
package integration
import (
"context"
"crypto/sha256"
"errors"
"fmt"
"math/rand"
"testing"
"time"
cmtproto "github.com/cometbft/cometbft/api/cometbft/types/v1"
cmtjson "github.com/cometbft/cometbft/libs/json"
cmttypes "github.com/cometbft/cometbft/types"
"github.com/stretchr/testify/require"
"cosmossdk.io/core/comet"
corecontext "cosmossdk.io/core/context"
"cosmossdk.io/core/server"
corestore "cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
"cosmossdk.io/depinject"
sdkmath "cosmossdk.io/math"
"cosmossdk.io/runtime/v2"
"cosmossdk.io/runtime/v2/services"
"cosmossdk.io/server/v2/stf"
"cosmossdk.io/server/v2/stf/branch"
"cosmossdk.io/store/v2"
"cosmossdk.io/store/v2/root"
bankkeeper "cosmossdk.io/x/bank/keeper"
banktypes "cosmossdk.io/x/bank/types"
consensustypes "cosmossdk.io/x/consensus/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsign "github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
const DefaultGenTxGas = 10000000
const (
Genesis_COMMIT = iota
Genesis_NOCOMMIT
Genesis_SKIP
)
type stateMachineTx = transaction.Tx
// DefaultConsensusParams defines the default CometBFT consensus params used in
// SimApp testing.
var DefaultConsensusParams = &cmtproto.ConsensusParams{
Version: &cmtproto.VersionParams{
App: 1,
},
Block: &cmtproto.BlockParams{
MaxBytes: 200000,
MaxGas: 100_000_000,
},
Evidence: &cmtproto.EvidenceParams{
MaxAgeNumBlocks: 302400,
MaxAgeDuration: 504 * time.Hour, // 3 weeks is the max duration
MaxBytes: 10000,
},
Validator: &cmtproto.ValidatorParams{
PubKeyTypes: []string{
cmttypes.ABCIPubKeyTypeEd25519,
cmttypes.ABCIPubKeyTypeSecp256k1,
},
},
}
// StartupConfig defines the startup configuration of a new test app.
type StartupConfig struct {
// ValidatorSet defines a custom validator set to be validating the app.
ValidatorSet func() (*cmttypes.ValidatorSet, error)
// AppOption defines the additional operations that will be run in the app builder phase.
AppOption runtime.AppBuilderOption[stateMachineTx]
// GenesisBehavior defines the behavior of the app at genesis.
GenesisBehavior int
// GenesisAccounts defines the genesis accounts to be used in the app.
GenesisAccounts []GenesisAccount
// HomeDir defines the home directory of the app where config and data will be stored.
HomeDir string
}
func DefaultStartUpConfig(t *testing.T) StartupConfig {
t.Helper()
priv := secp256k1.GenPrivKey()
ba := authtypes.NewBaseAccount(
priv.PubKey().Address().Bytes(),
priv.PubKey(),
0,
0,
)
ga := GenesisAccount{
ba,
sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000)),
),
}
homedir := t.TempDir()
t.Logf("generated integration test app config; HomeDir=%s", homedir)
return StartupConfig{
ValidatorSet: CreateRandomValidatorSet,
GenesisBehavior: Genesis_COMMIT,
GenesisAccounts: []GenesisAccount{ga},
HomeDir: homedir,
}
}
// NewApp initializes a new runtime.App. A Nop logger is set in runtime.App.
// appConfig defines the application configuration (f.e. app_config.go).
// extraOutputs defines the extra outputs to be assigned by the dependency injector (depinject).
func NewApp(
appConfig depinject.Config,
startupConfig StartupConfig,
extraOutputs ...interface{},
) (*App, error) {
// create the app with depinject
var (
storeBuilder = root.NewBuilder()
app *runtime.App[stateMachineTx]
appBuilder *runtime.AppBuilder[stateMachineTx]
txConfig client.TxConfig
txConfigOptions tx.ConfigOptions
cometService comet.Service = &cometServiceImpl{}
kvFactory corestore.KVStoreServiceFactory = func(actor []byte) corestore.KVStoreService {
return services.NewGenesisKVService(actor, &storeService{actor, stf.NewKVStoreService(actor)})
}
cdc codec.Codec
err error
)
if err := depinject.Inject(
depinject.Configs(
appConfig,
codec.DefaultProviders,
depinject.Supply(
&root.Config{
Home: startupConfig.HomeDir,
AppDBBackend: "goleveldb",
Options: root.DefaultStoreOptions(),
},
runtime.GlobalConfig{
"server": server.ConfigMap{
"minimum-gas-prices": "0stake",
},
},
services.NewGenesisHeaderService(stf.HeaderService{}),
cometService,
kvFactory,
&eventService{},
storeBuilder,
),
depinject.Invoke(
std.RegisterInterfaces,
),
),
append(extraOutputs, &appBuilder, &cdc, &txConfigOptions, &txConfig, &storeBuilder)...); err != nil {
return nil, fmt.Errorf("failed to inject dependencies: %w", err)
}
app, err = appBuilder.Build()
if err != nil {
return nil, fmt.Errorf("failed to build app: %w", err)
}
if err := app.LoadLatest(); err != nil {
return nil, fmt.Errorf("failed to load app: %w", err)
}
store := storeBuilder.Get()
if store == nil {
return nil, fmt.Errorf("failed to build store: %w", err)
}
err = store.SetInitialVersion(0)
if err != nil {
return nil, fmt.Errorf("failed to set initial version: %w", err)
}
integrationApp := &App{App: app, Store: store, txConfig: txConfig, lastHeight: 0}
if startupConfig.GenesisBehavior == Genesis_SKIP {
return integrationApp, nil
}
// create validator set
valSet, err := startupConfig.ValidatorSet()
if err != nil {
return nil, errors.New("failed to create validator set")
}
var (
balances []banktypes.Balance
genAccounts []authtypes.GenesisAccount
)
for _, ga := range startupConfig.GenesisAccounts {
genAccounts = append(genAccounts, ga.GenesisAccount)
balances = append(
balances,
banktypes.Balance{
Address: ga.GenesisAccount.GetAddress().String(),
Coins: ga.Coins,
},
)
}
genesisJSON, err := genesisStateWithValSet(
cdc,
app.DefaultGenesis(),
valSet,
genAccounts,
balances...)
if err != nil {
return nil, fmt.Errorf("failed to create genesis state: %w", err)
}
// init chain must be called to stop deliverState from being nil
genesisJSONBytes, err := cmtjson.MarshalIndent(genesisJSON, "", " ")
if err != nil {
return nil, fmt.Errorf(
"failed to marshal default genesis state: %w",
err,
)
}
ctx := context.WithValue(
context.Background(),
corecontext.CometParamsInitInfoKey,
&consensustypes.MsgUpdateParams{
Authority: "consensus",
Block: DefaultConsensusParams.Block,
Evidence: DefaultConsensusParams.Evidence,
Validator: DefaultConsensusParams.Validator,
Abci: DefaultConsensusParams.Abci,
Synchrony: DefaultConsensusParams.Synchrony,
Feature: DefaultConsensusParams.Feature,
},
)
emptyHash := sha256.Sum256(nil)
_, genesisState, err := app.InitGenesis(
ctx,
&server.BlockRequest[stateMachineTx]{
Height: 1,
Time: time.Now(),
Hash: emptyHash[:],
ChainId: "test-chain",
AppHash: emptyHash[:],
IsGenesis: true,
},
genesisJSONBytes,
&genesisTxCodec{txConfigOptions},
)
if err != nil {
return nil, fmt.Errorf("failed init genesis: %w", err)
}
if startupConfig.GenesisBehavior == Genesis_NOCOMMIT {
integrationApp.lastHeight = 0
return integrationApp, nil
}
_, err = integrationApp.Commit(genesisState)
if err != nil {
return nil, fmt.Errorf("failed to commit initial version: %w", err)
}
return integrationApp, nil
}
// App is a wrapper around runtime.App that provides additional testing utilities.
type App struct {
*runtime.App[stateMachineTx]
lastHeight uint64
Store store.RootStore
txConfig client.TxConfig
}
// Deliver delivers a block with the given transactions and returns the resulting state.
func (a *App) Deliver(
t *testing.T, ctx context.Context, txs []stateMachineTx,
) (*server.BlockResponse, corestore.WriterMap) {
t.Helper()
req := &server.BlockRequest[stateMachineTx]{
Height: a.lastHeight + 1,
Txs: txs,
Hash: make([]byte, 32),
AppHash: make([]byte, 32),
}
resp, state, err := a.DeliverBlock(ctx, req)
require.NoError(t, err)
a.lastHeight++
return resp, state
}
// StateLatestContext creates returns a new context from context.Background() with the latest state.
func (a *App) StateLatestContext(t *testing.T) context.Context {
t.Helper()
_, state, err := a.Store.StateLatest()
require.NoError(t, err)
writeableState := branch.DefaultNewWriterMap(state)
iCtx := &integrationContext{state: writeableState}
return context.WithValue(context.Background(), contextKey, iCtx)
}
// Commit commits the given state and returns the new state hash.
func (a *App) Commit(state corestore.WriterMap) ([]byte, error) {
changes, err := state.GetStateChanges()
if err != nil {
return nil, fmt.Errorf("failed to get state changes: %w", err)
}
cs := &corestore.Changeset{Version: a.lastHeight, Changes: changes}
return a.Store.Commit(cs)
}
// SignCheckDeliver signs and checks the given messages and delivers them.
func (a *App) SignCheckDeliver(
t *testing.T, ctx context.Context, msgs []sdk.Msg,
chainID string, accNums, accSeqs []uint64, privateKeys []cryptotypes.PrivKey,
txErrString string,
) server.TxResult {
t.Helper()
r := rand.New(rand.NewSource(time.Now().UnixNano()))
sigs := make([]signing.SignatureV2, len(privateKeys))
// create a random length memo
memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))
signMode, err := authsign.APISignModeToInternal(a.txConfig.SignModeHandler().DefaultMode())
require.NoError(t, err)
// 1st round: set SignatureV2 with empty signatures, to set correct
// signer infos.
for i, p := range privateKeys {
sigs[i] = signing.SignatureV2{
PubKey: p.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signMode,
},
Sequence: accSeqs[i],
}
}
txBuilder := a.txConfig.NewTxBuilder()
err = txBuilder.SetMsgs(msgs...)
require.NoError(t, err)
err = txBuilder.SetSignatures(sigs...)
require.NoError(t, err)
txBuilder.SetMemo(memo)
txBuilder.SetFeeAmount(sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)})
txBuilder.SetGasLimit(DefaultGenTxGas)
// 2nd round: once all signer infos are set, every signer can sign.
for i, p := range privateKeys {
signerData := authsign.SignerData{
Address: sdk.AccAddress(p.PubKey().Address()).String(),
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
PubKey: p.PubKey(),
}
signBytes, err := authsign.GetSignBytesAdapter(
ctx, a.txConfig.SignModeHandler(), signMode, signerData,
// todo why fetch twice?
txBuilder.GetTx())
require.NoError(t, err)
sig, err := p.Sign(signBytes)
require.NoError(t, err)
sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
}
err = txBuilder.SetSignatures(sigs...)
require.NoError(t, err)
builtTx := txBuilder.GetTx()
blockResponse, blockState := a.Deliver(t, ctx, []stateMachineTx{builtTx})
require.Equal(t, 1, len(blockResponse.TxResults))
txResult := blockResponse.TxResults[0]
if txErrString != "" {
require.ErrorContains(t, txResult.Error, txErrString)
} else {
require.NoError(t, txResult.Error)
}
_, err = a.Commit(blockState)
require.NoError(t, err)
return txResult
}
// CheckBalance checks the balance of the given address.
func (a *App) CheckBalance(
t *testing.T, ctx context.Context, addr sdk.AccAddress, expected sdk.Coins, keeper bankkeeper.Keeper,
) {
t.Helper()
balances := keeper.GetAllBalances(ctx, addr)
require.Equal(t, expected, balances)
}
func (a *App) Close() error {
return a.Store.Close()
}

View File

@ -1,469 +0,0 @@
package bank
import (
"testing"
"github.com/stretchr/testify/require"
secp256k1_internal "gitlab.com/yawning/secp256k1-voi"
"gitlab.com/yawning/secp256k1-voi/secec"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
sdkmath "cosmossdk.io/math"
_ "cosmossdk.io/x/accounts"
_ "cosmossdk.io/x/bank"
bankkeeper "cosmossdk.io/x/bank/keeper"
"cosmossdk.io/x/bank/testutil"
"cosmossdk.io/x/bank/types"
_ "cosmossdk.io/x/consensus"
_ "cosmossdk.io/x/distribution"
distrkeeper "cosmossdk.io/x/distribution/keeper"
_ "cosmossdk.io/x/gov"
govv1 "cosmossdk.io/x/gov/types/v1"
_ "cosmossdk.io/x/protocolpool"
_ "cosmossdk.io/x/staking"
stakingtypes "cosmossdk.io/x/staking/types"
"github.com/cosmos/cosmos-sdk/client"
cdctestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
sdk "github.com/cosmos/cosmos-sdk/types"
_ "github.com/cosmos/cosmos-sdk/x/auth"
_ "github.com/cosmos/cosmos-sdk/x/auth/tx/config"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
var (
stablePrivateKey, _ = secec.NewPrivateKeyFromScalar(secp256k1_internal.NewScalarFromUint64(100))
priv1 = &secp256k1.PrivKey{Key: stablePrivateKey.Bytes()}
addr1 = sdk.AccAddress(priv1.PubKey().Address())
priv2 = secp256k1.GenPrivKey()
addr2 = sdk.AccAddress(priv2.PubKey().Address())
addr3 = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
coins = sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}
halfCoins = sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}
moduleAccAddr = authtypes.NewModuleAddress(stakingtypes.BondedPoolName)
)
type suite struct {
BankKeeper bankkeeper.Keeper
AccountKeeper types.AccountKeeper
DistributionKeeper distrkeeper.Keeper
App *integration.App
TxConfig client.TxConfig
}
type expectedBalance struct {
addr sdk.AccAddress
coins sdk.Coins
}
type appTestCase struct {
desc string
msgs []sdk.Msg
accNums []uint64
accSeqs []uint64
privKeys []cryptotypes.PrivKey
expectedBalances []expectedBalance
expInError []string
}
func createTestSuite(t *testing.T, genesisAccounts []authtypes.GenesisAccount) suite {
t.Helper()
res := suite{}
moduleConfigs := []configurator.ModuleOption{
configurator.AccountsModule(),
configurator.AuthModule(),
configurator.StakingModule(),
configurator.TxModule(),
configurator.ValidateModule(),
configurator.ConsensusModule(),
configurator.BankModule(),
configurator.GovModule(),
configurator.DistributionModule(),
configurator.ProtocolPoolModule(),
}
var err error
startupCfg := integration.DefaultStartUpConfig(t)
var genAccounts []integration.GenesisAccount
for _, acc := range genesisAccounts {
genAccounts = append(genAccounts, integration.GenesisAccount{GenesisAccount: acc})
}
startupCfg.GenesisAccounts = genAccounts
res.App, err = integration.NewApp(
depinject.Configs(configurator.NewAppV2Config(moduleConfigs...), depinject.Supply(log.NewNopLogger())),
startupCfg,
&res.BankKeeper, &res.AccountKeeper, &res.DistributionKeeper, &res.TxConfig)
require.NoError(t, err)
return res
}
func TestSendNotEnoughBalance(t *testing.T) {
acc := &authtypes.BaseAccount{
Address: addr1.String(),
}
genAccs := []authtypes.GenesisAccount{acc}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
err := testutil.FundAccount(
ctx, s.BankKeeper, addr1,
sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67)))
require.NoError(t, err)
res1 := s.AccountKeeper.GetAccount(ctx, addr1)
require.NotNil(t, res1)
require.Equal(t, acc, res1.(*authtypes.BaseAccount))
origAccNum := res1.GetAccountNumber()
origSeq := res1.GetSequence()
addr1Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr1)
require.NoError(t, err)
addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2)
require.NoError(t, err)
sendMsg := types.NewMsgSend(addr1Str, addr2Str, sdk.Coins{sdk.NewInt64Coin("foocoin", 100)})
// TODO how to auto-advance height with app v2 interface?
s.App.SignCheckDeliver(
t, ctx, []sdk.Msg{sendMsg}, "", []uint64{origAccNum}, []uint64{origSeq},
[]cryptotypes.PrivKey{priv1},
"spendable balance 67foocoin is smaller than 100foocoin",
)
s.App.CheckBalance(t, ctx, addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 67)}, s.BankKeeper)
res2 := s.AccountKeeper.GetAccount(ctx, addr1)
require.NotNil(t, res2)
require.Equal(t, origAccNum, res2.GetAccountNumber())
require.Equal(t, origSeq+1, res2.GetSequence())
}
func TestMsgMultiSendWithAccounts(t *testing.T) {
addr1Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1)
require.NoError(t, err)
acc := &authtypes.BaseAccount{
Address: addr1Str,
}
addr2Str, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr2)
require.NoError(t, err)
moduleStrAddr, err := cdctestutil.CodecOptions{}.GetAddressCodec().BytesToString(moduleAccAddr)
require.NoError(t, err)
genAccs := []authtypes.GenesisAccount{acc}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 67))))
_, state := s.App.Deliver(t, ctx, nil)
_, err = s.App.Commit(state)
require.NoError(t, err)
res1 := s.AccountKeeper.GetAccount(ctx, addr1)
require.NotNil(t, res1)
require.Equal(t, acc, res1.(*authtypes.BaseAccount))
testCases := []appTestCase{
{
desc: "make a valid tx",
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins)},
Outputs: []types.Output{types.NewOutput(addr2Str, coins)},
}},
accNums: []uint64{0},
accSeqs: []uint64{0},
privKeys: []cryptotypes.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
},
},
{
desc: "wrong accNum should pass Simulate, but not Deliver",
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins)},
Outputs: []types.Output{types.NewOutput(addr2Str, coins)},
}},
accNums: []uint64{1}, // wrong account number
accSeqs: []uint64{1},
expInError: []string{"signature verification failed; please verify account number"},
privKeys: []cryptotypes.PrivKey{priv1},
},
{
desc: "wrong accSeq should not pass Simulate",
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins)},
Outputs: []types.Output{
types.NewOutput(moduleStrAddr, coins),
},
}},
accNums: []uint64{0},
accSeqs: []uint64{0}, // wrong account sequence
expInError: []string{"account sequence mismatch"},
privKeys: []cryptotypes.PrivKey{priv1},
},
{
desc: "multiple inputs not allowed",
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins), types.NewInput(addr2Str, coins)},
Outputs: []types.Output{},
}},
accNums: []uint64{0},
accSeqs: []uint64{0},
expInError: []string{"invalid number of signatures"},
privKeys: []cryptotypes.PrivKey{priv1},
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
var errString string
if len(tc.expInError) > 0 {
errString = tc.expInError[0]
}
s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, errString)
for _, eb := range tc.expectedBalances {
s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper)
}
})
}
}
func TestMsgMultiSendMultipleOut(t *testing.T) {
ac := cdctestutil.CodecOptions{}.GetAddressCodec()
addr1Str, err := ac.BytesToString(addr1)
require.NoError(t, err)
acc1 := &authtypes.BaseAccount{
Address: addr1Str,
}
addr2Str, err := ac.BytesToString(addr2)
require.NoError(t, err)
acc2 := &authtypes.BaseAccount{
Address: addr2Str,
}
addr3Str, err := ac.BytesToString(addr3)
require.NoError(t, err)
genAccs := []authtypes.GenesisAccount{acc1, acc2}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr2, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
_, state := s.App.Deliver(t, ctx, nil)
_, err = s.App.Commit(state)
require.NoError(t, err)
testCases := []appTestCase{
{
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins)},
Outputs: []types.Output{
types.NewOutput(addr2Str, halfCoins),
types.NewOutput(addr3Str, halfCoins),
},
}},
accNums: []uint64{0},
accSeqs: []uint64{0},
privKeys: []cryptotypes.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}},
{addr3, sdk.Coins{sdk.NewInt64Coin("foocoin", 5)}},
},
},
}
for _, tc := range testCases {
s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, "")
for _, eb := range tc.expectedBalances {
s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper)
}
}
}
func TestMsgMultiSendDependent(t *testing.T) {
ac := cdctestutil.CodecOptions{}.GetAddressCodec()
addr1Str, err := ac.BytesToString(addr1)
require.NoError(t, err)
addr2Str, err := ac.BytesToString(addr2)
require.NoError(t, err)
acc1 := authtypes.NewBaseAccountWithAddress(addr1)
acc2 := authtypes.NewBaseAccountWithAddress(addr2)
err = acc2.SetAccountNumber(1)
require.NoError(t, err)
genAccs := []authtypes.GenesisAccount{acc1, acc2}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
_, state := s.App.Deliver(t, ctx, nil)
_, err = s.App.Commit(state)
require.NoError(t, err)
testCases := []appTestCase{
{
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr1Str, coins)},
Outputs: []types.Output{types.NewOutput(addr2Str, coins)},
}},
accNums: []uint64{0},
accSeqs: []uint64{0},
privKeys: []cryptotypes.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
},
},
{
msgs: []sdk.Msg{&types.MsgMultiSend{
Inputs: []types.Input{types.NewInput(addr2Str, coins)},
Outputs: []types.Output{
types.NewOutput(addr1Str, coins),
},
}},
accNums: []uint64{1},
accSeqs: []uint64{0},
privKeys: []cryptotypes.PrivKey{priv2},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}},
},
},
}
for _, tc := range testCases {
s.App.SignCheckDeliver(t, ctx, tc.msgs, "", tc.accNums, tc.accSeqs, tc.privKeys, "")
for _, eb := range tc.expectedBalances {
s.App.CheckBalance(t, ctx, eb.addr, eb.coins, s.BankKeeper)
}
}
}
func TestMsgSetSendEnabled(t *testing.T) {
acc1 := authtypes.NewBaseAccountWithAddress(addr1)
genAccs := []authtypes.GenesisAccount{acc1}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 101))))
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("stake", 100000))))
addr1Str := addr1.String()
govAddr := s.BankKeeper.GetAuthority()
goodGovProp, err := govv1.NewMsgSubmitProposal(
[]sdk.Msg{
types.NewMsgSetSendEnabled(govAddr, nil, nil),
},
sdk.Coins{{Denom: "stake", Amount: sdkmath.NewInt(100000)}},
addr1Str,
"set default send enabled to true",
"Change send enabled",
"Modify send enabled and set to true",
govv1.ProposalType_PROPOSAL_TYPE_STANDARD,
)
require.NoError(t, err, "making goodGovProp")
testCases := []appTestCase{
{
desc: "wrong authority",
msgs: []sdk.Msg{
types.NewMsgSetSendEnabled(addr1Str, nil, nil),
},
accSeqs: []uint64{0},
expInError: []string{
"invalid authority",
"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn",
addr1Str,
"expected authority account as only signer for proposal message",
},
},
{
desc: "right authority wrong signer",
msgs: []sdk.Msg{
types.NewMsgSetSendEnabled(govAddr, nil, nil),
},
accSeqs: []uint64{1}, // wrong signer, so this sequence doesn't actually get used.
expInError: []string{
"cannot be claimed by public key with address",
govAddr,
},
},
{
desc: "submitted good as gov prop",
msgs: []sdk.Msg{
goodGovProp,
},
accSeqs: []uint64{1},
expInError: nil,
},
}
for _, tc := range testCases {
t.Run(tc.desc, func(tt *testing.T) {
var errString string
if len(tc.expInError) > 0 {
errString = tc.expInError[0]
}
txResult := s.App.SignCheckDeliver(
tt, ctx, tc.msgs, "", []uint64{0}, tc.accSeqs, []cryptotypes.PrivKey{priv1}, errString)
if len(tc.expInError) > 0 {
require.Error(tt, txResult.Error)
for _, exp := range tc.expInError {
require.ErrorContains(tt, txResult.Error, exp)
}
} else {
require.NoError(tt, txResult.Error)
}
})
}
}
// TestSendToNonExistingAccount tests sending coins to an account that does not exist, and this account
// must not be created.
func TestSendToNonExistingAccount(t *testing.T) {
acc1 := authtypes.NewBaseAccountWithAddress(addr1)
genAccs := []authtypes.GenesisAccount{acc1}
s := createTestSuite(t, genAccs)
ctx := s.App.StateLatestContext(t)
require.NoError(t, testutil.FundAccount(ctx, s.BankKeeper, addr1, sdk.NewCoins(sdk.NewInt64Coin("foocoin", 42))))
_, state := s.App.Deliver(t, ctx, nil)
_, err := s.App.Commit(state)
require.NoError(t, err)
addr2Str, err := s.AccountKeeper.AddressCodec().BytesToString(addr2)
require.NoError(t, err)
sendMsg := types.NewMsgSend(addr1.String(), addr2Str, coins)
res := s.App.SignCheckDeliver(t, ctx, []sdk.Msg{sendMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv1}, "")
require.NoError(t, res.Error)
// Check that the account was not created
acc2 := s.AccountKeeper.GetAccount(ctx, addr2)
require.Nil(t, acc2)
// But it does have a balance
s.App.CheckBalance(t, ctx, addr2, coins, s.BankKeeper)
// Now we send coins back and the account should be created
sendMsg = types.NewMsgSend(addr2Str, addr1.String(), coins)
res = s.App.SignCheckDeliver(t, ctx, []sdk.Msg{sendMsg}, "", []uint64{0}, []uint64{0}, []cryptotypes.PrivKey{priv2}, "")
require.NoError(t, res.Error)
// Balance has been reduced
s.App.CheckBalance(t, ctx, addr2, sdk.NewCoins(), s.BankKeeper)
// Check that the account was created
acc2 = s.AccountKeeper.GetAccount(ctx, addr2)
require.NotNil(t, acc2, "account should have been created %s", addr2.String())
}

View File

@ -1,570 +0,0 @@
package bank
import (
"context"
"fmt"
"testing"
"github.com/cosmos/gogoproto/proto"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"pgregory.net/rapid"
"cosmossdk.io/core/gas"
"cosmossdk.io/depinject"
"cosmossdk.io/log"
"cosmossdk.io/math"
bankkeeper "cosmossdk.io/x/bank/keeper"
banktestutil "cosmossdk.io/x/bank/testutil"
banktypes "cosmossdk.io/x/bank/types"
minttypes "cosmossdk.io/x/mint/types"
codectestutil "github.com/cosmos/cosmos-sdk/codec/testutil"
"github.com/cosmos/cosmos-sdk/tests/integration/v2"
"github.com/cosmos/cosmos-sdk/testutil/configurator"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
)
var (
denomRegex = `[a-zA-Z][a-zA-Z0-9/:._-]{2,127}`
coin1 = sdk.NewCoin("denom", math.NewInt(10))
metadataAtom = banktypes.Metadata{
Description: "The native staking token of the Cosmos Hub.",
DenomUnits: []*banktypes.DenomUnit{
{
Denom: "uatom",
Exponent: 0,
Aliases: []string{"microatom"},
},
{
Denom: "atom",
Exponent: 6,
Aliases: []string{"ATOM"},
},
},
Base: "uatom",
Display: "atom",
}
)
type deterministicFixture struct {
*testing.T
ctx context.Context
app *integration.App
bankKeeper bankkeeper.Keeper
}
func queryFnFactory[RequestT, ResponseT proto.Message](
f *deterministicFixture,
) func(RequestT) (ResponseT, error) {
return func(req RequestT) (ResponseT, error) {
var emptyResponse ResponseT
res, err := f.app.Query(f.ctx, 0, req)
if err != nil {
return emptyResponse, err
}
castedRes, ok := res.(ResponseT)
if !ok {
return emptyResponse, fmt.Errorf("unexpected response type: %T", res)
}
return castedRes, nil
}
}
func fundAccount(f *deterministicFixture, addr sdk.AccAddress, coin ...sdk.Coin) {
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin...))
require.NoError(f.T, err)
}
func getCoin(rt *rapid.T) sdk.Coin {
return sdk.NewCoin(
rapid.StringMatching(denomRegex).Draw(rt, "denom"),
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")),
)
}
func initDeterministicFixture(t *testing.T) *deterministicFixture {
t.Helper()
ctrl := gomock.NewController(t)
acctsModKeeper := authtestutil.NewMockAccountsModKeeper(ctrl)
accNum := uint64(0)
acctsModKeeper.EXPECT().NextAccountNumber(gomock.Any()).AnyTimes().DoAndReturn(func(ctx context.Context) (
uint64, error,
) {
currentNum := accNum
accNum++
return currentNum, nil
})
startupConfig := integration.DefaultStartUpConfig(t)
startupConfig.GenesisBehavior = integration.Genesis_SKIP
diConfig := configurator.NewAppV2Config(
configurator.TxModule(),
configurator.AuthModule(),
configurator.BankModule(),
)
var bankKeeper bankkeeper.Keeper
diConfig = depinject.Configs(diConfig, depinject.Supply(acctsModKeeper, log.NewNopLogger()))
app, err := integration.NewApp(diConfig, startupConfig, &bankKeeper)
require.NoError(t, err)
require.NotNil(t, app)
return &deterministicFixture{app: app, bankKeeper: bankKeeper, T: t}
}
func assertNonZeroGas(t *testing.T, gasUsed gas.Gas) {
t.Helper()
require.NotZero(t, gasUsed)
}
func TestQueryBalance(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryBalanceRequest, *banktypes.QueryBalanceResponse](f)
assertBalance := func(coin sdk.Coin) func(t *testing.T, res *banktypes.QueryBalanceResponse) {
return func(t *testing.T, res *banktypes.QueryBalanceResponse) {
t.Helper()
require.Equal(t, coin.Denom, res.Balance.Denom)
require.Truef(t, coin.Amount.Equal(res.Balance.Amount),
"expected %s, got %s", coin.Amount, res.Balance.Amount)
}
}
rapid.Check(t, func(rt *rapid.T) {
addr := testdata.AddressGenerator(rt).Draw(rt, "address")
coin := getCoin(rt)
fundAccount(f, addr, coin)
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr)
require.NoError(t, err)
req := banktypes.NewQueryBalanceRequest(addrStr, coin.GetDenom())
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, assertBalance(coin))
})
fundAccount(f, addr1, coin1)
addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1)
require.NoError(t, err)
req := banktypes.NewQueryBalanceRequest(addr1Str, coin1.GetDenom())
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, assertBalance(coin1))
}
func TestQueryAllBalances(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
addressCodec := codectestutil.CodecOptions{}.GetAddressCodec()
queryFn := queryFnFactory[*banktypes.QueryAllBalancesRequest, *banktypes.QueryAllBalancesResponse](f)
rapid.Check(t, func(rt *rapid.T) {
addr := testdata.AddressGenerator(rt).Draw(rt, "address")
numCoins := rapid.IntRange(1, 10).Draw(rt, "num-count")
coins := make(sdk.Coins, 0, numCoins)
addrStr, err := addressCodec.BytesToString(addr)
require.NoError(t, err)
for i := 0; i < numCoins; i++ {
coin := getCoin(rt)
if exists, _ := coins.Find(coin.Denom); exists {
t.Skip("duplicate denom")
}
// NewCoins sorts the denoms
coins = sdk.NewCoins(append(coins, coin)...)
}
fundAccount(f, addr, coins...)
req := banktypes.NewQueryAllBalancesRequest(
addrStr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false)
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
coins := sdk.NewCoins(
sdk.NewCoin("stake", math.NewInt(10)),
sdk.NewCoin("denom", math.NewInt(100)),
)
fundAccount(f, addr1, coins...)
addr1Str, err := addressCodec.BytesToString(addr1)
require.NoError(t, err)
req := banktypes.NewQueryAllBalancesRequest(addr1Str, nil, false)
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestQuerySpendableBalances(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QuerySpendableBalancesRequest, *banktypes.QuerySpendableBalancesResponse](f)
rapid.Check(t, func(rt *rapid.T) {
addr := testdata.AddressGenerator(rt).Draw(rt, "address")
addrStr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr)
require.NoError(t, err)
// Denoms must be unique, otherwise sdk.NewCoins will panic.
denoms := rapid.SliceOfNDistinct(rapid.StringMatching(denomRegex), 1, 10, rapid.ID[string]).Draw(rt, "denoms")
coins := make(sdk.Coins, 0, len(denoms))
for _, denom := range denoms {
coin := sdk.NewCoin(
denom,
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")),
)
// NewCoins sorts the denoms
coins = sdk.NewCoins(append(coins, coin)...)
}
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, coins)
require.NoError(t, err)
req := banktypes.NewQuerySpendableBalancesRequest(addrStr, testdata.PaginationGenerator(rt, uint64(len(denoms))).Draw(rt, "pagination"))
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
coins := sdk.NewCoins(
sdk.NewCoin("stake", math.NewInt(10)),
sdk.NewCoin("denom", math.NewInt(100)),
)
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr1, coins)
require.NoError(t, err)
addr1Str, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(addr1)
require.NoError(t, err)
req := banktypes.NewQuerySpendableBalancesRequest(addr1Str, nil)
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestQueryTotalSupply(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryTotalSupplyRequest, *banktypes.QueryTotalSupplyResponse](f)
res, err := queryFn(&banktypes.QueryTotalSupplyRequest{})
require.NoError(t, err)
initialSupply := res.GetSupply()
rapid.Check(t, func(rt *rapid.T) {
numCoins := rapid.IntRange(1, 3).Draw(rt, "num-count")
coins := make(sdk.Coins, 0, numCoins)
for i := 0; i < numCoins; i++ {
coin := sdk.NewCoin(
rapid.StringMatching(denomRegex).Draw(rt, "denom"),
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")),
)
coins = coins.Add(coin)
}
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins))
initialSupply = initialSupply.Add(coins...)
req := &banktypes.QueryTotalSupplyRequest{
Pagination: testdata.PaginationGenerator(rt, uint64(len(initialSupply))).Draw(rt, "pagination"),
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
f = initDeterministicFixture(t) // reset
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory = integration.GasMeterFactory(f.ctx)
queryFn = queryFnFactory[*banktypes.QueryTotalSupplyRequest, *banktypes.QueryTotalSupplyResponse](f)
coins := sdk.NewCoins(
sdk.NewCoin("foo", math.NewInt(10)),
sdk.NewCoin("bar", math.NewInt(100)),
)
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, coins))
req := &banktypes.QueryTotalSupplyRequest{}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestQueryTotalSupplyOf(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QuerySupplyOfRequest, *banktypes.QuerySupplyOfResponse](f)
rapid.Check(t, func(rt *rapid.T) {
coin := sdk.NewCoin(
rapid.StringMatching(denomRegex).Draw(rt, "denom"),
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")),
)
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin)))
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
coin := sdk.NewCoin("bar", math.NewInt(100))
require.NoError(t, f.bankKeeper.MintCoins(f.ctx, minttypes.ModuleName, sdk.NewCoins(coin)))
req := &banktypes.QuerySupplyOfRequest{Denom: coin.GetDenom()}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestQueryParams(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryParamsRequest, *banktypes.QueryParamsResponse](f)
rapid.Check(t, func(rt *rapid.T) {
enabledStatus := banktypes.SendEnabled{
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"),
Enabled: rapid.Bool().Draw(rt, "status"),
}
params := banktypes.Params{
SendEnabled: []*banktypes.SendEnabled{&enabledStatus},
DefaultSendEnabled: rapid.Bool().Draw(rt, "send"),
}
err := f.bankKeeper.SetParams(f.ctx, params)
require.NoError(t, err)
req := &banktypes.QueryParamsRequest{}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
enabledStatus := banktypes.SendEnabled{
Denom: "denom",
Enabled: true,
}
params := banktypes.Params{
SendEnabled: []*banktypes.SendEnabled{&enabledStatus},
DefaultSendEnabled: false,
}
err := f.bankKeeper.SetParams(f.ctx, params)
require.NoError(t, err)
req := &banktypes.QueryParamsRequest{}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func createAndReturnMetadatas(t *rapid.T, count int) []banktypes.Metadata {
denomsMetadata := make([]banktypes.Metadata, 0, count)
for i := 0; i < count; i++ {
denom := rapid.StringMatching(denomRegex).Draw(t, "denom")
aliases := rapid.SliceOf(rapid.String()).Draw(t, "aliases")
// In the GRPC server code, empty arrays are returned as nil
if len(aliases) == 0 {
aliases = nil
}
metadata := banktypes.Metadata{
Description: rapid.StringN(1, 100, 100).Draw(t, "desc"),
DenomUnits: []*banktypes.DenomUnit{
{
Denom: denom,
Exponent: rapid.Uint32().Draw(t, "exponent"),
Aliases: aliases,
},
},
Base: denom,
Display: denom,
Name: rapid.String().Draw(t, "name"),
Symbol: rapid.String().Draw(t, "symbol"),
URI: rapid.String().Draw(t, "uri"),
URIHash: rapid.String().Draw(t, "uri-hash"),
}
denomsMetadata = append(denomsMetadata, metadata)
}
return denomsMetadata
}
func TestDenomsMetadata(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryDenomsMetadataRequest, *banktypes.QueryDenomsMetadataResponse](f)
rapid.Check(t, func(rt *rapid.T) {
count := rapid.IntRange(1, 3).Draw(rt, "count")
denomsMetadata := createAndReturnMetadatas(rt, count)
require.True(t, len(denomsMetadata) == count)
for i := 0; i < count; i++ {
f.bankKeeper.SetDenomMetaData(f.ctx, denomsMetadata[i])
}
req := &banktypes.QueryDenomsMetadataRequest{
Pagination: testdata.PaginationGenerator(rt, uint64(count)).Draw(rt, "pagination"),
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
require.NoError(t, f.app.Close())
f = initDeterministicFixture(t) // reset
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory = integration.GasMeterFactory(f.ctx)
queryFn = queryFnFactory[*banktypes.QueryDenomsMetadataRequest, *banktypes.QueryDenomsMetadataResponse](f)
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom)
req := &banktypes.QueryDenomsMetadataRequest{}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestDenomMetadata(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryDenomMetadataRequest, *banktypes.QueryDenomMetadataResponse](f)
rapid.Check(t, func(rt *rapid.T) {
denomMetadata := createAndReturnMetadatas(rt, 1)
require.True(t, len(denomMetadata) == 1)
f.bankKeeper.SetDenomMetaData(f.ctx, denomMetadata[0])
req := &banktypes.QueryDenomMetadataRequest{
Denom: denomMetadata[0].Base,
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
f.bankKeeper.SetDenomMetaData(f.ctx, metadataAtom)
req := &banktypes.QueryDenomMetadataRequest{
Denom: metadataAtom.Base,
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestSendEnabled(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QuerySendEnabledRequest, *banktypes.QuerySendEnabledResponse](f)
allDenoms := []string{}
rapid.Check(t, func(rt *rapid.T) {
count := rapid.IntRange(1, 10).Draw(rt, "count")
denoms := make([]string, 0, count)
for i := 0; i < count; i++ {
coin := banktypes.SendEnabled{
Denom: rapid.StringMatching(denomRegex).Draw(rt, "denom"),
Enabled: rapid.Bool().Draw(rt, "enabled-status"),
}
f.bankKeeper.SetSendEnabled(f.ctx, coin.Denom, coin.Enabled)
denoms = append(denoms, coin.Denom)
}
allDenoms = append(allDenoms, denoms...)
req := &banktypes.QuerySendEnabledRequest{
Denoms: denoms,
// Pagination is only taken into account when `denoms` is an empty array
Pagination: testdata.PaginationGenerator(rt, uint64(len(allDenoms))).Draw(rt, "pagination"),
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
coin1 := banktypes.SendEnabled{
Denom: "falsecoin",
Enabled: false,
}
coin2 := banktypes.SendEnabled{
Denom: "truecoin",
Enabled: true,
}
f.bankKeeper.SetSendEnabled(f.ctx, coin1.Denom, false)
f.bankKeeper.SetSendEnabled(f.ctx, coin2.Denom, true)
req := &banktypes.QuerySendEnabledRequest{
Denoms: []string{coin1.GetDenom(), coin2.GetDenom()},
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}
func TestDenomOwners(t *testing.T) {
t.Parallel()
f := initDeterministicFixture(t)
f.ctx = f.app.StateLatestContext(t)
gasMeterFactory := integration.GasMeterFactory(f.ctx)
queryFn := queryFnFactory[*banktypes.QueryDenomOwnersRequest, *banktypes.QueryDenomOwnersResponse](f)
rapid.Check(t, func(rt *rapid.T) {
denom := rapid.StringMatching(denomRegex).Draw(rt, "denom")
numAddr := rapid.IntRange(1, 10).Draw(rt, "number-address")
for i := 0; i < numAddr; i++ {
addr := testdata.AddressGenerator(rt).Draw(rt, "address")
coin := sdk.NewCoin(
denom,
math.NewInt(rapid.Int64Min(1).Draw(rt, "amount")),
)
err := banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin))
require.NoError(t, err)
}
req := &banktypes.QueryDenomOwnersRequest{
Denom: denom,
Pagination: testdata.PaginationGenerator(rt, uint64(numAddr)).Draw(rt, "pagination"),
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
})
denomOwners := []*banktypes.DenomOwner{
{
Address: "cosmos1qg65a9q6k2sqq7l3ycp428sqqpmqcucgzze299",
Balance: coin1,
},
{
Address: "cosmos1qglnsqgpq48l7qqzgs8qdshr6fh3gqq9ej3qut",
Balance: coin1,
},
}
for i := 0; i < len(denomOwners); i++ {
addr, err := sdk.AccAddressFromBech32(denomOwners[i].Address)
require.NoError(t, err)
err = banktestutil.FundAccount(f.ctx, f.bankKeeper, addr, sdk.NewCoins(coin1))
require.NoError(t, err)
}
req := &banktypes.QueryDenomOwnersRequest{
Denom: coin1.GetDenom(),
}
testdata.DeterministicIterationsV2(t, req, gasMeterFactory, queryFn, assertNonZeroGas, nil)
}

View File

@ -1,182 +0,0 @@
package integration
import (
"encoding/json"
"errors"
"fmt"
"time"
cmttypes "github.com/cometbft/cometbft/types"
sdkmath "cosmossdk.io/math"
banktypes "cosmossdk.io/x/bank/types"
stakingtypes "cosmossdk.io/x/staking/types"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/testutil/mock"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// genesisStateWithValSet returns a new genesis state with the validator set
func genesisStateWithValSet(
codec codec.Codec,
genesisState map[string]json.RawMessage,
valSet *cmttypes.ValidatorSet,
genAccs []authtypes.GenesisAccount,
balances ...banktypes.Balance,
) (map[string]json.RawMessage, error) {
if len(genAccs) == 0 {
return nil, errors.New("no genesis accounts provided")
}
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = codec.MustMarshalJSON(authGenesis)
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
bondAmt := sdk.DefaultPowerReduction
for _, val := range valSet.Validators {
pk, err := cryptocodec.FromCmtPubKeyInterface(val.PubKey)
if err != nil {
return nil, fmt.Errorf("failed to convert pubkey: %w", err)
}
pkAny, err := codectypes.NewAnyWithValue(pk)
if err != nil {
return nil, fmt.Errorf("failed to create new any: %w", err)
}
validator := stakingtypes.Validator{
OperatorAddress: sdk.ValAddress(val.Address).String(),
ConsensusPubkey: pkAny,
Jailed: false,
Status: stakingtypes.Bonded,
Tokens: bondAmt,
DelegatorShares: sdkmath.LegacyOneDec(),
Description: stakingtypes.Description{},
UnbondingHeight: int64(0),
UnbondingTime: time.Unix(0, 0).UTC(),
Commission: stakingtypes.NewCommission(
sdkmath.LegacyZeroDec(),
sdkmath.LegacyZeroDec(),
sdkmath.LegacyZeroDec(),
),
MinSelfDelegation: sdkmath.ZeroInt(),
}
validators = append(validators, validator)
delegations = append(
delegations,
stakingtypes.NewDelegation(
genAccs[0].GetAddress().String(),
sdk.ValAddress(val.Address).String(),
sdkmath.LegacyOneDec(),
),
)
}
// set validators and delegations
stakingGenesis := stakingtypes.NewGenesisState(
stakingtypes.DefaultParams(),
validators,
delegations,
)
genesisState[stakingtypes.ModuleName] = codec.MustMarshalJSON(
stakingGenesis,
)
totalSupply := sdk.NewCoins()
for _, b := range balances {
// add genesis acc tokens to total supply
totalSupply = totalSupply.Add(b.Coins...)
}
for range delegations {
// add delegated tokens to total supply
totalSupply = totalSupply.Add(
sdk.NewCoin(sdk.DefaultBondDenom, bondAmt),
)
}
// add bonded amount to bonded pool module account
balances = append(balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).
String(),
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
})
// update total supply
bankGenesis := banktypes.NewGenesisState(
banktypes.DefaultGenesisState().Params,
balances,
totalSupply,
[]banktypes.Metadata{},
[]banktypes.SendEnabled{},
)
genesisState[banktypes.ModuleName] = codec.MustMarshalJSON(bankGenesis)
return genesisState, nil
}
// CreateRandomValidatorSet creates a validator set with one random validator
func CreateRandomValidatorSet() (*cmttypes.ValidatorSet, error) {
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
if err != nil {
return nil, fmt.Errorf("failed to get pub key: %w", err)
}
// create validator set with single validator
validator := cmttypes.NewValidator(pubKey, 1)
return cmttypes.NewValidatorSet([]*cmttypes.Validator{validator}), nil
}
type GenesisAccount struct {
authtypes.GenesisAccount
Coins sdk.Coins
}
type genesisTxCodec struct {
tx.ConfigOptions
}
// Decode implements transaction.Codec.
func (t *genesisTxCodec) Decode(bz []byte) (stateMachineTx, error) {
var out stateMachineTx
tx, err := t.ProtoDecoder(bz)
if err != nil {
return out, err
}
var ok bool
out, ok = tx.(stateMachineTx)
if !ok {
return out, errors.New("unexpected Tx type")
}
return out, nil
}
// DecodeJSON implements transaction.Codec.
func (t *genesisTxCodec) DecodeJSON(bz []byte) (stateMachineTx, error) {
var out stateMachineTx
tx, err := t.JSONDecoder(bz)
if err != nil {
return out, err
}
var ok bool
out, ok = tx.(stateMachineTx)
if !ok {
return out, errors.New("unexpected Tx type")
}
return out, nil
}

View File

@ -1,119 +0,0 @@
package integration
import (
"context"
"fmt"
"cosmossdk.io/core/comet"
"cosmossdk.io/core/event"
"cosmossdk.io/core/gas"
"cosmossdk.io/core/server"
corestore "cosmossdk.io/core/store"
"cosmossdk.io/core/transaction"
stfgas "cosmossdk.io/server/v2/stf/gas"
)
func (c cometServiceImpl) CometInfo(context.Context) comet.Info {
return comet.Info{}
}
// Services
var _ server.DynamicConfig = &dynamicConfigImpl{}
type dynamicConfigImpl struct {
homeDir string
}
func (d *dynamicConfigImpl) Get(key string) any {
return d.GetString(key)
}
func (d *dynamicConfigImpl) GetString(key string) string {
switch key {
case "home":
return d.homeDir
case "store.app-db-backend":
return "goleveldb"
case "server.minimum-gas-prices":
return "0stake"
default:
panic(fmt.Sprintf("unknown key: %s", key))
}
}
func (d *dynamicConfigImpl) UnmarshalSub(string, any) (bool, error) {
return false, nil
}
var _ comet.Service = &cometServiceImpl{}
type cometServiceImpl struct{}
type storeService struct {
actor []byte
executionService corestore.KVStoreService
}
type contextKeyType struct{}
var contextKey = contextKeyType{}
type integrationContext struct {
state corestore.WriterMap
gasMeter gas.Meter
}
func GasMeterFromContext(ctx context.Context) gas.Meter {
iCtx, ok := ctx.Value(contextKey).(*integrationContext)
if !ok {
return nil
}
return iCtx.gasMeter
}
func GasMeterFactory(ctx context.Context) func() gas.Meter {
return func() gas.Meter {
return GasMeterFromContext(ctx)
}
}
func (s storeService) OpenKVStore(ctx context.Context) corestore.KVStore {
const gasLimit = 100_000
iCtx, ok := ctx.Value(contextKey).(*integrationContext)
if !ok {
return s.executionService.OpenKVStore(ctx)
}
iCtx.gasMeter = stfgas.NewMeter(gasLimit)
writerMap := stfgas.NewMeteredWriterMap(stfgas.DefaultConfig, iCtx.gasMeter, iCtx.state)
state, err := writerMap.GetWriter(s.actor)
if err != nil {
panic(err)
}
return state
}
var (
_ event.Service = &eventService{}
_ event.Manager = &eventManager{}
)
type eventService struct{}
// EventManager implements event.Service.
func (e *eventService) EventManager(context.Context) event.Manager {
return &eventManager{}
}
type eventManager struct{}
// Emit implements event.Manager.
func (e *eventManager) Emit(event transaction.Msg) error {
return nil
}
// EmitKV implements event.Manager.
func (e *eventManager) EmitKV(eventType string, attrs ...event.Attribute) error {
return nil
}