chore: remove v2 from 0.52 release branch (#23445)
Co-authored-by: aljo242 <alex@skip.money>
This commit is contained in:
parent
84186b07e1
commit
3a48b2941f
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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 ##
|
||||
###################
|
||||
|
||||
42
.github/workflows/test.yml
vendored
42
.github/workflows/test.yml
vendored
@ -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:
|
||||
|
||||
151
.github/workflows/v2-test.yml
vendored
151
.github/workflows/v2-test.yml
vendored
@ -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
|
||||
@ -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
|
||||
|
||||
54
README.md
54
README.md
@ -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
|
||||
|
||||
|
||||
11
UPGRADING.md
11
UPGRADING.md
@ -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`
|
||||
|
||||
@ -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.
|
||||
@ -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`.
|
||||
@ -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
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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")
|
||||
)
|
||||
@ -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
|
||||
)
|
||||
@ -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=
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
)
|
||||
@ -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))
|
||||
}
|
||||
@ -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 }
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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}
|
||||
}
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
// Package mempool defines a few mempool services which can be used in conjunction with your consensus implementation.
|
||||
package mempool
|
||||
@ -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
|
||||
}
|
||||
@ -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 }
|
||||
@ -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
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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 },
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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")
|
||||
)
|
||||
@ -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)
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
1
simapp/v2/.gitignore
vendored
1
simapp/v2/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/simapp.test
|
||||
@ -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.
|
||||
@ -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{}),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
274
simapp/v2/go.mod
274
simapp/v2/go.mod
@ -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
|
||||
)
|
||||
1562
simapp/v2/go.sum
1562
simapp/v2/go.sum
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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:")
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
12
tests/go.sum
12
tests/go.sum
@ -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=
|
||||
|
||||
@ -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()
|
||||
}
|
||||
@ -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())
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user