Merge branch 'master' into hulatown/adr-043-nft
This commit is contained in:
commit
be60788e23
|
@ -1,41 +1,41 @@
|
||||||
"Scope: x/auth":
|
"C:x/auth":
|
||||||
- x/auth/**/*
|
- x/auth/**/*
|
||||||
"Scope: x/authz":
|
"C:x/authz":
|
||||||
- x/authz/**/*
|
- x/authz/**/*
|
||||||
"Scope: x/bank":
|
"C:x/bank":
|
||||||
- x/bank/**/*
|
- x/bank/**/*
|
||||||
"Scope: x/capability":
|
"C:x/capability":
|
||||||
- x/capability/**/*
|
- x/capability/**/*
|
||||||
"Scope: x/crisis":
|
"C:x/crisis":
|
||||||
- x/crisis/**/*
|
- x/crisis/**/*
|
||||||
"Scope: x/distribution":
|
"C:x/distribution":
|
||||||
- x/distribution/**/*
|
- x/distribution/**/*
|
||||||
"Scope: x/evidence":
|
"C:x/evidence":
|
||||||
- x/evidence/**/*
|
- x/evidence/**/*
|
||||||
"Scope: x/feegrant":
|
"C:x/feegrant":
|
||||||
- x/feegrant/**/*
|
- x/feegrant/**/*
|
||||||
"Scope: x/genutil":
|
"C:x/genutil":
|
||||||
- x/genutil/**/*
|
- x/genutil/**/*
|
||||||
"Scope: x/gov":
|
"C:x/gov":
|
||||||
- x/gov/**/*
|
- x/gov/**/*
|
||||||
"Scope: x/mint":
|
"C:x/mint":
|
||||||
- x/mint/**/*
|
- x/mint/**/*
|
||||||
"Scope: x/params":
|
"C:x/params":
|
||||||
- x/params/**/*
|
- x/params/**/*
|
||||||
"Scope: Simulations":
|
"C:Simulations":
|
||||||
- x/simulation/**/*
|
- x/simulation/**/*
|
||||||
- x/*/simulation/**/*
|
- x/*/simulation/**/*
|
||||||
"Scope: x/slashing":
|
"C:x/slashing":
|
||||||
- x/slashing/**/*
|
- x/slashing/**/*
|
||||||
"Scope: x/staking":
|
"C:x/staking":
|
||||||
- x/staking/**/*
|
- x/staking/**/*
|
||||||
"Scope: x/upgrade":
|
"C:x/upgrade":
|
||||||
- x/upgrade/**/*
|
- x/upgrade/**/*
|
||||||
"Scope: Cosmovisor":
|
"C:Cosmovisor":
|
||||||
- cosmovisor/**/*
|
- cosmovisor/**/*
|
||||||
"Scope: Rosetta":
|
"C:Rosetta":
|
||||||
- contrib/rosetta/**/*
|
- contrib/rosetta/**/*
|
||||||
"Scope: Keys":
|
"C:Keys":
|
||||||
- client/keys/**/*
|
- client/keys/**/*
|
||||||
"Type: Build":
|
"Type: Build":
|
||||||
- Makefile
|
- Makefile
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
- buf.yaml
|
- buf.yaml
|
||||||
- .mergify.yml
|
- .mergify.yml
|
||||||
- .golangci.yml
|
- .golangci.yml
|
||||||
"Scope: CLI":
|
"C:CLI":
|
||||||
- client/**/*
|
- client/**/*
|
||||||
- x/*/client/**/*
|
- x/*/client/**/*
|
||||||
"Type: Docs":
|
"Type: Docs":
|
||||||
|
|
|
@ -7,7 +7,7 @@ jobs:
|
||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v3.0.18
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
|
stale-pr-message: "This pull request has been automatically marked as stale because it has not had
|
||||||
|
|
|
@ -38,9 +38,11 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||||
* [\#9205](https://github.com/cosmos/cosmos-sdk/pull/9205) Improve readability in `abci` handleQueryP2P
|
* [\#9205](https://github.com/cosmos/cosmos-sdk/pull/9205) Improve readability in `abci` handleQueryP2P
|
||||||
* [\#9235](https://github.com/cosmos/cosmos-sdk/pull/9235) CreateMembershipProof/CreateNonMembershipProof now returns an error
|
* [\#9235](https://github.com/cosmos/cosmos-sdk/pull/9235) CreateMembershipProof/CreateNonMembershipProof now returns an error
|
||||||
if input key is empty, or input data contains empty key.
|
if input key is empty, or input data contains empty key.
|
||||||
|
* [\#9314](https://github.com/cosmos/cosmos-sdk/pull/9314) Update Rosetta SDK to upstream's latest release.
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
* [\#8077](https://github.com/cosmos/cosmos-sdk/pull/8077) Added support for grpc-web, enabling browsers to communicate with a chain's gRPC server
|
||||||
* [\#8965](https://github.com/cosmos/cosmos-sdk/pull/8965) cosmos reflection now provides more information on the application such as: deliverable msgs, sdk.Config info etc (still in alpha stage).
|
* [\#8965](https://github.com/cosmos/cosmos-sdk/pull/8965) cosmos reflection now provides more information on the application such as: deliverable msgs, sdk.Config info etc (still in alpha stage).
|
||||||
* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Added Protobuf compatible secp256r1 ECDSA signatures.
|
* [\#8559](https://github.com/cosmos/cosmos-sdk/pull/8559) Added Protobuf compatible secp256r1 ECDSA signatures.
|
||||||
* [\#8786](https://github.com/cosmos/cosmos-sdk/pull/8786) Enabled secp256r1 in x/auth.
|
* [\#8786](https://github.com/cosmos/cosmos-sdk/pull/8786) Enabled secp256r1 in x/auth.
|
||||||
|
@ -67,6 +69,7 @@ if input key is empty, or input data contains empty key.
|
||||||
* via `ServiceMsg` TypeURLs (e.g. `message.action='/cosmos.bank.v1beta1.Msg/Send'`) does not work anymore,
|
* via `ServiceMsg` TypeURLs (e.g. `message.action='/cosmos.bank.v1beta1.Msg/Send'`) does not work anymore,
|
||||||
* via legacy `msg.Type()` (e.g. `message.action='send'`) is being deprecated, new `Msg`s won't emit these events.
|
* via legacy `msg.Type()` (e.g. `message.action='send'`) is being deprecated, new `Msg`s won't emit these events.
|
||||||
* Please use concrete `Msg` TypeURLs instead (e.g. `message.action='/cosmos.bank.v1beta1.MsgSend'`).
|
* Please use concrete `Msg` TypeURLs instead (e.g. `message.action='/cosmos.bank.v1beta1.MsgSend'`).
|
||||||
|
* [\#9291](https://github.com/cosmos/cosmos-sdk/pull/9291) Migration scripts prior to v0.38 have been removed from the CLI `migrate` command. The oldest supported migration is v0.39->v0.42.
|
||||||
|
|
||||||
### API Breaking Changes
|
### API Breaking Changes
|
||||||
|
|
||||||
|
@ -136,7 +139,6 @@ if input key is empty, or input data contains empty key.
|
||||||
* (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic`
|
* (keyring) [#\8635](https://github.com/cosmos/cosmos-sdk/issues/8635) Remove hardcoded default passphrase value on `NewMnemonic`
|
||||||
* (x/bank) [\#8434](https://github.com/cosmos/cosmos-sdk/pull/8434) Fix legacy REST API `GET /bank/total` and `GET /bank/total/{denom}` in swagger
|
* (x/bank) [\#8434](https://github.com/cosmos/cosmos-sdk/pull/8434) Fix legacy REST API `GET /bank/total` and `GET /bank/total/{denom}` in swagger
|
||||||
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
|
* (x/slashing) [\#8427](https://github.com/cosmos/cosmos-sdk/pull/8427) Fix query signing infos command
|
||||||
* (server) [\#8399](https://github.com/cosmos/cosmos-sdk/pull/8399) fix gRPC-web flag default value
|
|
||||||
* (x/bank) [\#9229](https://github.com/cosmos/cosmos-sdk/pull/9229) Now zero coin balances cannot be added to balances & supply stores. If any denom becomes zero corresponding key gets deleted from store.
|
* (x/bank) [\#9229](https://github.com/cosmos/cosmos-sdk/pull/9229) Now zero coin balances cannot be added to balances & supply stores. If any denom becomes zero corresponding key gets deleted from store.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
|
@ -4,19 +4,16 @@
|
||||||
|
|
||||||
Only the following release series are currently supported and receive bug fixes:
|
Only the following release series are currently supported and receive bug fixes:
|
||||||
|
|
||||||
The `0.37.x` release series will continue receiving bug fixes until the Cosmos Hub
|
* **0.39 «Launchpad»** will be supported until 6 months after **0.42.0** is published. A fairly strict **bugfix-only** rule applies to pull requests that are requested to be included into a stable point-release.
|
||||||
migrates to a newer release of the Cosmos-SDK.
|
* **0.42 «Stargate»** is the latest stable release.
|
||||||
|
|
||||||
* **0.37** will continue receiving bug fixes until the Cosmos Hub migrates to a newer release series of the Cosmos-SDK.
|
The **0.42 «Stargate»** release series is maintained in compliance with the **Stable Release Policy** as described in this document.
|
||||||
* **0.39 «Launchpad»** will be supported until 6 months after **0.40.0** is published. A fairly strict **bugfix-only** rule applies to pull requests that are requested to be included into a stable point-release.
|
|
||||||
|
|
||||||
The **0.39 «Launchpad»** release series is maintained in compliance with the **Stable Release Policy** as described in this document.
|
|
||||||
|
|
||||||
## Stable Release Policy
|
## Stable Release Policy
|
||||||
|
|
||||||
This policy presently applies *only* to the following release series:
|
This policy presently applies *only* to the following release series:
|
||||||
|
|
||||||
* **0.39 «Launchpad»**
|
* **0.42 «Stargate»**
|
||||||
|
|
||||||
### Point Releases
|
### Point Releases
|
||||||
|
|
||||||
|
@ -48,6 +45,10 @@ priority is to minimise the risk caused by changes that are not strictly require
|
||||||
be correlated with minimising the size of such changes. As such, the same bug may need to be fixed in different
|
be correlated with minimising the size of such changes. As such, the same bug may need to be fixed in different
|
||||||
ways in stable releases and `master` branch.
|
ways in stable releases and `master` branch.
|
||||||
|
|
||||||
|
### Migrations
|
||||||
|
|
||||||
|
To smoothen the update to the latest stable release, the SDK includes a set of CLI commands for managing migrations between SDK versions, under the `migrate` subcommand. Only migration scripts between stable releases are included. For the current release, **0.39 «Launchpad»** and later migrations are supported.
|
||||||
|
|
||||||
### What qualifies as a Stable Release Update (SRU)
|
### What qualifies as a Stable Release Update (SRU)
|
||||||
|
|
||||||
* **High-impact bugs**
|
* **High-impact bugs**
|
||||||
|
@ -86,12 +87,12 @@ As rule of thumb, the following changes will **NOT** be automatically accepted i
|
||||||
|
|
||||||
## Stable Release Exception - Procedure
|
## Stable Release Exception - Procedure
|
||||||
|
|
||||||
1. Check that the bug is either fixed or not reproducible in `master`. It is, in general, not appropriate to release bug fixes for stable releases without first testing them in `master`. Please apply the label [0.39 «Launchpad»](https://github.com/cosmos/cosmos-sdk/labels/0.39%20LTS%20%28Launchpad%29) to the issue.
|
1. Check that the bug is either fixed or not reproducible in `master`. It is, in general, not appropriate to release bug fixes for stable releases without first testing them in `master`. Please apply the label [0.42 «Stargate»](https://github.com/cosmos/cosmos-sdk/labels/0.42%20LTS%20%28Stargate%29) to the issue.
|
||||||
2. Add a comment to the issue and ensure it contains the following information (see the bug template below):
|
2. Add a comment to the issue and ensure it contains the following information (see the bug template below):
|
||||||
* **[Impact]** An explanation of the bug on users and justification for backporting the fix to the stable release.
|
* **[Impact]** An explanation of the bug on users and justification for backporting the fix to the stable release.
|
||||||
* A **[Test Case]** section containing detailed instructions on how to reproduce the bug.
|
* A **[Test Case]** section containing detailed instructions on how to reproduce the bug.
|
||||||
* A **[Regression Potential]** section with a clear assessment on how regressions are most likely to manifest as a result of the pull request that aims to fix the bug in the target stable release.
|
* A **[Regression Potential]** section with a clear assessment on how regressions are most likely to manifest as a result of the pull request that aims to fix the bug in the target stable release.
|
||||||
3. **Stable Release Managers** will review and discuss the PR. Once *consensus* surrounding the rationale has been reached and the technical review has successfully concluded, the pull request will be merged in the respective point-release target branch (e.g. `release/launchpad/0.39.X` being `X` the Launchpad's upcoming point-release) and the PR included in the point-release's respective milestone (e.g. `0.39.5`).
|
3. **Stable Release Managers** will review and discuss the PR. Once *consensus* surrounding the rationale has been reached and the technical review has successfully concluded, the pull request will be merged in the respective point-release target branch (e.g. `release/v0.42.x`) and the PR included in the point-release's respective milestone (e.g. `0.42.5`).
|
||||||
|
|
||||||
### Stable Release Exception - Bug template
|
### Stable Release Exception - Bug template
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ Brief xplanation of the effects of the bug on users and a justification for back
|
||||||
|
|
||||||
#### Test Case
|
#### Test Case
|
||||||
|
|
||||||
Detailed instructions on how to reproduce the bug on Launchpad's most recently published point-release.
|
Detailed instructions on how to reproduce the bug on Stargate's most recently published point-release.
|
||||||
|
|
||||||
#### Regression Potential
|
#### Regression Potential
|
||||||
|
|
||||||
|
@ -122,10 +123,8 @@ Their responsibilites include:
|
||||||
* Approving/rejecting proposed changes to a stable release series.
|
* Approving/rejecting proposed changes to a stable release series.
|
||||||
* Executing the release process of stable point-releases in compliance with the [Point Release Procedure](CONTRIBUTING.md).
|
* Executing the release process of stable point-releases in compliance with the [Point Release Procedure](CONTRIBUTING.md).
|
||||||
|
|
||||||
The Stable Release Managers are appointed by the Interchain Foundation.
|
The Stable Release Managers are appointed by the Interchain Foundation. Currently residing Stable Release Managers:
|
||||||
|
|
||||||
*Stable Release Managers* for the **0.39 «Launchpad»** release series follow:
|
* @clevinson - Cory Levinson
|
||||||
|
* @amaurym - Amaruy Martiny
|
||||||
* @alessio - Alessio Treglia
|
* @robert-zaremba - Robert Zaremba
|
||||||
* @clevinson - Cory Levinson-
|
|
||||||
* @ethanfrey - Ethan Frey
|
|
||||||
|
|
|
@ -36,8 +36,11 @@ func runConfigCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0:
|
case 0:
|
||||||
// print all client config fields to sdt out
|
// print all client config fields to stdout
|
||||||
s, _ := json.MarshalIndent(conf, "", "\t")
|
s, err := json.MarshalIndent(conf, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
cmd.Println(string(s))
|
cmd.Println(string(s))
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1545,7 +1545,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: delegation
|
name: delegation
|
||||||
description: The password of the account to remove from the KMS
|
description: Delegate an amount of liquid coins to a validator
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -1760,7 +1760,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: delegation
|
name: delegation
|
||||||
description: The password of the account to remove from the KMS
|
description: Unbond an amount of bonded shares from a validator
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -16945,6 +16945,11 @@ paths:
|
||||||
bond_denom:
|
bond_denom:
|
||||||
type: string
|
type: string
|
||||||
description: bond_denom defines the bondable coin denomination.
|
description: bond_denom defines the bondable coin denomination.
|
||||||
|
power_reduction:
|
||||||
|
type: string
|
||||||
|
title: >-
|
||||||
|
power_reduction is the amount of staking tokens required
|
||||||
|
for 1 unit of consensus-engine power
|
||||||
description: >-
|
description: >-
|
||||||
QueryParamsResponse is response type for the Query/Params RPC
|
QueryParamsResponse is response type for the Query/Params RPC
|
||||||
method.
|
method.
|
||||||
|
@ -31115,6 +31120,11 @@ definitions:
|
||||||
bond_denom:
|
bond_denom:
|
||||||
type: string
|
type: string
|
||||||
description: bond_denom defines the bondable coin denomination.
|
description: bond_denom defines the bondable coin denomination.
|
||||||
|
power_reduction:
|
||||||
|
type: string
|
||||||
|
title: >-
|
||||||
|
power_reduction is the amount of staking tokens required for 1 unit of
|
||||||
|
consensus-engine power
|
||||||
description: Params defines the parameters for the staking module.
|
description: Params defines the parameters for the staking module.
|
||||||
cosmos.staking.v1beta1.Pool:
|
cosmos.staking.v1beta1.Pool:
|
||||||
type: object
|
type: object
|
||||||
|
@ -32355,6 +32365,11 @@ definitions:
|
||||||
bond_denom:
|
bond_denom:
|
||||||
type: string
|
type: string
|
||||||
description: bond_denom defines the bondable coin denomination.
|
description: bond_denom defines the bondable coin denomination.
|
||||||
|
power_reduction:
|
||||||
|
type: string
|
||||||
|
title: >-
|
||||||
|
power_reduction is the amount of staking tokens required for 1
|
||||||
|
unit of consensus-engine power
|
||||||
description: QueryParamsResponse is response type for the Query/Params RPC method.
|
description: QueryParamsResponse is response type for the Query/Params RPC method.
|
||||||
cosmos.staking.v1beta1.QueryPoolResponse:
|
cosmos.staking.v1beta1.QueryPoolResponse:
|
||||||
type: object
|
type: object
|
||||||
|
@ -35881,7 +35896,14 @@ definitions:
|
||||||
transaction.
|
transaction.
|
||||||
memo:
|
memo:
|
||||||
type: string
|
type: string
|
||||||
title: memo is any arbitrary memo to be added to the transaction
|
description: >-
|
||||||
|
memo is any arbitrary note/comment to be added to the transaction.
|
||||||
|
|
||||||
|
WARNING: in clients, any publicly exposed text should not be
|
||||||
|
called memo,
|
||||||
|
|
||||||
|
but should be called `note` instead (see
|
||||||
|
https://github.com/cosmos/cosmos-sdk/issues/9122).
|
||||||
timeout_height:
|
timeout_height:
|
||||||
type: string
|
type: string
|
||||||
format: uint64
|
format: uint64
|
||||||
|
@ -36451,7 +36473,14 @@ definitions:
|
||||||
transaction.
|
transaction.
|
||||||
memo:
|
memo:
|
||||||
type: string
|
type: string
|
||||||
title: memo is any arbitrary memo to be added to the transaction
|
description: >-
|
||||||
|
memo is any arbitrary note/comment to be added to the transaction.
|
||||||
|
|
||||||
|
WARNING: in clients, any publicly exposed text should not be called
|
||||||
|
memo,
|
||||||
|
|
||||||
|
but should be called `note` instead (see
|
||||||
|
https://github.com/cosmos/cosmos-sdk/issues/9122).
|
||||||
timeout_height:
|
timeout_height:
|
||||||
type: string
|
type: string
|
||||||
format: uint64
|
format: uint64
|
||||||
|
|
|
@ -556,7 +556,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: delegation
|
name: delegation
|
||||||
description: The password of the account to remove from the KMS
|
description: Delegate an amount of liquid coins to a validator
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -646,7 +646,7 @@ paths:
|
||||||
parameters:
|
parameters:
|
||||||
- in: body
|
- in: body
|
||||||
name: delegation
|
name: delegation
|
||||||
description: The password of the account to remove from the KMS
|
description: Unbond an amount of bonded shares from a validator
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -102,7 +102,6 @@ output
|
||||||
- armor encrypted private key (saved to file)
|
- armor encrypted private key (saved to file)
|
||||||
*/
|
*/
|
||||||
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
|
func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *bufio.Reader) error {
|
||||||
// func RunAddCmd(cmd *cobra.Command, args []string, kb keyring.Keyring, inBuf *bufio.Reader) error {
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
name := args[0]
|
name := args[0]
|
||||||
|
|
|
@ -32,7 +32,7 @@ services:
|
||||||
- 8080
|
- 8080
|
||||||
|
|
||||||
test_rosetta:
|
test_rosetta:
|
||||||
image: tendermintdev/rosetta-cli:v0.6.6
|
image: tendermintdev/rosetta-cli:v0.6.7
|
||||||
volumes:
|
volumes:
|
||||||
- ./configuration:/rosetta/config:z
|
- ./configuration:/rosetta/config:z
|
||||||
command: ["./config/run_tests.sh"]
|
command: ["./config/run_tests.sh"]
|
||||||
|
|
|
@ -2,7 +2,7 @@ FROM golang:1.15-alpine as build
|
||||||
|
|
||||||
RUN apk add git gcc libc-dev --no-cache
|
RUN apk add git gcc libc-dev --no-cache
|
||||||
|
|
||||||
ARG ROSETTA_VERSION="v0.5.23"
|
ARG ROSETTA_VERSION="v0.6.7"
|
||||||
|
|
||||||
# build rosetta CLI
|
# build rosetta CLI
|
||||||
WORKDIR /rosetta
|
WORKDIR /rosetta
|
||||||
|
|
|
@ -24,7 +24,7 @@ func (suite *SKSuite) TestPubKey() {
|
||||||
suite.True(suite.sk.PublicKey.Equal(&pk.PublicKey))
|
suite.True(suite.sk.PublicKey.Equal(&pk.PublicKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SKSuite) Bytes() {
|
func (suite *SKSuite) TestBytes() {
|
||||||
bz := suite.sk.Bytes()
|
bz := suite.sk.Bytes()
|
||||||
suite.Len(bz, 32)
|
suite.Len(bz, 32)
|
||||||
var sk *PrivKey
|
var sk *PrivKey
|
||||||
|
|
|
@ -26,7 +26,9 @@ type PubKey struct {
|
||||||
address tmcrypto.Address
|
address tmcrypto.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address creates an ADR-28 address for ECDSA keys. protoName is a concrete proto structure id.
|
// Address gets the address associated with a pubkey. If no address exists, it returns a newly created ADR-28 address
|
||||||
|
// for ECDSA keys.
|
||||||
|
// protoName is a concrete proto structure id.
|
||||||
func (pk *PubKey) Address(protoName string) tmcrypto.Address {
|
func (pk *PubKey) Address(protoName string) tmcrypto.Address {
|
||||||
if pk.address == nil {
|
if pk.address == nil {
|
||||||
pk.address = address.Hash(protoName, pk.Bytes())
|
pk.address = address.Hash(protoName, pk.Bytes())
|
||||||
|
|
|
@ -48,9 +48,11 @@ func (suite *PKSuite) TestString() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *PKSuite) TestBytes() {
|
func (suite *PKSuite) TestBytes() {
|
||||||
require := suite.Require()
|
bz := suite.sk.Bytes()
|
||||||
|
fieldSize := (suite.sk.Curve.Params().BitSize + 7) / 8
|
||||||
|
suite.Len(bz, fieldSize)
|
||||||
var pk *PubKey
|
var pk *PubKey
|
||||||
require.Nil(pk.Bytes())
|
suite.Nil(pk.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *PKSuite) TestMarshal() {
|
func (suite *PKSuite) TestMarshal() {
|
||||||
|
|
|
@ -33,6 +33,9 @@ func (m *PrivKey) Sign(msg []byte) ([]byte, error) {
|
||||||
|
|
||||||
// Bytes serialize the private key.
|
// Bytes serialize the private key.
|
||||||
func (m *PrivKey) Bytes() []byte {
|
func (m *PrivKey) Bytes() []byte {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return m.Secret.Bytes()
|
return m.Secret.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package secp256r1
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
proto "github.com/gogo/protobuf/proto"
|
"github.com/gogo/protobuf/proto"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ func (suite *SKSuite) TestPubKey() {
|
||||||
suite.True(suite.sk.(*PrivKey).Secret.PublicKey.Equal(&pk.(*PubKey).Key.PublicKey))
|
suite.True(suite.sk.(*PrivKey).Secret.PublicKey.Equal(&pk.(*PubKey).Key.PublicKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SKSuite) Bytes() {
|
func (suite *SKSuite) TestBytes() {
|
||||||
bz := suite.sk.Bytes()
|
bz := suite.sk.Bytes()
|
||||||
suite.Len(bz, fieldSize)
|
suite.Len(bz, fieldSize)
|
||||||
var sk *PrivKey
|
var sk *PrivKey
|
||||||
|
|
|
@ -15,6 +15,9 @@ func (m *PubKey) String() string {
|
||||||
|
|
||||||
// Bytes implements SDK PubKey interface.
|
// Bytes implements SDK PubKey interface.
|
||||||
func (m *PubKey) Bytes() []byte {
|
func (m *PubKey) Bytes() []byte {
|
||||||
|
if m == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return m.Key.Bytes()
|
return m.Key.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,13 @@ func (suite *PKSuite) TestType() {
|
||||||
suite.Require().Equal(name, suite.pk.Type())
|
suite.Require().Equal(name, suite.pk.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *PKSuite) TestBytes() {
|
||||||
|
bz := suite.pk.Bytes()
|
||||||
|
suite.Len(bz, fieldSize+1)
|
||||||
|
var pk *PubKey
|
||||||
|
suite.Nil(pk.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *PKSuite) TestEquals() {
|
func (suite *PKSuite) TestEquals() {
|
||||||
require := suite.Require()
|
require := suite.Require()
|
||||||
|
|
||||||
|
|
|
@ -73,3 +73,4 @@ Read about the [PROCESS](./PROCESS.md).
|
||||||
- [ADR 037: Governance Split Votes](./adr-037-gov-split-vote.md)
|
- [ADR 037: Governance Split Votes](./adr-037-gov-split-vote.md)
|
||||||
- [ADR 038: State Listening](./adr-038-state-listening.md)
|
- [ADR 038: State Listening](./adr-038-state-listening.md)
|
||||||
- [ADR 039: Epoched Staking](./adr-039-epoched-staking.md)
|
- [ADR 039: Epoched Staking](./adr-039-epoched-staking.md)
|
||||||
|
- [ADR 040: Storage and SMT State Commitments](./adr-040-storage-and-smt-state-commitments.md)
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
- Alessio Treglia (@alessio)
|
- Alessio Treglia (@alessio)
|
||||||
- Frojdy Dymylja (@fdymylja)
|
- Frojdy Dymylja (@fdymylja)
|
||||||
|
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- 2021-05-12: the external library [cosmos-rosetta-gateway](https://github.com/tendermint/cosmos-rosetta-gateway) has been moved within the SDK.
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
[Rosetta API](https://www.rosetta-api.org/) is an open-source specification and set of tools developed by Coinbase to
|
[Rosetta API](https://www.rosetta-api.org/) is an open-source specification and set of tools developed by Coinbase to
|
||||||
|
@ -34,7 +38,7 @@ The driving principles of the proposed design are:
|
||||||
|
|
||||||
We will achieve these delivering on these principles by the following:
|
We will achieve these delivering on these principles by the following:
|
||||||
|
|
||||||
1. There will be an external repo called [cosmos-rosetta-gateway](https://github.com/tendermint/cosmos-rosetta-gateway)
|
1. There will be a package `rosetta/lib`
|
||||||
for the implementation of the core Rosetta API features, particularly:
|
for the implementation of the core Rosetta API features, particularly:
|
||||||
a. The types and interfaces (`Client`, `OfflineClient`...), this separates design from implementation detail.
|
a. The types and interfaces (`Client`, `OfflineClient`...), this separates design from implementation detail.
|
||||||
b. The `Server` functionality as this is independent of the Cosmos SDK version.
|
b. The `Server` functionality as this is independent of the Cosmos SDK version.
|
||||||
|
@ -207,4 +211,3 @@ Proposed
|
||||||
## References
|
## References
|
||||||
|
|
||||||
- https://www.rosetta-api.org/
|
- https://www.rosetta-api.org/
|
||||||
- https://github.com/tendermint/cosmos-rosetta-gateway
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
# ADR 040: Storage and SMT State Commitments
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
- 2020-01-15: Draft
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
DRAFT Not Implemented
|
||||||
|
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
|
||||||
|
Sparse Merke Tree ([SMT](https://osf.io/8mcnh/)) is a version of a Merkle Tree with various storage and performance optimizations. This ADR defines a separation of state commitments from data storage and the SDK transition from IAVL to SMT.
|
||||||
|
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
Currently, Cosmos SDK uses IAVL for both state [commitments](https://cryptography.fandom.com/wiki/Commitment_scheme) and data storage.
|
||||||
|
|
||||||
|
IAVL has effectively become an orphaned project within the Cosmos ecosystem and it's proven to be an inefficient state commitment data structure.
|
||||||
|
In the current design, IAVL is used for both data storage and as a Merkle Tree for state commitments. IAVL is meant to be a standalone Merkelized key/value database, however it's using a KV DB engine to store all tree nodes. So, each node is stored in a separate record in the KV DB. This causes many inefficiencies and problems:
|
||||||
|
|
||||||
|
+ Each object query requires a tree traversal from the root. Subsequent queries for the same object are cached on the SDK level.
|
||||||
|
+ Each edge traversal requires a DB query.
|
||||||
|
+ Creating snapshots is [expensive](https://github.com/cosmos/cosmos-sdk/issues/7215#issuecomment-684804950). It takes about 30 seconds to export less than 100 MB of state (as of March 2020).
|
||||||
|
+ Updates in IAVL may trigger tree reorganization and possible O(log(n)) hashes re-computation, which can become a CPU bottleneck.
|
||||||
|
+ The node structure is pretty expensive - it contains a standard tree node elements (key, value, left and right element) and additional metadata such as height, version (which is not required by the SDK). The entire node is hashed, and that hash is used as the key in the underlying database, [ref](https://github.com/cosmos/iavl/blob/master/docs/node/node.md
|
||||||
|
).
|
||||||
|
|
||||||
|
Moreover, the IAVL project lacks support and a maintainer and we already see better and well-established alternatives. Instead of optimizing the IAVL, we are looking into other solutions for both storage and state commitments.
|
||||||
|
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
We propose to separate the concerns of state commitment (**SC**), needed for consensus, and state storage (**SS**), needed for state machine. Finally we replace IAVL with [LazyLedgers' SMT](https://github.com/lazyledger/smt). LazyLedger SMT is based on Diem (called jellyfish) design [*] - it uses a compute-optimised SMT by replacing subtrees with only default values with a single node (same approach is used by Ethereum2) and implements compact proofs.
|
||||||
|
|
||||||
|
The storage model presented here doesn't deal with data structure nor serialization. It's a Key-Value database, where both key and value are binaries. The storage user is responsible for data serialization.
|
||||||
|
|
||||||
|
### Decouple state commitment from storage
|
||||||
|
|
||||||
|
|
||||||
|
Separation of storage and commitment (by the SMT) will allow the optimization of different components according to their usage and access patterns.
|
||||||
|
|
||||||
|
`SS` (SMT) is used to commit to a data and compute merkle proofs. `SC` is used to directly access data. To avoid collisions, both `SS` and `SC` will use a separate storage namespace (they could use the same database underneath). `SC` will store each `(key, value)` pair directly (map key -> value).
|
||||||
|
|
||||||
|
SMT is a merkle tree structure: we don't store keys directly. For every `(key, value)` pair, `hash(key)` is stored in a path (we hash a key to evenly distribute keys in the tree) and `hash(key, value)` in a leaf. Since we don't know a structure of a value (in particular if it contains the key) we hash both the key and the value in the `SC` leaf.
|
||||||
|
|
||||||
|
For data access we propose 2 additional KV buckets (namespaces for the key-value pairs, sometimes called [column family](https://github.com/facebook/rocksdb/wiki/Terminology)):
|
||||||
|
1. B1: `key → value`: the principal object storage, used by a state machine, behind the SDK `KVStore` interface: provides direct access by key and allows prefix iteration (KV DB backend must support it).
|
||||||
|
2. B2: `hash(key, value) → key`: a reverse index to get a key from an SMT path. Recall that SMT will store `(k, v)` as `(hash(k), hash(key, value))`. So, we can get an object value by composing `SMT_path → B2 → B1`.
|
||||||
|
3. we could use more buckets to optimize the app usage if needed.
|
||||||
|
|
||||||
|
Above, we propose to use a KV DB. However, for the state machine, we could use an RDBMS, which we discuss below.
|
||||||
|
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
State Storage requirements:
|
||||||
|
+ range queries
|
||||||
|
+ quick (key, value) access
|
||||||
|
+ creating a snapshot
|
||||||
|
+ historical versioning
|
||||||
|
+ pruning (garbage collection)
|
||||||
|
|
||||||
|
State Commitment requirements:
|
||||||
|
+ fast updates
|
||||||
|
+ tree path should be short
|
||||||
|
+ pruning (garbage collection)
|
||||||
|
|
||||||
|
|
||||||
|
### LazyLedger SMT for State Commitment
|
||||||
|
|
||||||
|
A Sparse Merkle tree is based on the idea of a complete Merkle tree of an intractable size. The assumption here is that as the size of the tree is intractable, there would only be a few leaf nodes with valid data blocks relative to the tree size, rendering a sparse tree.
|
||||||
|
|
||||||
|
|
||||||
|
### Snapshots for storage sync and state versioning
|
||||||
|
|
||||||
|
Below, with simple _snapshot_ we refer to a database snapshot mechanism, not to a _ABCI snapshot sync_. The latter will be referred as _snapshot sync_ (which will directly use DB snapshot as described below).
|
||||||
|
|
||||||
|
Database snapshot is a view of DB state at a certain time or transaction. It's not a full copy of a database (it would be too big), usually a snapshot mechanism is based on a _copy on write_ and it allows to efficiently deliver DB state at a certain stage.
|
||||||
|
Some DB engines support snapshotting. Hence, we propose to reuse that functionality for the state sync and versioning (described below). It will the supported DB engines to ones which efficiently implement snapshots. In a final section we will discuss evaluated DBs.
|
||||||
|
|
||||||
|
One of the Stargate core features is a _snapshot sync_ delivered in the `/snapshot` package. It provides a way to trustlessly sync a blockchain without repeating all transactions from the genesis. This feature is implemented in SDK and requires storage support. Currently IAVL is the only supported backend. It works by streaming to a client a snapshot of a `SS` at a certain version together with a header chain.
|
||||||
|
|
||||||
|
A new `SS` snapshot will be created in every `EndBlocker` and identified by a block height. The `rootmulti.Store` keeps track of the available snapshots to offer `SS` at a certain version. The `rootmulti.Store` implements the `CommitMultiStore` interface, which encapsulates a `Committer` interface. `Committer` has a `Commit`, `SetPruning`, `GetPruning` functions which will be used for creating and removing snapshots. The `rootStore.Commit` function creates a new snapshot and increments the version on each call, and checks if it needs to remove old versions. We will need to update the SMT interface to implement the `Committer` interface.
|
||||||
|
NOTE: `Commit` must be called exactly once per block. Otherwise we risk going out of sync for the version number and block height.
|
||||||
|
NOTE: For the SDK storage, we may consider splitting that interface into `Committer` and `PruningCommitter` - only the multiroot should implement `PruningCommitter` (cache and prefix store don't need pruning).
|
||||||
|
|
||||||
|
Number of historical versions for `abci.Query` and state sync snapshots is part of a node configuration, not a chain configuration (configuration implied by the blockchain consensus). A configuration should allow to specify number of past blocks and number of past blocks modulo some number (eg: 100 past blocks and one snapshot every 100 blocks for past 2000 blocks). Archival nodes can keep all past versions.
|
||||||
|
|
||||||
|
Pruning old snapshots is effectively done by a database. Whenever we update a record in `SC`, SMT won't update nodes - instead it creates new nodes on the update path, without removing the old one. Since we are snapshoting each block, we need to update that mechanism to immediately remove orphaned nodes from the storage. This is a safe operation - snapshots will keep track of the records which should be available for past versions.
|
||||||
|
|
||||||
|
To manage the active snapshots we will either us a DB _max number of snapshots_ option (if available), or will remove snapshots in the `EndBlocker`. The latter option can be done efficiently by identifying snapshots with block height.
|
||||||
|
|
||||||
|
|
||||||
|
#### Accessing old state versions
|
||||||
|
|
||||||
|
One of the functional requirements is to access old state. This is done through `abci.Query` structure. The version is specified by a block height (so we query for an object by a key `K` at block height `H`). The number of old versions supported for `abci.Query` is configurable. Accessing an old state is done by using available snapshots.
|
||||||
|
`abci.Query` doesn't need old state of `SC`. So, for efficiency, we should keep `SC` and `SS` in different databases (however using the same DB engine).
|
||||||
|
|
||||||
|
Moreover, SDK could provide a way to directly access the state. However, a state machine shouldn't do that - since the number of snapshots is configurable, it would lead to nondeterministic execution.
|
||||||
|
|
||||||
|
We positively [validated](https://github.com/cosmos/cosmos-sdk/discussions/8297) a versioning and snapshot mechanism for querying old state with regards to the database we evaluated.
|
||||||
|
|
||||||
|
|
||||||
|
### State Proofs
|
||||||
|
|
||||||
|
For any object stored in State Store (SS), we have corresponding object in `SC`. A proof for object `V` identified by a key `K` is a branch of `SC`, where the path corresponds to the key `hash(K)`, and the leaf is `hash(K, V)`.
|
||||||
|
|
||||||
|
|
||||||
|
### Rollbacks
|
||||||
|
|
||||||
|
We need to be able to process transactions and roll-back state updates if a transaction fails. This can be done in the following way: during transaction processing, we keep all state change requests (writes) in a `CacheWrapper` abstraction (as it's done today). Once we finish the block processing, in the `Endblocker`, we commit a root store - at that time, all changes are written to the SMT and to the `SS` and a snapshot is created.
|
||||||
|
|
||||||
|
|
||||||
|
### Committing to an object without saving it
|
||||||
|
|
||||||
|
We identified use-cases, where modules will need to save an object commitment without storing an object itself. Sometimes clients are receiving complex objects, and they have no way to prove a correctness of that object without knowing the storage layout. For those use cases it would be easier to commit to the object without storing it directly.
|
||||||
|
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
|
||||||
|
### Backwards Compatibility
|
||||||
|
|
||||||
|
This ADR doesn't introduce any SDK level API changes.
|
||||||
|
|
||||||
|
We change the storage layout of the state machine, a storage hard fork and network upgrade is required to incorporate these changes. SMT provides a merkle proof functionality, however it is not compatible with ICS23. Updating the proofs for ICS23 compatibility is required.
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
+ Decoupling state from state commitment introduce better engineering opportunities for further optimizations and better storage patterns.
|
||||||
|
+ Performance improvements.
|
||||||
|
+ Joining SMT based camp which has wider and proven adoption than IAVL. Example projects which decided on SMT: Ethereum2, Diem (Libra), Trillan, Tezos, LazyLedger.
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
+ Storage migration
|
||||||
|
+ LL SMT doesn't support pruning - we will need to add and test that functionality.
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
+ Deprecating IAVL, which is one of the core proposals of Cosmos Whitepaper.
|
||||||
|
|
||||||
|
|
||||||
|
## Alternative designs.
|
||||||
|
|
||||||
|
Most of the alternative designs were evaluated in [state commitments and storage report](https://paper.dropbox.com/published/State-commitments-and-storage-review--BDvA1MLwRtOx55KRihJ5xxLbBw-KeEB7eOd11pNrZvVtqUgL3h).
|
||||||
|
|
||||||
|
Ethereum research published [Verkle Tire](https://notes.ethereum.org/_N1mutVERDKtqGIEYc-Flw#fnref1) - an idea of combining polynomial commitments with merkle tree in order to reduce the tree height. This concept has a very good potential, but we think it's too early to implement it. The current, SMT based design could be easily updated to the Verkle Tire once other research implement all necessary libraries. The main advantage of the design described in this ADR is the separation of state commitments from the data storage and designing a more powerful interface.
|
||||||
|
|
||||||
|
|
||||||
|
## Further Discussions
|
||||||
|
|
||||||
|
### Evaluated KV Databases
|
||||||
|
|
||||||
|
We verified existing databases KV databases for evaluating snapshot support. The following databases provide efficient snapshot mechanism: Badger, RocksDB, [Pebble](https://github.com/cockroachdb/pebble). Databases which don't provide such support or are not production ready: boltdb, leveldb, goleveldb, membdb, lmdb.
|
||||||
|
|
||||||
|
### RDBMS
|
||||||
|
|
||||||
|
Use of RDBMS instead of simple KV store for state. Use of RDBMS will require an SDK API breaking change (`KVStore` interface), will allow better data extraction and indexing solutions. Instead of saving an object as a single blob of bytes, we could save it as record in a table in the state storage layer, and as a `hash(key, protobuf(object))` in the SMT as outlined above. To verify that an object registered in RDBMS is same as the one committed to SMT, one will need to load it from RDBMS, marshal using protobuf, hash and do SMT search.
|
||||||
|
|
||||||
|
### Off Chain Store
|
||||||
|
|
||||||
|
We were discussing use case where modules can use a support database, which is not automatically committed. Module will responsible for having a sound storage model and can optionally use the feature discussed in __Committing to an object without saving it_ section.
|
||||||
|
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
+ [IAVL What's Next?](https://github.com/cosmos/cosmos-sdk/issues/7100)
|
||||||
|
+ [IAVL overview](https://docs.google.com/document/d/16Z_hW2rSAmoyMENO-RlAhQjAG3mSNKsQueMnKpmcBv0/edit#heading=h.yd2th7x3o1iv) of it's state v0.15
|
||||||
|
+ [State commitments and storage report](https://paper.dropbox.com/published/State-commitments-and-storage-review--BDvA1MLwRtOx55KRihJ5xxLbBw-KeEB7eOd11pNrZvVtqUgL3h)
|
||||||
|
+ [LazyLedger SMT](https://github.com/lazyledger/smt)
|
||||||
|
+ Facebook Diem (Libra) SMT [design](https://developers.diem.com/papers/jellyfish-merkle-tree/2021-01-14.pdf)
|
||||||
|
+ [Trillian Revocation Transparency](https://github.com/google/trillian/blob/master/docs/papers/RevocationTransparency.pdf), [Trillian Verifiable Data Structures](https://github.com/google/trillian/blob/master/docs/papers/VerifiableDataStructures.pdf).
|
||||||
|
+ Design and implementation [discussion](https://github.com/cosmos/cosmos-sdk/discussions/8297).
|
|
@ -139,22 +139,24 @@ Modules must implement [interfaces](../building-modules/module-manager.md#applic
|
||||||
|
|
||||||
### `Msg` Services
|
### `Msg` Services
|
||||||
|
|
||||||
Each module defines two [Protobuf services](https://developers.google.com/protocol-buffers/docs/proto#services): one `Msg` service to handle messages, and one gRPC `Query` service to handle queries. If we consider the module as a state-machine, then a `Msg` is a state transition. A `Msg` service is a Protobuf service defining all possible `Msg`s a module exposes. Note that `Msg`s are bundled in [`transactions`](../core/transactions.md), and each transaction contains one or multiple `messages`.
|
Each module defines two [Protobuf services](https://developers.google.com/protocol-buffers/docs/proto#services): one `Msg` service to handle messages, and one gRPC `Query` service to handle queries. If we consider the module as a state-machine, then a `Msg` service is a set of state transition RPC methods.
|
||||||
|
Each Protobuf `Msg` service method is 1:1 related to a Protobuf request type, which must implement `sdk.Msg` interface.
|
||||||
|
Note that `sdk.Msg`s are bundled in [transactions](../core/transactions.md), and each transaction contains one or multiple messages.
|
||||||
|
|
||||||
When a valid block of transactions is received by the full-node, Tendermint relays each one to the application via [`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx). Then, the application handles the transaction:
|
When a valid block of transactions is received by the full-node, Tendermint relays each one to the application via [`DeliverTx`](https://tendermint.com/docs/app-dev/abci-spec.html#delivertx). Then, the application handles the transaction:
|
||||||
|
|
||||||
1. Upon receiving the transaction, the application first unmarshalls it from `[]bytes`.
|
1. Upon receiving the transaction, the application first unmarshalls it from `[]bytes`.
|
||||||
2. Then, it verifies a few things about the transaction like [fee payment and signatures](#gas-fees.md#antehandler) before extracting the `Msg`(s) contained in the transaction.
|
2. Then, it verifies a few things about the transaction like [fee payment and signatures](#gas-fees.md#antehandler) before extracting the `Msg`(s) contained in the transaction.
|
||||||
3. `Msg`s are encoded as Protobuf [`Any`s](#register-codec) via the `sdk.ServiceMsg` struct. By analyzing each `Any`'s `type_url`, baseapp's `msgServiceRouter` routes the `Msg` to the corresponding module's `Msg` service.
|
3. `sdk.Msg`s are encoded using Protobuf [`Any`s](#register-codec). By analyzing each `Any`'s `type_url`, baseapp's `msgServiceRouter` routes the `sdk.Msg` to the corresponding module's `Msg` service.
|
||||||
4. If the message is successfully processed, the state is updated.
|
4. If the message is successfully processed, the state is updated.
|
||||||
|
|
||||||
For a more detailed look at a transaction lifecycle, click [here](./tx-lifecycle.md).
|
For a more details look at a transaction [lifecycle](./tx-lifecycle.md).
|
||||||
|
|
||||||
Module developers create custom `Msg`s when they build their own module. The general practice is to define all `Msg`s in a Protobuf service called `service Msg {}`, and define each `Msg` as a Protobuf service method, using the `rpc` keyword. These definitions usually reside in a `tx.proto` file. For example, the `x/bank` module defines two `Msg`s to allows users to transfer tokens:
|
Module developers create custom `Msg` services when they build their own module. The general practice is to define the `Msg` Protobuf service in a `tx.proto` file. For example, the `x/bank` module defines a service with two methods to transfer tokens:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
|
||||||
|
|
||||||
These two `Msg`s are processed by the `Msg` service of the `x/bank` module, which ultimately calls the `keeper` of the `x/auth` module in order to update the state.
|
Service methods use `keeper` in order to update the module state.
|
||||||
|
|
||||||
Each module should also implement the `RegisterServices` method as part of the [`AppModule` interface](#application-module-interface). This method should call the `RegisterMsgServer` function provided by the generated Protobuf code.
|
Each module should also implement the `RegisterServices` method as part of the [`AppModule` interface](#application-module-interface). This method should call the `RegisterMsgServer` function provided by the generated Protobuf code.
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ ctx.BlockGasMeter().ConsumeGas(
|
||||||
|
|
||||||
## AnteHandler
|
## AnteHandler
|
||||||
|
|
||||||
The `AnteHandler` is run for every transaction during `CheckTx` and `DeliverTx`, before the `Msg` service of each `Msg` in the transaction. `AnteHandler`s have the following signature:
|
The `AnteHandler` is run for every transaction during `CheckTx` and `DeliverTx`, before a Protobuf `Msg` service method for each `sdk.Msg` in the transaction. `AnteHandler`s have the following signature:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// AnteHandler authenticates transactions, before their internal messages are handled.
|
// AnteHandler authenticates transactions, before their internal messages are handled.
|
||||||
|
|
|
@ -83,7 +83,7 @@ When `Tx` is received by the application from the underlying consensus engine (e
|
||||||
|
|
||||||
### ValidateBasic
|
### ValidateBasic
|
||||||
|
|
||||||
[`Msg`s](../core/transactions.md#messages) are extracted from `Tx` and `ValidateBasic`, a method of the `Msg` interface implemented by the module developer, is run for each one. It should include basic **stateless** sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as account balance of an address.
|
[`sdk.Msg`s](../core/transactions.md#messages) are extracted from `Tx`, and `ValidateBasic`, a method of the `sdk.Msg` interface implemented by the module developer, is run for each one. `ValidateBasic` should include basic **stateless** sanity checks. For example, if the message is to send coins from one address to another, `ValidateBasic` likely checks for nonempty addresses and a nonnegative coin amount, but does not require knowledge of state such as the account balance of an address.
|
||||||
|
|
||||||
### AnteHandler
|
### AnteHandler
|
||||||
|
|
||||||
|
@ -199,12 +199,11 @@ Instead of using their `checkState`, full-nodes use `deliverState`:
|
||||||
- **`MsgServiceRouter`:** While `CheckTx` would have exited, `DeliverTx` continues to run
|
- **`MsgServiceRouter`:** While `CheckTx` would have exited, `DeliverTx` continues to run
|
||||||
[`runMsgs`](../core/baseapp.md#runtx-and-runmsgs) to fully execute each `Msg` within the transaction.
|
[`runMsgs`](../core/baseapp.md#runtx-and-runmsgs) to fully execute each `Msg` within the transaction.
|
||||||
Since the transaction may have messages from different modules, `BaseApp` needs to know which module
|
Since the transaction may have messages from different modules, `BaseApp` needs to know which module
|
||||||
to find the appropriate handler. This is achieved using `BaseApp`'s `MsgServiceRouter` so that it can be processed by the module's [`Msg` service](../building-modules/msg-services.md).
|
to find the appropriate handler. This is achieved using `BaseApp`'s `MsgServiceRouter` so that it can be processed by the module's Protobuf [`Msg` service](../building-modules/msg-services.md).
|
||||||
For legacy `Msg` routing, the `Route` function is called via the [module manager](../building-modules/module-manager.md) to retrieve the route name and find the legacy [`Handler`](../building-modules/msg-services.md#handler-type) within the module.
|
For `LegacyMsg` routing, the `Route` function is called via the [module manager](../building-modules/module-manager.md) to retrieve the route name and find the legacy [`Handler`](../building-modules/msg-services.md#handler-type) within the module.
|
||||||
|
|
||||||
- **`Msg` service:** The `Msg` service, a step up from `AnteHandler`, is responsible for executing each
|
- **`Msg` service:** a Protobuf `Msg` service, a step up from `AnteHandler`, is responsible for executing each
|
||||||
message in the `Tx` and causes state transitions to persist in `deliverTxState`. It is defined
|
message in the `Tx` and causes state transitions to persist in `deliverTxState`.
|
||||||
within a module `Msg` protobuf service and writes to the appropriate stores within the module.
|
|
||||||
|
|
||||||
- **Gas:** While a `Tx` is being delivered, a `GasMeter` is used to keep track of how much
|
- **Gas:** While a `Tx` is being delivered, a `GasMeter` is used to keep track of how much
|
||||||
gas is being used; if execution completes, `GasUsed` is set and returned in the
|
gas is being used; if execution completes, `GasUsed` is set and returned in the
|
||||||
|
|
|
@ -17,7 +17,7 @@ The Cosmos SDK can be thought of as the Ruby-on-Rails of blockchain development.
|
||||||
|
|
||||||
On top of this core, the Cosmos SDK enables developers to build modules that implement the business logic of their application. In other words, SDK modules implement the bulk of the logic of applications, while the core does the wiring and enables modules to be composed together. The end goal is to build a robust ecosystem of open-source SDK modules, making it increasingly easier to build complex blockchain applications.
|
On top of this core, the Cosmos SDK enables developers to build modules that implement the business logic of their application. In other words, SDK modules implement the bulk of the logic of applications, while the core does the wiring and enables modules to be composed together. The end goal is to build a robust ecosystem of open-source SDK modules, making it increasingly easier to build complex blockchain applications.
|
||||||
|
|
||||||
SDK modules can be seen as little state-machines within the state-machine. They generally define a subset of the state using one or more `KVStore`s in the [main multistore](../core/store.md), as well as a subset of [message types](./messages-and-queries.md#messages). These messages are routed by one of the main components of SDK core, [`BaseApp`](../core/baseapp.md), to the [`Msg` service](./msg-services.md) of the module that defines them.
|
SDK modules can be seen as little state-machines within the state-machine. They generally define a subset of the state using one or more `KVStore`s in the [main multistore](../core/store.md), as well as a subset of [message types](./messages-and-queries.md#messages). These messages are routed by one of the main components of SDK core, [`BaseApp`](../core/baseapp.md), to a module Protobuf [`Msg` service](./msg-services.md) that defines them.
|
||||||
|
|
||||||
```
|
```
|
||||||
+
|
+
|
||||||
|
@ -79,7 +79,7 @@ While there are no definitive guidelines for writing modules, here are some impo
|
||||||
Modules are by convention defined in the `./x/` subfolder (e.g. the `bank` module will be defined in the `./x/bank` folder). They generally share the same core components:
|
Modules are by convention defined in the `./x/` subfolder (e.g. the `bank` module will be defined in the `./x/bank` folder). They generally share the same core components:
|
||||||
|
|
||||||
- A [`keeper`](./keeper.md), used to access the module's store(s) and update the state.
|
- A [`keeper`](./keeper.md), used to access the module's store(s) and update the state.
|
||||||
- A [`Msg` service](./messages-and-queries.md#messages) used to process messages when they are routed to the module by [`BaseApp`](../core/baseapp.md#message-routing) and trigger state-transitions.
|
- A [`Msg` service](./messages-and-queries.md#messages), used to process messages when they are routed to the module by [`BaseApp`](../core/baseapp.md#message-routing) and trigger state-transitions.
|
||||||
- A [query service](./query-services.md), used to process user queries when they are routed to the module by [`BaseApp`](../core/baseapp.md#query-routing).
|
- A [query service](./query-services.md), used to process user queries when they are routed to the module by [`BaseApp`](../core/baseapp.md#query-routing).
|
||||||
- Interfaces, for end users to query the subset of the state defined by the module and create `message`s of the custom types defined in the module.
|
- Interfaces, for end users to query the subset of the state defined by the module and create `message`s of the custom types defined in the module.
|
||||||
|
|
||||||
|
|
|
@ -18,32 +18,35 @@ When a transaction is relayed from the underlying consensus engine to the SDK ap
|
||||||
|
|
||||||
### `Msg` Services
|
### `Msg` Services
|
||||||
|
|
||||||
Starting from v0.40, defining Protobuf `Msg` services is the recommended way to handle messages. A `Msg` protobuf service should be created per module, typically in `tx.proto` (see more info about [conventions and naming](../core/encoding.md#faq)). It must have an RPC service method defined for each message in the module.
|
Starting from v0.40, defining Protobuf `Msg` services is the recommended way to handle messages. A Protobuf `Msg` service should be created for each module, typically in `tx.proto` (see more info about [conventions and naming](../core/encoding.md#faq)). It must have an RPC service method defined for each message in the module.
|
||||||
|
|
||||||
See an example of a `Msg` service definition from `x/bank` module:
|
See an example of a `Msg` service definition from `x/bank` module:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/proto/cosmos/bank/v1beta1/tx.proto#L10-L17
|
||||||
|
|
||||||
For backwards compatibility with [legacy Amino `Msg`s](#legacy-amino-msgs), existing `Msg` types should be used as the request parameter for `service` definitions. Newer `Msg` types which only support `service` definitions should use the more canonical `Msg...Request` names.
|
Each `Msg` service method must have exactly one argument, which must implement the `sdk.Msg` interface, and a Protobuf response. The naming convention is to call the RPC argument `Msg<service-rpc-name>` and the RPC response `Msg<service-rpc-name>Response`. For example:
|
||||||
|
```
|
||||||
|
rpc Send(MsgSend) returns (MsgSendResponse);
|
||||||
|
```
|
||||||
|
|
||||||
`Msg` request types need to implement the `MsgRequest` interface which is a simplified version of the `Msg` interface described [below](#legacy-amino-msgs) with only `ValidateBasic()` and `GetSigners()` methods.
|
`sdk.Msg` interface is a simplified version of the Amino `LegacyMsg` interface described [below](#legacy-amino-msgs) with only `ValidateBasic()` and `GetSigners()` methods. For backwards compatibility with [Amino `LegacyMsg`s](#legacy-amino-msgs), existing `LegacyMsg` types should be used as the request parameter for `service` RPC definitions. Newer `sdk.Msg` types, which only support `service` definitions, should use canonical `Msg...` name.
|
||||||
|
|
||||||
Defining such `Msg` services allow to specify return types as part of `Msg` response using the canonical `Msg...Response` names.
|
|
||||||
|
|
||||||
In addition, this generates client and server code.
|
Cosmos SDK uses Protobuf definitions to generate client and server code:
|
||||||
The generated `MsgServer` interface defines the server API for the `Msg` service and its implementation is described as part of the [`Msg` services](./msg-services.md) documentation.
|
* `MsgServer` interface defines the server API for the `Msg` service and its implementation is described as part of the [`Msg` services](./msg-services.md) documentation.
|
||||||
|
* Structures are generated for all RPC request and response types.
|
||||||
|
|
||||||
A `RegisterMsgServer` method is also generated and should be used to register the module's `MsgServer` implementation in `RegisterServices` method from the [`AppModule` interface](./module-manager.md#appmodule).
|
A `RegisterMsgServer` method is also generated and should be used to register the module's `MsgServer` implementation in `RegisterServices` method from the [`AppModule` interface](./module-manager.md#appmodule).
|
||||||
|
|
||||||
In order for clients (CLI and grpc-gateway) to have these URLs registered, the SDK provides the function `RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.ServiceDesc)` that should be called inside module's [`RegisterInterfaces`](module-manager.md#appmodulebasic) method, using the proto-generated `&_Msg_serviceDesc` as `*grpc.ServiceDesc` argument.
|
In order for clients (CLI and grpc-gateway) to have these URLs registered, the SDK provides the function `RegisterMsgServiceDesc(registry codectypes.InterfaceRegistry, sd *grpc.ServiceDesc)` that should be called inside module's [`RegisterInterfaces`](module-manager.md#appmodulebasic) method, using the proto-generated `&_Msg_serviceDesc` as `*grpc.ServiceDesc` argument.
|
||||||
|
|
||||||
### Legacy Amino `Msg`s
|
### Legacy Amino `LegacyMsg`s
|
||||||
|
|
||||||
This way of defining messages is deprecated and using [`Msg` services](#msg-services) is preferred.
|
The following way of defining messages is deprecated and using [`Msg` services](#msg-services) is preferred.
|
||||||
|
|
||||||
Legacy `Msg`s can be defined as protobuf messages. The messages definition usually includes a list of parameters needed to process the message that will be provided by end-users when they want to create a new transaction containing said message.
|
Amino `LegacyMsg`s can be defined as protobuf messages. The messages definition usually includes a list of parameters needed to process the message that will be provided by end-users when they want to create a new transaction containing said message.
|
||||||
|
|
||||||
The `Msg` is typically accompanied by a standard constructor function, that is called from one of the [module's interface](./module-interfaces.md). `message`s also need to implement the `Msg` interface:
|
A `LegacyMsg` is typically accompanied by a standard constructor function, that is called from one of the [module's interface](./module-interfaces.md). `message`s also need to implement the `sdk.Msg` interface:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/4a1b2fba43b1052ca162b3a1e0b6db6db9c26656/types/tx_msg.go#L10-L33
|
+++ https://github.com/cosmos/cosmos-sdk/blob/4a1b2fba43b1052ca162b3a1e0b6db6db9c26656/types/tx_msg.go#L10-L33
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ order: 4
|
||||||
-->
|
-->
|
||||||
# `Msg` Services
|
# `Msg` Services
|
||||||
|
|
||||||
A `Msg` Service processes [messages](./messages-and-queries.md#messages). `Msg` Services are specific to the module in which they are defined, and only process messages defined within the said module. They are called from `BaseApp` during [`DeliverTx`](../core/baseapp.md#delivertx). {synopsis}
|
A Protobuf `Msg` service processes [messages](./messages-and-queries.md#messages). Protobuf `Msg` services are specific to the module in which they are defined, and only process messages defined within the said module. They are called from `BaseApp` during [`DeliverTx`](../core/baseapp.md#delivertx). {synopsis}
|
||||||
|
|
||||||
## Pre-requisite Readings
|
## Pre-requisite Readings
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ A `Msg` Service processes [messages](./messages-and-queries.md#messages). `Msg`
|
||||||
|
|
||||||
## Implementation of a module `Msg` service
|
## Implementation of a module `Msg` service
|
||||||
|
|
||||||
All `Msg` processing is done by a [`Msg`](messages-and-queries.md#msg-services) protobuf service. Each module should define a `Msg` service, which will be responsible for request and response serialization.
|
Each module should define a Protobuf `Msg` service, which will be responsible for processing requests (implementing `sdk.Msg`) and returning responses.
|
||||||
|
|
||||||
As further described in [ADR 031](../architecture/adr-031-msg-service.md), this approach has the advantage of clearly specifying return types and generating server and client code.
|
As further described in [ADR 031](../architecture/adr-031-msg-service.md), this approach has the advantage of clearly specifying return types and generating server and client code.
|
||||||
|
|
||||||
Based on the definition of the `Msg` service, Protobuf generates a `MsgServer` interface. It is the role of the module developer to implement this interface, by implementing the state transition logic that should happen upon receival of each `Msg`. As an example, here is the generated `MsgServer` interface for `x/bank`, which exposes two `Msg`s:
|
Protobuf generates a `MsgServer` interface based on a definition of `Msg` service. It is the role of the module developer to implement this interface, by implementing the state transition logic that should happen upon receival of each `sdk.Msg`. As an example, here is the generated `MsgServer` interface for `x/bank`, which exposes two `sdk.Msg`s:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/x/bank/types/tx.pb.go#L285-L291
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/x/bank/types/tx.pb.go#L285-L291
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ When possible, the existing module's [`Keeper`](keeper.md) should implement `Msg
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/x/bank/keeper/msg_server.go#L27-L28
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc1/x/bank/keeper/msg_server.go#L27-L28
|
||||||
|
|
||||||
`Msg` processing usually follows these 2 steps:
|
`sdk.Msg` processing usually follows these 2 steps:
|
||||||
|
|
||||||
- First, they perform *stateful* checks to make sure the `message` is valid. At this stage, the `message`'s `ValidateBasic()` method has already been called, meaning *stateless* checks on the message (like making sure parameters are correctly formatted) have already been performed. Checks performed in the `msgServer` method can be more expensive and require access to the state. For example, a `msgServer` method for a `transfer` message might check that the sending account has enough funds to actually perform the transfer. To access the state, the `msgServer` method needs to call the [`keeper`'s](./keeper.md) getter functions.
|
- First, they perform *stateful* checks to make sure the `message` is valid. At this stage, the `message`'s `ValidateBasic()` method has already been called, meaning *stateless* checks on the message (like making sure parameters are correctly formatted) have already been performed. Checks performed in the `msgServer` method can be more expensive and require access to the state. For example, a `msgServer` method for a `transfer` message might check that the sending account has enough funds to actually perform the transfer. To access the state, the `msgServer` method needs to call the [`keeper`'s](./keeper.md) getter functions.
|
||||||
- Then, if the checks are successful, the `msgServer` method calls the [`keeper`'s](./keeper.md) setter functions to actually perform the state transition.
|
- Then, if the checks are successful, the `msgServer` method calls the [`keeper`'s](./keeper.md) setter functions to actually perform the state transition.
|
||||||
|
@ -54,11 +54,11 @@ This method takes care of marshaling the `res` parameter to protobuf and attachi
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/base/abci/v1beta1/abci.proto#L81-L95
|
+++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/proto/cosmos/base/abci/v1beta1/abci.proto#L81-L95
|
||||||
|
|
||||||
This diagram shows a typical structure of a `Msg` Service, and how the message propagates through the module.
|
This diagram shows a typical structure of a Protobuf `Msg` service, and how the message propagates through the module.
|
||||||
|
|
||||||
![Transaction flow](../uml/svg/transaction_flow.svg)
|
![Transaction flow](../uml/svg/transaction_flow.svg)
|
||||||
|
|
||||||
## Legacy Amino `Msg`s
|
## Amino `LegacyMsg`s
|
||||||
|
|
||||||
### `handler` type
|
### `handler` type
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ Here is the typical structure of a `handler` function:
|
||||||
|
|
||||||
Let us break it down:
|
Let us break it down:
|
||||||
|
|
||||||
- The [`Msg`](./messages-and-queries.md#messages) is the actual object being processed.
|
- The [`LegacyMsg`](./messages-and-queries.md#messages) is the actual object being processed.
|
||||||
- The [`Context`](../core/context.md) contains all the necessary information needed to process the `msg`, as well as a branch of the latest state. If the `msg` is successfully processed, the branched version of the state contained in the `ctx` will be written to the main state (branch).
|
- The [`Context`](../core/context.md) contains all the necessary information needed to process the `msg`, as well as a branch of the latest state. If the `msg` is successfully processed, the branched version of the state contained in the `ctx` will be written to the main state (branch).
|
||||||
- The `*Result` returned to `BaseApp` contains (among other things) information on the execution of the `handler` and [events](../core/events.md).
|
- The `*Result` returned to `BaseApp` contains (among other things) information on the execution of the `handler` and [events](../core/events.md).
|
||||||
|
|
||||||
|
@ -82,16 +82,17 @@ the manager's `Route()` method simply constructs a Route that calls a `NewHandle
|
||||||
|
|
||||||
### Implementation
|
### Implementation
|
||||||
|
|
||||||
`NewHandler` function dispatches a `Msg` to appropriate handler function, usually by using a switch statement:
|
`NewHandler` function dispatches a `LegacyMsg` to appropriate handler function, usually by using a switch statement:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/bank/handler.go#L13-L29
|
+++ https://github.com/cosmos/cosmos-sdk/blob/d55c1a26657a0af937fa2273b38dcfa1bb3cff9f/x/bank/handler.go#L13-L29
|
||||||
|
|
||||||
First, `NewHandler` function sets a new `EventManager` to the context to isolate events per `msg`.
|
First, `NewHandler` function sets a new `EventManager` to the context to isolate events per `msg`.
|
||||||
Then, a simple switch calls the appropriate `handler` based on the `Msg` type.
|
Then, a simple switch calls the appropriate `handler` based on the `LegacyMsg` type.
|
||||||
|
|
||||||
In this regard, `handler`s functions need to be implemented for each module `Msg`. This will also involve manual handler registration of `Msg` types.
|
In this regard, `handler`s functions need to be implemented for each module `LegacyMsg`. This will also involve manual handler registration of `LegacyMsg` types.
|
||||||
`handler`s functions should return a `*Result` and an `error`.
|
`handler`s functions should return a `*Result` and an `error`.
|
||||||
|
|
||||||
|
|
||||||
## Telemetry
|
## Telemetry
|
||||||
|
|
||||||
New [telemetry metrics](../core/telemetry.md) can be created from `msgServer` methods when handling messages.
|
New [telemetry metrics](../core/telemetry.md) can be created from `msgServer` methods when handling messages.
|
||||||
|
|
|
@ -4,7 +4,7 @@ order: 5
|
||||||
|
|
||||||
# Query Services
|
# Query Services
|
||||||
|
|
||||||
A query service processes [`queries`](./messages-and-queries.md#queries). Query services are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `BaseApp`'s [`Query` method](../core/baseapp.md#query). {synopsis}
|
A Protobuf Query service processes [`queries`](./messages-and-queries.md#queries). Query services are specific to the module in which they are defined, and only process `queries` defined within said module. They are called from `BaseApp`'s [`Query` method](../core/baseapp.md#query). {synopsis}
|
||||||
|
|
||||||
## Pre-requisite Readings
|
## Pre-requisite Readings
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ proto
|
||||||
- `{module_name}.proto`: The module's common message type definitions.
|
- `{module_name}.proto`: The module's common message type definitions.
|
||||||
- `event.proto`: The module's message type definitions related to events.
|
- `event.proto`: The module's message type definitions related to events.
|
||||||
- `genesis.proto`: The module's message type definitions related to genesis state.
|
- `genesis.proto`: The module's message type definitions related to genesis state.
|
||||||
- `query.proto`: The module's service and message type definitions related to the query service.
|
- `query.proto`: The module's Query service and related message type definitions.
|
||||||
- `tx.proto`: The module's service and message type definitions related to the message service.
|
- `tx.proto`: The module's Msg service and related message type definitions.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
x/{module_name}
|
x/{module_name}
|
||||||
|
|
|
@ -60,9 +60,9 @@ First, the important parameters that are initialized during the bootstrapping of
|
||||||
The `CommitMultiStore` is a multi-store, meaning a store of stores. Each module of the application
|
The `CommitMultiStore` is a multi-store, meaning a store of stores. Each module of the application
|
||||||
uses one or multiple `KVStores` in the multi-store to persist their subset of the state.
|
uses one or multiple `KVStores` in the multi-store to persist their subset of the state.
|
||||||
- Database: The `db` is used by the `CommitMultiStore` to handle data persistence.
|
- Database: The `db` is used by the `CommitMultiStore` to handle data persistence.
|
||||||
- [`Msg` Service Router](#msg-service-router): The `msgServiceRouter` facilitates the routing of service `Msg`s to the appropriate
|
- [`Msg` Service Router](#msg-service-router): The `msgServiceRouter` facilitates the routing of `sdk.Msg` requests to the appropriate
|
||||||
module for it to be processed. Here a service `Msg` refers to the transaction components that need to be
|
module `Msg` service for processing. Here a `sdk.Msg` refers to the transaction component that needs to be
|
||||||
processed by the application in order to update the state, and not to ABCI messages which implement
|
processed by a service in order to update the application state, and not to ABCI message which implements
|
||||||
the interface between the application and the underlying consensus engine.
|
the interface between the application and the underlying consensus engine.
|
||||||
- [gRPC Query Router](#grpc-query-router): The `grpcQueryRouter` facilitates the routing of gRPC queries to the
|
- [gRPC Query Router](#grpc-query-router): The `grpcQueryRouter` facilitates the routing of gRPC queries to the
|
||||||
appropriate module for it to be processed. These queries are not ABCI messages themselves, but they
|
appropriate module for it to be processed. These queries are not ABCI messages themselves, but they
|
||||||
|
@ -191,7 +191,7 @@ When messages and queries are received by the application, they must be routed t
|
||||||
|
|
||||||
### `Msg` Service Router
|
### `Msg` Service Router
|
||||||
|
|
||||||
[`Msg`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `BaseApp` holds a `msgServiceRouter` which maps fully-qualified service methods (`string`, defined in each module's `Msg` Protobuf service) to the appropriate module's `Msg` server implementation.
|
[`sdk.Msg`s](#../building-modules/messages-and-queries.md#messages) need to be routed after they are extracted from transactions, which are sent from the underlying Tendermint engine via the [`CheckTx`](#checktx) and [`DeliverTx`](#delivertx) ABCI messages. To do so, `BaseApp` holds a `msgServiceRouter` which maps fully-qualified service methods (`string`, defined in each module's Protobuf `Msg` service) to the appropriate module's `MsgServer` implementation.
|
||||||
|
|
||||||
The [default `msgServiceRouter` included in `BaseApp`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go) is stateless. However, some applications may want to make use of more stateful routing mechanisms such as allowing governance to disable certain routes or point them to new modules for upgrade purposes. For this reason, the `sdk.Context` is also passed into each [route handler inside `msgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go#L31-L32). For a stateless router that doesn't want to make use of this, you can just ignore the `ctx`.
|
The [default `msgServiceRouter` included in `BaseApp`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go) is stateless. However, some applications may want to make use of more stateful routing mechanisms such as allowing governance to disable certain routes or point them to new modules for upgrade purposes. For this reason, the `sdk.Context` is also passed into each [route handler inside `msgServiceRouter`](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc3/baseapp/msg_service_router.go#L31-L32). For a stateless router that doesn't want to make use of this, you can just ignore the `ctx`.
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ The application's `msgServiceRouter` is initialized with all the routes using th
|
||||||
|
|
||||||
### gRPC Query Router
|
### gRPC Query Router
|
||||||
|
|
||||||
Similar to `Msg`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [`Query` service](../building-modules/query-services.md). To do so, `BaseApp` holds a `grpcQueryRouter`, which maps modules' fully-qualified service methods (`string`, defined in their Protobuf `Query` gRPC) to their `Query` server implementation. The `grpcQueryRouter` is called during the initial stages of query processing, which can be either by directly sending a gRPC query to the gRPC endpoint, or via the [`Query` ABCI message](#query) on the Tendermint RPC endpoint.
|
Similar to `sdk.Msg`s, [`queries`](../building-modules/messages-and-queries.md#queries) need to be routed to the appropriate module's [`Query` service](../building-modules/query-services.md). To do so, `BaseApp` holds a `grpcQueryRouter`, which maps modules' fully-qualified service methods (`string`, defined in their Protobuf `Query` gRPC) to their `QueryServer` implementation. The `grpcQueryRouter` is called during the initial stages of query processing, which can be either by directly sending a gRPC query to the gRPC endpoint, or via the [`Query` ABCI message](#query) on the Tendermint RPC endpoint.
|
||||||
|
|
||||||
Just like the `msgServiceRouter`, the `grpcQueryRouter` is initialized with all the query routes using the application's [module manager](../building-modules/module-manager.md) (via the `RegisterServices` method), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor).
|
Just like the `msgServiceRouter`, the `grpcQueryRouter` is initialized with all the query routes using the application's [module manager](../building-modules/module-manager.md) (via the `RegisterServices` method), which itself is initialized with all the application's modules in the application's [constructor](../basics/app-anatomy.md#app-constructor).
|
||||||
|
|
||||||
|
@ -227,18 +227,18 @@ Unconfirmed transactions are relayed to peers only if they pass `CheckTx`.
|
||||||
make them lightweight. In the Cosmos SDK, after [decoding transactions](./encoding.md), `CheckTx()` is implemented
|
make them lightweight. In the Cosmos SDK, after [decoding transactions](./encoding.md), `CheckTx()` is implemented
|
||||||
to do the following checks:
|
to do the following checks:
|
||||||
|
|
||||||
1. Extract the `Msg`s from the transaction.
|
1. Extract the `sdk.Msg`s from the transaction.
|
||||||
2. Perform _stateless_ checks by calling `ValidateBasic()` on each of the `Msg`s. This is done
|
2. Perform _stateless_ checks by calling `ValidateBasic()` on each of the `sdk.Msg`s. This is done
|
||||||
first, as _stateless_ checks are less computationally expensive than _stateful_ checks. If
|
first, as _stateless_ checks are less computationally expensive than _stateful_ checks. If
|
||||||
`ValidateBasic()` fail, `CheckTx` returns before running _stateful_ checks, which saves resources.
|
`ValidateBasic()` fail, `CheckTx` returns before running _stateful_ checks, which saves resources.
|
||||||
3. Perform non-module related _stateful_ checks on the [account](../basics/accounts.md). This step is mainly about checking
|
3. Perform non-module related _stateful_ checks on the [account](../basics/accounts.md). This step is mainly about checking
|
||||||
that the `Msg` signatures are valid, that enough fees are provided and that the sending account
|
that the `sdk.Msg` signatures are valid, that enough fees are provided and that the sending account
|
||||||
has enough funds to pay for said fees. Note that no precise [`gas`](../basics/gas-fees.md) counting occurs here,
|
has enough funds to pay for said fees. Note that no precise [`gas`](../basics/gas-fees.md) counting occurs here,
|
||||||
as `Msg`s are not processed. Usually, the [`AnteHandler`](../basics/gas-fees.md#antehandler) will check that the `gas` provided
|
as `sdk.Msg`s are not processed. Usually, the [`AnteHandler`](../basics/gas-fees.md#antehandler) will check that the `gas` provided
|
||||||
with the transaction is superior to a minimum reference gas amount based on the raw transaction size,
|
with the transaction is superior to a minimum reference gas amount based on the raw transaction size,
|
||||||
in order to avoid spam with transactions that provide 0 gas.
|
in order to avoid spam with transactions that provide 0 gas.
|
||||||
4. Ensure that each `Msg`'s fully-qualified service method matches on of the routes inside the `msgServiceRouter`, but do **not** actually
|
4. Ensure that each `sdk.Msg`'s fully-qualified service method matches on of the routes inside the `msgServiceRouter`, but do **not** actually
|
||||||
process `Msg`s. `Msg`s only need to be processed when the canonical state need to be updated,
|
process `sdk.Msg`s. `sdk.Msg`s only need to be processed when the canonical state need to be updated,
|
||||||
which happens during `DeliverTx`.
|
which happens during `DeliverTx`.
|
||||||
|
|
||||||
Steps 2. and 3. are performed by the [`AnteHandler`](../basics/gas-fees.md#antehandler) in the [`RunTx()`](#runtx-antehandler-and-runmsgs)
|
Steps 2. and 3. are performed by the [`AnteHandler`](../basics/gas-fees.md#antehandler) in the [`RunTx()`](#runtx-antehandler-and-runmsgs)
|
||||||
|
@ -284,7 +284,7 @@ Before the first transaction of a given block is processed, a [volatile state](#
|
||||||
`DeliverTx` performs the **exact same steps as `CheckTx`**, with a little caveat at step 3 and the addition of a fifth step:
|
`DeliverTx` performs the **exact same steps as `CheckTx`**, with a little caveat at step 3 and the addition of a fifth step:
|
||||||
|
|
||||||
1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose.
|
1. The `AnteHandler` does **not** check that the transaction's `gas-prices` is sufficient. That is because the `min-gas-prices` value `gas-prices` is checked against is local to the node, and therefore what is enough for one full-node might not be for another. This means that the proposer can potentially include transactions for free, although they are not incentivised to do so, as they earn a bonus on the total fee of the block they propose.
|
||||||
2. For each `Msg` in the transaction, route to the appropriate module's [`Msg` service](../building-modules/msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `deliverState` `CacheMultiStore`.
|
2. For each `sdk.Msg` in the transaction, route to the appropriate module's Protobuf [`Msg` service](../building-modules/msg-services.md). Additional _stateful_ checks are performed, and the branched multistore held in `deliverState`'s `context` is updated by the module's `keeper`. If the `Msg` service returns successfully, the branched multistore held in `context` is written to `deliverState` `CacheMultiStore`.
|
||||||
|
|
||||||
During the additional fifth step outlined in (2), each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation:
|
During the additional fifth step outlined in (2), each read/write to the store increases the value of `GasConsumed`. You can find the default cost of each operation:
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ At any point, if `GasConsumed > GasWanted`, the function returns with `Code != 0
|
||||||
|
|
||||||
The first thing `RunTx` does upon being called is to retrieve the `context`'s `CacheMultiStore` by calling the `getContextForTx()` function with the appropriate mode (either `runTxModeCheck` or `runTxModeDeliver`). This `CacheMultiStore` is a branch of the main store, with cache functionality (for query requests), instantiated during `BeginBlock` for `DeliverTx` and during the `Commit` of the previous block for `CheckTx`. After that, two `defer func()` are called for [`gas`](../basics/gas-fees.md) management. They are executed when `runTx` returns and make sure `gas` is actually consumed, and will throw errors, if any.
|
The first thing `RunTx` does upon being called is to retrieve the `context`'s `CacheMultiStore` by calling the `getContextForTx()` function with the appropriate mode (either `runTxModeCheck` or `runTxModeDeliver`). This `CacheMultiStore` is a branch of the main store, with cache functionality (for query requests), instantiated during `BeginBlock` for `DeliverTx` and during the `Commit` of the previous block for `CheckTx`. After that, two `defer func()` are called for [`gas`](../basics/gas-fees.md) management. They are executed when `runTx` returns and make sure `gas` is actually consumed, and will throw errors, if any.
|
||||||
|
|
||||||
After that, `RunTx()` calls `ValidateBasic()` on each `Msg`in the `Tx`, which runs preliminary _stateless_ validity checks. If any `Msg` fails to pass `ValidateBasic()`, `RunTx()` returns with an error.
|
After that, `RunTx()` calls `ValidateBasic()` on each `sdk.Msg`in the `Tx`, which runs preliminary _stateless_ validity checks. If any `sdk.Msg` fails to pass `ValidateBasic()`, `RunTx()` returns with an error.
|
||||||
|
|
||||||
Then, the [`anteHandler`](#antehandler) of the application is run (if it exists). In preparation of this step, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
Then, the [`anteHandler`](#antehandler) of the application is run (if it exists). In preparation of this step, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ Then, the [`anteHandler`](#antehandler) of the application is run (if it exists)
|
||||||
|
|
||||||
This allows `RunTx` not to commit the changes made to the state during the execution of `anteHandler` if it ends up failing. It also prevents the module implementing the `anteHandler` from writing to state, which is an important part of the [object-capabilities](./ocap.md) of the Cosmos SDK.
|
This allows `RunTx` not to commit the changes made to the state during the execution of `anteHandler` if it ends up failing. It also prevents the module implementing the `anteHandler` from writing to state, which is an important part of the [object-capabilities](./ocap.md) of the Cosmos SDK.
|
||||||
|
|
||||||
Finally, the [`RunMsgs()`](#runmsgs) function is called to process the `Msg`s in the `Tx`. In preparation of this step, just like with the `anteHandler`, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
Finally, the [`RunMsgs()`](#runmsgs) function is called to process the `sdk.Msg`s in the `Tx`. In preparation of this step, just like with the `anteHandler`, both the `checkState`/`deliverState`'s `context` and `context`'s `CacheMultiStore` are branched using the `cacheTxContext()` function.
|
||||||
|
|
||||||
### AnteHandler
|
### AnteHandler
|
||||||
|
|
||||||
|
@ -339,9 +339,9 @@ Click [here](../basics/gas-fees.md#antehandler) for more on the `anteHandler`.
|
||||||
|
|
||||||
### RunMsgs
|
### RunMsgs
|
||||||
|
|
||||||
`RunMsgs` is called from `RunTx` with `runTxModeCheck` as parameter to check the existence of a route for each message the transaction, and with `runTxModeDeliver` to actually process the `Msg`s.
|
`RunMsgs` is called from `RunTx` with `runTxModeCheck` as parameter to check the existence of a route for each message the transaction, and with `runTxModeDeliver` to actually process the `sdk.Msg`s.
|
||||||
|
|
||||||
First, it retrieves the `Msg`'s fully-qualified service method name, by checking the `type_url` of the Protobuf `Any` representing the service `Msg`. Then, using the application's [`msgServiceRouter`](#msg-service-router), it checks for the existence of this fully-qualified service method. At this point, if `mode == runTxModeCheck`, `RunMsgs` returns. If instead `mode == runTxModeDeliver`, the [`Msg` server](../building-modules/msg-services.md) implementation for the message is executed, before `RunMsgs` returns.
|
First, it retrieves the `sdk.Msg`'s fully-qualified type name, by checking the `type_url` of the Protobuf `Any` representing the `sdk.Msg`. Then, using the application's [`msgServiceRouter`](#msg-service-router), it checks for the existence of `Msg` service method related to that `type_url`. At this point, if `mode == runTxModeCheck`, `RunMsgs` returns. Otherwise, if `mode == runTxModeDeliver`, the [`Msg` service](../building-modules/msg-services.md) RPC is executed, before `RunMsgs` returns.
|
||||||
|
|
||||||
## Other ABCI Messages
|
## Other ABCI Messages
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ To parse the attribute values as strings, make sure to add `'` (single quotes) a
|
||||||
:::
|
:::
|
||||||
|
|
||||||
Events, the `type` and `attributes` are defined on a **per-module basis** in the module's
|
Events, the `type` and `attributes` are defined on a **per-module basis** in the module's
|
||||||
`/types/events.go` file, and triggered from the module's [`Msg` service](../building-modules/msg-services.md)
|
`/types/events.go` file, and triggered from the module's Protobuf [`Msg` service](../building-modules/msg-services.md)
|
||||||
by using the [`EventManager`](#eventmanager). In addition, each module documents its Events under
|
by using the [`EventManager`](#eventmanager). In addition, each module documents its Events under
|
||||||
`spec/xx_events.md`.
|
`spec/xx_events.md`.
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ All routes are configured under the following fields in `~/.simapp/config/app.to
|
||||||
|
|
||||||
If, for various reasons, you cannot use gRPC (for example, you are building a web application, and browsers don't support HTTP2 on which gRPC is built), then the SDK offers REST routes via gRPC-gateway.
|
If, for various reasons, you cannot use gRPC (for example, you are building a web application, and browsers don't support HTTP2 on which gRPC is built), then the SDK offers REST routes via gRPC-gateway.
|
||||||
|
|
||||||
[gRPC-gateway](https://grpc-ecosystem.github.io/grpc-gateway/) is a tool to expose gRPC endpoints as REST endpoints. For each RPC endpoint defined in a Protobuf service, the SDK offers a REST equivalent. For instance, querying a balance could be done via the `/cosmos.bank.v1beta1.Query/AllBalances` gRPC endpoint, or alternatively via the gRPC-gateway `"/cosmos/bank/v1beta1/balances/{address}"` REST endpoint: both will return the same result. For each RPC method defined in a Protobuf service, the corresponding REST endpoint is defined as an option:
|
[gRPC-gateway](https://grpc-ecosystem.github.io/grpc-gateway/) is a tool to expose gRPC endpoints as REST endpoints. For each RPC endpoint defined in a Protobuf service, the SDK offers a REST equivalent. For instance, querying a balance could be done via the `/cosmos.bank.v1beta1.QueryAllBalances` gRPC endpoint, or alternatively via the gRPC-gateway `"/cosmos/bank/v1beta1/balances/{address}"` REST endpoint: both will return the same result. For each RPC method defined in a Protobuf service, the corresponding REST endpoint is defined as an option:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/proto/cosmos/bank/v1beta1/query.proto#L19-L22
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/proto/cosmos/bank/v1beta1/query.proto#L19-L22
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ Independently from the Cosmos SDK, Tendermint also exposes a RPC server. This RP
|
||||||
Some Tendermint RPC endpoints are directly related to the Cosmos SDK:
|
Some Tendermint RPC endpoints are directly related to the Cosmos SDK:
|
||||||
|
|
||||||
- `/abci_query`: this endpoint will query the application for state. As the `path` parameter, you can send the following strings:
|
- `/abci_query`: this endpoint will query the application for state. As the `path` parameter, you can send the following strings:
|
||||||
- any Protobuf fully-qualified service method, such as `/cosmos.bank.v1beta1.Query/AllBalances`. The `data` field should then include the method's request parameter(s) encoded as bytes using Protobuf.
|
- any Protobuf fully-qualified service method, such as `/cosmos.bank.v1beta1.QueryAllBalances`. The `data` field should then include the method's request parameter(s) encoded as bytes using Protobuf.
|
||||||
- `/app/simulate`: this will simulate a transaction, and return some information such as gas used.
|
- `/app/simulate`: this will simulate a transaction, and return some information such as gas used.
|
||||||
- `/app/version`: this will return the application's version.
|
- `/app/version`: this will return the application's version.
|
||||||
- `/store/{path}`: this will query the store directly.
|
- `/store/{path}`: this will query the store directly.
|
||||||
|
|
|
@ -12,9 +12,9 @@ order: 2
|
||||||
|
|
||||||
## Transactions
|
## Transactions
|
||||||
|
|
||||||
Transactions are comprised of metadata held in [contexts](./context.md) and [`Msg`s](../building-modules/messages-and-queries.md) that trigger state changes within a module through the module's [`Msg` service](../building-modules/msg-services.md).
|
Transactions are comprised of metadata held in [contexts](./context.md) and [`sdk.Msg`s](../building-modules/messages-and-queries.md) that trigger state changes within a module through the module's Protobuf [`Msg` service](../building-modules/msg-services.md).
|
||||||
|
|
||||||
When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Each of a transaction's `Msg`s must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A transaction must then be included in a block, validated, and approved by the network through the consensus process. To read more about the lifecycle of a transaction, click [here](../basics/tx-lifecycle.md).
|
When users want to interact with an application and make state changes (e.g. sending coins), they create transactions. Each of a transaction's `sdk.Msg` must be signed using the private key associated with the appropriate account(s), before the transaction is broadcasted to the network. A transaction must then be included in a block, validated, and approved by the network through the consensus process. To read more about the lifecycle of a transaction, click [here](../basics/tx-lifecycle.md).
|
||||||
|
|
||||||
## Type Definition
|
## Type Definition
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@ Transaction objects are SDK types that implement the `Tx` interface
|
||||||
|
|
||||||
It contains the following methods:
|
It contains the following methods:
|
||||||
|
|
||||||
- **GetMsgs:** unwraps the transaction and returns a list of its `Msg`s - one transaction may have one or multiple [`Msg`s](../building-modules/messages-and-queries.md#messages), which are defined by module developers.
|
- **GetMsgs:** unwraps the transaction and returns a list of contained `sdk.Msg`s - one transaction may have one or multiple messages, which are defined by module developers.
|
||||||
- **ValidateBasic:** includes lightweight, [_stateless_](../basics/tx-lifecycle.md#types-of-checks) checks used by ABCI messages [`CheckTx`](./baseapp.md#checktx) and [`DeliverTx`](./baseapp.md#delivertx) to make sure transactions are not invalid. For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth) module's `StdTx` `ValidateBasic` function checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from the `ValidateBasic` functions for `Msg`s, which perform basic validity checks on messages only. For example, when [`runTx`](./baseapp.md#runtx) is checking a transaction created from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module, it first runs `ValidateBasic` on each message, then runs the `auth` module AnteHandler which calls `ValidateBasic` for the transaction itself.
|
- **ValidateBasic:** includes lightweight, [_stateless_](../basics/tx-lifecycle.md#types-of-checks) checks used by ABCI messages [`CheckTx`](./baseapp.md#checktx) and [`DeliverTx`](./baseapp.md#delivertx) to make sure transactions are not invalid. For example, the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth) module's `StdTx` `ValidateBasic` function checks that its transactions are signed by the correct number of signers and that the fees do not exceed what the user's maximum. Note that this function is to be distinct from the `ValidateBasic` functions for `sdk.Msg`s, which perform basic validity checks on messages only. For example, when [`runTx`](./baseapp.md#runtx) is checking a transaction created from the [`auth`](https://github.com/cosmos/cosmos-sdk/tree/master/x/auth/spec) module, it first runs `ValidateBasic` on each message, then runs the `auth` module AnteHandler which calls `ValidateBasic` for the transaction itself.
|
||||||
|
|
||||||
As a developer, you should rarely manipulate `Tx` directly, as `Tx` is really an intermediate type used for transaction generation. Instead, developers should prefer the `TxBuilder` interface, which you can learn more about [below](#transaction-generation).
|
As a developer, you should rarely manipulate `Tx` directly, as `Tx` is really an intermediate type used for transaction generation. Instead, developers should prefer the `TxBuilder` interface, which you can learn more about [below](#transaction-generation).
|
||||||
|
|
||||||
|
@ -74,14 +74,15 @@ The next paragraphs will describe each of these components, in this order.
|
||||||
### Messages
|
### Messages
|
||||||
|
|
||||||
::: tip
|
::: tip
|
||||||
Module `Msg`s are not to be confused with [ABCI Messages](https://tendermint.com/docs/spec/abci/abci.html#messages) which define interactions between the Tendermint and application layers.
|
Module `sdk.Msg`s are not to be confused with [ABCI Messages](https://tendermint.com/docs/spec/abci/abci.html#messages) which define interactions between the Tendermint and application layers.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
**Messages** (or `Msg`s) are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the messages for their module by adding methods to the Protobuf [`Msg` service](../building-modules/msg-services.md), and also implement the corresponding `MsgServer`.
|
**Messages** (or `sdk.Msg`s) are module-specific objects that trigger state transitions within the scope of the module they belong to. Module developers define the messages for their module by adding methods to the Protobuf [`Msg` service](../building-modules/msg-services.md), and also implement the corresponding `MsgServer`.
|
||||||
|
|
||||||
`Msg`s in a module are defined as methods in the [`Msg` service] inside each module's `tx.proto` file. Since `Msg`s are module-specific, each module needs a to process all of its message types and trigger state changes within the module's scope. This design puts more responsibility on module developers, allowing application developers to reuse common functionalities without having to implement state transition logic repetitively. To achieve this, Protobuf generates a `MsgServer` interface for each module, and the module developer needs to implement this interface. The methods on the `MsgServer` interface corresponds on how to handle each of the different `Msg`.
|
Each `sdk.Msg`s is related to exactly one Protobuf [`Msg` service](../building-modules/msg-services.md) RPC, defined inside each module's `tx.proto` file. An SKD app router automatically maps every `sdk.Msg` to a corresponding RPC. Protobuf generates a `MsgServer` interface for each module `Msg` service, and the module developer needs to implement this interface.
|
||||||
|
This design puts more responsibility on module developers, allowing application developers to reuse common functionalities without having to implement state transition logic repetitively.
|
||||||
|
|
||||||
To learn more about `Msg` services and how to implement `MsgServer`, click [here](../building-modules/msg-services.md).
|
To learn more about Protobuf `Msg` services and how to implement `MsgServer`, click [here](../building-modules/msg-services.md).
|
||||||
|
|
||||||
While messages contain the information for state transition logic, a transaction's other metadata and relevant information are stored in the `TxBuilder` and `Context`.
|
While messages contain the information for state transition logic, a transaction's other metadata and relevant information are stored in the `TxBuilder` and `Context`.
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ Note that **Tendermint only handles transaction bytes**. It has no knowledge of
|
||||||
Here are the most important messages of the ABCI:
|
Here are the most important messages of the ABCI:
|
||||||
|
|
||||||
- `CheckTx`: When a transaction is received by Tendermint Core, it is passed to the application to check if a few basic requirements are met. `CheckTx` is used to protect the mempool of full-nodes against spam transactions. A special handler called the [`AnteHandler`](../basics/gas-fees.md#antehandler) is used to execute a series of validation steps such as checking for sufficient fees and validating the signatures. If the checks are valid, the transaction is added to the [mempool](https://docs.tendermint.com/v0.34/tendermint-core/mempool.html#mempool) and relayed to peer nodes. Note that transactions are not processed (i.e. no modification of the state occurs) with `CheckTx` since they have not been included in a block yet.
|
- `CheckTx`: When a transaction is received by Tendermint Core, it is passed to the application to check if a few basic requirements are met. `CheckTx` is used to protect the mempool of full-nodes against spam transactions. A special handler called the [`AnteHandler`](../basics/gas-fees.md#antehandler) is used to execute a series of validation steps such as checking for sufficient fees and validating the signatures. If the checks are valid, the transaction is added to the [mempool](https://docs.tendermint.com/v0.34/tendermint-core/mempool.html#mempool) and relayed to peer nodes. Note that transactions are not processed (i.e. no modification of the state occurs) with `CheckTx` since they have not been included in a block yet.
|
||||||
- `DeliverTx`: When a [valid block](https://docs.tendermint.com/v0.34/spec/blockchain/blockchain.html#validation) is received by Tendermint Core, each transaction in the block is passed to the application via `DeliverTx` in order to be processed. It is during this stage that the state transitions occur. The `AnteHandler` executes again along with the actual [`Msg` service methods](../building-modules/msg-services.md) for each message in the transaction.
|
- `DeliverTx`: When a [valid block](https://docs.tendermint.com/v0.34/spec/blockchain/blockchain.html#validation) is received by Tendermint Core, each transaction in the block is passed to the application via `DeliverTx` in order to be processed. It is during this stage that the state transitions occur. The `AnteHandler` executes again along with the actual [`Msg` service](../building-modules/msg-services.md) RPC for each message in the transaction.
|
||||||
- `BeginBlock`/`EndBlock`: These messages are executed at the beginning and the end of each block, whether the block contains transaction or not. It is useful to trigger automatic execution of logic. Proceed with caution though, as computationally expensive loops could slow down your blockchain, or even freeze it if the loop is infinite.
|
- `BeginBlock`/`EndBlock`: These messages are executed at the beginning and the end of each block, whether the block contains transaction or not. It is useful to trigger automatic execution of logic. Proceed with caution though, as computationally expensive loops could slow down your blockchain, or even freeze it if the loop is infinite.
|
||||||
|
|
||||||
Find a more detailed view of the ABCI methods from the [Tendermint docs](https://docs.tendermint.com/v0.34/spec/abci/abci.html#overview).
|
Find a more detailed view of the ABCI methods from the [Tendermint docs](https://docs.tendermint.com/v0.34/spec/abci/abci.html#overview).
|
||||||
|
|
|
@ -77,7 +77,7 @@ Cosmos SDK v0.40 uses Protobuf services to define state transitions (`Msg`s) and
|
||||||
|
|
||||||
#### `Msg` Service
|
#### `Msg` Service
|
||||||
|
|
||||||
For migrating `Msg`s, the handler pattern (inside the `handler.go` file) is deprecated. You may still keep it if you wish to support `Msg`s defined in older versions of the SDK. However, it is strongly recommended to add a `Msg` service to your Protobuf files, and each old `Msg` should be converted into a service method. Taking [x/bank's](../../x/bank/spec/README.md) `MsgSend` as an example, we have a corresponding `cosmos.bank.v1beta1.Msg/Send` service method:
|
The handler pattern (inside the `handler.go` file) for handling `Msg`s is deprecated. You may still keep it if you wish to support `Msg`s defined in pre-Stargate versions of the SDK. However, it is strongly recommended to add a `Msg` service to your Protobuf files, and each old `Msg` handler should be converted into a service method. Taking [x/bank's](../../x/bank/spec/README.md) `MsgSend` as an example, we have a corresponding `/cosmos.bank.v1beta1.MsgSend` RPC:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/bank/v1beta1/tx.proto#L10-L31
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/bank/v1beta1/tx.proto#L10-L31
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ For more information, please check our [`Msg` service guide](../building-modules
|
||||||
|
|
||||||
#### `Query` Service
|
#### `Query` Service
|
||||||
|
|
||||||
For migrating state queries, the querier pattern (inside the `querier.go` file) is deprecated. You may still keep this file to support legacy queries, but it is strongly recommended to use a Protobuf `Query` service to handle state queries.
|
The querier pattern (inside the `querier.go` file) for handling state queries is deprecated. You may still keep this file to support legacy queries, but it is strongly recommended to use a Protobuf `Query` service to handle state queries.
|
||||||
|
|
||||||
Each query endpoint is now defined as a separate service method in the `Query` service. Still taking `x/bank` as an example, here are the queries to fetch an account's balances:
|
Each query endpoint is now defined as a separate service method in the `Query` service. Still taking `x/bank` as an example, here are the queries to fetch an account's balances:
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ If you wish to expose your `Query` endpoints as REST endpoints (as proposed in t
|
||||||
|
|
||||||
If you still use Amino (which is deprecated since Stargate), you must register related types using the `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)` method (previously it was called `RegisterCodec(cdc *codec.Codec)`).
|
If you still use Amino (which is deprecated since Stargate), you must register related types using the `RegisterLegacyAminoCodec(cdc *codec.LegacyAmino)` method (previously it was called `RegisterCodec(cdc *codec.Codec)`).
|
||||||
|
|
||||||
Moreover, a new `RegisterInterfaces` method has been added to the `AppModule` interface that all modules must implement. This method must register the interfaces that Protobuf messages implement, as well as the service `Msg`s used in the module. An example from x/bank is given below:
|
Moreover, a new `RegisterInterfaces` method has been added to the `AppModule` interface that all modules must implement. This method must register the interfaces that Protobuf messages implement, as well as the service request `Msg`s used in the module. An example from x/bank is given below:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/x/bank/types/codec.go#L21-L34
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/x/bank/types/codec.go#L21-L34
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ We described in the [modules migration section](#updating-modules) `Query` and `
|
||||||
- the [Tx Service](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/tx/v1beta1/service.proto), to perform operations on transactions,
|
- the [Tx Service](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/tx/v1beta1/service.proto), to perform operations on transactions,
|
||||||
- the [Tendermint service](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/base/tendermint/v1beta1/query.proto), to have a more idiomatic interface to the [Tendermint RPC](https://docs.tendermint.com/master/rpc/).
|
- the [Tendermint service](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/proto/cosmos/base/tendermint/v1beta1/query.proto), to have a more idiomatic interface to the [Tendermint RPC](https://docs.tendermint.com/master/rpc/).
|
||||||
|
|
||||||
These services are optional, if you wish to use them, or if you wish to add more module-agnostic Protobuf services into your app, then you need to add them inside `app.go`:
|
These services are optional. To use them, or if you wish to add more module-agnostic Protobuf services into your app, you need to register them inside `app.go`:
|
||||||
|
|
||||||
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/simapp/app.go#L577-L585
|
+++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0-rc6/simapp/app.go#L577-L585
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
Package rosetta implements the rosetta API for the current cosmos sdk release series.
|
Package rosetta implements the rosetta API for the current cosmos sdk release series.
|
||||||
|
|
||||||
The client satisfies [cosmos-rosetta-gateway](https://github.com/tendermint/cosmos-rosetta-gateway) `Client` interface implementation.
|
|
||||||
|
|
||||||
## Extension
|
## Extension
|
||||||
|
|
||||||
There are two ways in which you can customize and extend the implementation with your custom settings.
|
There are two ways in which you can customize and extend the implementation with your custom settings.
|
||||||
|
@ -24,7 +22,7 @@ import (
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"github.com/coinbase/rosetta-sdk-go/types"
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
"github.com/cosmos/cosmos-sdk/server/rosetta/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CustomClient embeds the standard cosmos client
|
// CustomClient embeds the standard cosmos client
|
||||||
|
@ -48,7 +46,7 @@ Example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
package custom_errors
|
package custom_errors
|
||||||
import crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
import crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
|
||||||
var customErrRetriable = true
|
var customErrRetriable = true
|
||||||
var CustomError = crgerrs.RegisterError(100, "custom message", customErrRetriable, "description")
|
var CustomError = crgerrs.RegisterError(100, "custom message", customErrRetriable, "description")
|
||||||
|
|
7
go.mod
7
go.mod
|
@ -4,11 +4,11 @@ module github.com/cosmos/cosmos-sdk
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/keyring v1.1.6
|
github.com/99designs/keyring v1.1.6
|
||||||
github.com/armon/go-metrics v0.3.7
|
github.com/armon/go-metrics v0.3.8
|
||||||
github.com/bgentry/speakeasy v0.1.0
|
github.com/bgentry/speakeasy v0.1.0
|
||||||
github.com/btcsuite/btcd v0.21.0-beta
|
github.com/btcsuite/btcd v0.21.0-beta
|
||||||
github.com/btcsuite/btcutil v1.0.2
|
github.com/btcsuite/btcutil v1.0.2
|
||||||
github.com/coinbase/rosetta-sdk-go v0.5.9
|
github.com/coinbase/rosetta-sdk-go v0.6.10
|
||||||
github.com/confio/ics23/go v0.6.6
|
github.com/confio/ics23/go v0.6.6
|
||||||
github.com/cosmos/go-bip39 v1.0.0
|
github.com/cosmos/go-bip39 v1.0.0
|
||||||
github.com/cosmos/iavl v0.16.0
|
github.com/cosmos/iavl v0.16.0
|
||||||
|
@ -19,7 +19,6 @@ require (
|
||||||
github.com/gogo/protobuf v1.3.3
|
github.com/gogo/protobuf v1.3.3
|
||||||
github.com/golang/mock v1.4.4
|
github.com/golang/mock v1.4.4
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/golang/snappy v0.0.2 // indirect
|
|
||||||
github.com/gorilla/handlers v1.5.1
|
github.com/gorilla/handlers v1.5.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||||
|
@ -46,12 +45,12 @@ require (
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tendermint/btcd v0.1.1
|
github.com/tendermint/btcd v0.1.1
|
||||||
github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df
|
|
||||||
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
|
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15
|
||||||
github.com/tendermint/go-amino v0.16.0
|
github.com/tendermint/go-amino v0.16.0
|
||||||
github.com/tendermint/tendermint v0.34.10
|
github.com/tendermint/tendermint v0.34.10
|
||||||
github.com/tendermint/tm-db v0.6.4
|
github.com/tendermint/tm-db v0.6.4
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f
|
google.golang.org/genproto v0.0.0-20210114201628-6edceaf6022f
|
||||||
google.golang.org/grpc v1.37.0
|
google.golang.org/grpc v1.37.0
|
||||||
google.golang.org/protobuf v1.26.0
|
google.golang.org/protobuf v1.26.0
|
||||||
|
|
53
go.sum
53
go.sum
|
@ -46,6 +46,7 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrd
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI=
|
github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9abU0yMQt0NI=
|
||||||
github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
|
github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
|
||||||
|
github.com/Zilliqa/gozilliqa-sdk v1.2.1-0.20201201074141-dd0ecada1be6/go.mod h1:eSYp2T6f0apnuW8TzhV3f6Aff2SE8Dwio++U4ha4yEM=
|
||||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
@ -61,8 +62,8 @@ github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-metrics v0.3.7 h1:c/oCtWzYpboy6+6f6LjXRlyW7NwA2SWf+a9KMlHq/bM=
|
github.com/armon/go-metrics v0.3.8 h1:oOxq3KPj0WhCuy50EhzwiyMyG2ovRQZpZLXQuOh2a/M=
|
||||||
github.com/armon/go-metrics v0.3.7/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
github.com/armon/go-metrics v0.3.8/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
|
||||||
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
|
||||||
|
@ -78,11 +79,13 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
|
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
|
||||||
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
|
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
|
||||||
|
github.com/btcsuite/btcd v0.0.0-20190315201642-aa6e0f35703c/go.mod h1:DrZx5ec/dmnfpw9KyYoQyYo7d0KEvTkk/5M/vbZjAr8=
|
||||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||||
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=
|
github.com/btcsuite/btcd v0.21.0-beta h1:At9hIZdJW0s9E/fAz28nrz6AmcNlSVucCH796ZteX1M=
|
||||||
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
|
github.com/btcsuite/btcd v0.21.0-beta/go.mod h1:ZSWyehm27aAuS9bvkATT+Xte3hjHZ+MRgMY/8NJ7K94=
|
||||||
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
|
||||||
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
|
github.com/btcsuite/btcutil v0.0.0-20190207003914-4c204d697803/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
|
||||||
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
github.com/btcsuite/btcutil v1.0.2 h1:9iZ1Terx9fMIOtq1VrwdqfsATL9MC2l8ZrUY6YZ2uts=
|
||||||
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
github.com/btcsuite/btcutil v1.0.2/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts=
|
||||||
|
@ -108,9 +111,8 @@ github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||||
github.com/coinbase/rosetta-sdk-go v0.5.8/go.mod h1:xd4wYUhV3LkY78SPH8BUhc88rXfn2jYgN9BfiSjbcvM=
|
github.com/coinbase/rosetta-sdk-go v0.6.10 h1:rgHD/nHjxLh0lMEdfGDqpTtlvtSBwULqrrZ2qPdNaCM=
|
||||||
github.com/coinbase/rosetta-sdk-go v0.5.9 h1:CuGQE3HFmYwdEACJnuOtVI9cofqPsGvq6FdFIzaOPKI=
|
github.com/coinbase/rosetta-sdk-go v0.6.10/go.mod h1:J/JFMsfcePrjJZkwQFLh+hJErkAmdm9Iyy3D5Y0LfXo=
|
||||||
github.com/coinbase/rosetta-sdk-go v0.5.9/go.mod h1:xd4wYUhV3LkY78SPH8BUhc88rXfn2jYgN9BfiSjbcvM=
|
|
||||||
github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
github.com/confio/ics23/go v0.0.0-20200817220745-f173e6211efb/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
||||||
github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
github.com/confio/ics23/go v0.6.3/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg=
|
||||||
github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8=
|
github.com/confio/ics23/go v0.6.6 h1:pkOy18YxxJ/r0XFDCnrl4Bjv6h4LkBSpLS6F38mrKL8=
|
||||||
|
@ -180,7 +182,7 @@ github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 h1:2vLKys4RBU4
|
||||||
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25/go.mod h1:hTr8+TLQmkUkgcuh3mcr5fjrT9c64ZzsBCdCEC6UppY=
|
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25/go.mod h1:hTr8+TLQmkUkgcuh3mcr5fjrT9c64ZzsBCdCEC6UppY=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/ethereum/go-ethereum v1.9.23/go.mod h1:JIfVb6esrqALTExdz9hRYvrP0xBDf6wCncIu1hNwHpM=
|
github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
|
||||||
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||||
|
@ -189,7 +191,7 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQD
|
||||||
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||||
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
|
||||||
|
@ -266,9 +268,8 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.2-0.20200707131729-196ae77b8a26/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3 h1:ur2rms48b3Ep1dxh7aUV2FZEQ8jEVO2F6ILKx8ofkAg=
|
||||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
@ -292,6 +293,7 @@ github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OI
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
@ -376,6 +378,7 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||||
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
|
||||||
|
github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU=
|
||||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jhump/protoreflect v1.8.2 h1:k2xE7wcUomeqwY0LDCYA16y4WWfyTcMx5mKhk0d4ua0=
|
github.com/jhump/protoreflect v1.8.2 h1:k2xE7wcUomeqwY0LDCYA16y4WWfyTcMx5mKhk0d4ua0=
|
||||||
|
@ -430,15 +433,12 @@ github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaW
|
||||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||||
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
|
||||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
@ -482,6 +482,7 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE
|
||||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||||
|
github.com/neilotoole/errgroup v0.1.5/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
|
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
|
||||||
|
@ -611,6 +612,7 @@ github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZ
|
||||||
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4=
|
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4=
|
||||||
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
|
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
|
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
|
||||||
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
@ -663,6 +665,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
@ -674,8 +677,6 @@ github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzH
|
||||||
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
||||||
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
|
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
|
||||||
github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
|
github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
|
||||||
github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df h1:hoMLrOS4WyyMM+Y+iWdGu94o0zzp6Q43y7v89Q1/OIw=
|
|
||||||
github.com/tendermint/cosmos-rosetta-gateway v0.3.0-rc2.0.20210304154332-87d6ca4410df/go.mod h1:gBPw8WV2Erm4UGHlBRiM3zaEBst4bsuihmMCNQdgP/s=
|
|
||||||
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI=
|
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI=
|
||||||
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
|
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
|
||||||
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
|
github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E=
|
||||||
|
@ -689,14 +690,15 @@ github.com/tendermint/tm-db v0.6.2/go.mod h1:GYtQ67SUvATOcoY8/+x6ylk8Qo02BQyLrAs
|
||||||
github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8=
|
github.com/tendermint/tm-db v0.6.3/go.mod h1:lfA1dL9/Y/Y8wwyPp2NMLyn5P5Ptr/gvDFNWtrCWSf8=
|
||||||
github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ=
|
github.com/tendermint/tm-db v0.6.4 h1:3N2jlnYQkXNQclQwd/eKV/NzlqPlfK21cpRRIx80XXQ=
|
||||||
github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw=
|
github.com/tendermint/tm-db v0.6.4/go.mod h1:dptYhIpJ2M5kUuenLr+Yyf3zQOv1SgBZcl8/BmWlMBw=
|
||||||
github.com/tidwall/gjson v1.6.1/go.mod h1:BaHyNc5bjzYkPqgLq7mdVzeiRtULKULXLgZFKsxEHI0=
|
github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI=
|
||||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tidwall/sjson v1.1.2/go.mod h1:SEzaDwxiPzKzNfUEO4HbYF/m4UCSJDsGgNqsS1LvdoY=
|
github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
|
github.com/tyler-smith/go-bip39 v1.0.2/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||||
|
@ -705,11 +707,12 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs
|
||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
||||||
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/vmihailenco/msgpack/v5 v5.0.0-beta.9/go.mod h1:HVxBVPUK/+fZMonk4bi1islLa8V3cfnBug0+4dykPzo=
|
github.com/vmihailenco/msgpack/v5 v5.1.4/go.mod h1:C5gboKD0TJPqWDTVTtrQNfRbiBwHZGo8UTqP/9/XvLI=
|
||||||
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI=
|
||||||
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
|
github.com/ybbus/jsonrpc v2.1.2+incompatible/go.mod h1:XJrh1eMSzdIYFbM08flv0wp5G35eRniyeGut1z+LSiE=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
@ -738,10 +741,12 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
@ -833,7 +838,6 @@ golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -864,13 +868,13 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/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-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
|
|
||||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -992,9 +996,8 @@ 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.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -16,7 +16,7 @@ message GenesisState {
|
||||||
repeated SigningInfo signing_infos = 2
|
repeated SigningInfo signing_infos = 2
|
||||||
[(gogoproto.moretags) = "yaml:\"signing_infos\"", (gogoproto.nullable) = false];
|
[(gogoproto.moretags) = "yaml:\"signing_infos\"", (gogoproto.nullable) = false];
|
||||||
|
|
||||||
// signing_infos represents a map between validator addresses and their
|
// missed_blocks represents a map between validator addresses and their
|
||||||
// missed blocks.
|
// missed blocks.
|
||||||
repeated ValidatorMissedBlocks missed_blocks = 3
|
repeated ValidatorMissedBlocks missed_blocks = 3
|
||||||
[(gogoproto.moretags) = "yaml:\"missed_blocks\"", (gogoproto.nullable) = false];
|
[(gogoproto.moretags) = "yaml:\"missed_blocks\"", (gogoproto.nullable) = false];
|
||||||
|
|
|
@ -5,10 +5,9 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RosettaCommand builds the rosetta root command given
|
// RosettaCommand builds the rosetta root command given
|
||||||
|
|
|
@ -5,7 +5,8 @@ import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
||||||
"github.com/coinbase/rosetta-sdk-go/types"
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
|
||||||
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,8 +18,8 @@ import (
|
||||||
"github.com/tendermint/tendermint/rpc/client/http"
|
"github.com/tendermint/tendermint/rpc/client/http"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types"
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
|
||||||
|
|
|
@ -7,7 +7,8 @@ import (
|
||||||
|
|
||||||
"github.com/coinbase/rosetta-sdk-go/types"
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
crg "github.com/tendermint/cosmos-rosetta-gateway/server"
|
|
||||||
|
crg "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
|
|
@ -11,17 +11,19 @@ import (
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec"
|
"github.com/btcsuite/btcd/btcec"
|
||||||
crgtypes "github.com/tendermint/cosmos-rosetta-gateway/types"
|
|
||||||
tmcoretypes "github.com/tendermint/tendermint/rpc/core/types"
|
tmcoretypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
|
||||||
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
|
|
||||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
|
||||||
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
|
||||||
sdkclient "github.com/cosmos/cosmos-sdk/client"
|
sdkclient "github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
@ -251,7 +253,7 @@ func (c converter) Ops(status string, msg sdk.Msg) ([]*rosettatypes.Operation, e
|
||||||
for i, signer := range msg.GetSigners() {
|
for i, signer := range msg.GetSigners() {
|
||||||
op := &rosettatypes.Operation{
|
op := &rosettatypes.Operation{
|
||||||
Type: opName,
|
Type: opName,
|
||||||
Status: status,
|
Status: &status,
|
||||||
Account: &rosettatypes.AccountIdentifier{Address: signer.String()},
|
Account: &rosettatypes.AccountIdentifier{Address: signer.String()},
|
||||||
Metadata: meta,
|
Metadata: meta,
|
||||||
}
|
}
|
||||||
|
@ -395,7 +397,7 @@ func sdkEventToBalanceOperations(status string, event abci.Event) (operations []
|
||||||
|
|
||||||
op := &rosettatypes.Operation{
|
op := &rosettatypes.Operation{
|
||||||
Type: event.Type,
|
Type: event.Type,
|
||||||
Status: status,
|
Status: &status,
|
||||||
Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier},
|
Account: &rosettatypes.AccountIdentifier{Address: accountIdentifier},
|
||||||
Amount: &rosettatypes.Amount{
|
Amount: &rosettatypes.Amount{
|
||||||
Value: value,
|
Value: value,
|
||||||
|
@ -520,7 +522,7 @@ func (c converter) SyncStatus(status *tmcoretypes.ResultStatus) *rosettatypes.Sy
|
||||||
}
|
}
|
||||||
|
|
||||||
return &rosettatypes.SyncStatus{
|
return &rosettatypes.SyncStatus{
|
||||||
CurrentIndex: status.SyncInfo.LatestBlockHeight,
|
CurrentIndex: &status.SyncInfo.LatestBlockHeight,
|
||||||
TargetIndex: nil, // sync info does not allow us to get target height
|
TargetIndex: nil, // sync info does not allow us to get target height
|
||||||
Stage: &stage,
|
Stage: &stage,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
|
@ -17,7 +15,9 @@ import (
|
||||||
|
|
||||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||||
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
// errors.go contains all the errors returned by the adapter implementation
|
||||||
|
// plus some extra utilities to parse those errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
grpccodes "google.golang.org/grpc/codes"
|
||||||
|
grpcstatus "google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ListErrors lists all the registered errors
|
||||||
|
func ListErrors() []*types.Error {
|
||||||
|
return registry.list()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SealAndListErrors seals the registry and lists its errors
|
||||||
|
func SealAndListErrors() []*types.Error {
|
||||||
|
registry.seal()
|
||||||
|
return registry.list()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error defines an error that can be converted to a Rosetta API error.
|
||||||
|
type Error struct {
|
||||||
|
rosErr *types.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Error) Error() string {
|
||||||
|
if e.rosErr == nil {
|
||||||
|
return ErrUnknown.Error()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("rosetta: (%d) %s", e.rosErr.Code, e.rosErr.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is implements errors.Is for *Error, two errors are considered equal
|
||||||
|
// if their error codes are identical
|
||||||
|
func (e *Error) Is(err error) bool {
|
||||||
|
// assert it can be casted
|
||||||
|
rosErr, ok := err.(*Error)
|
||||||
|
if rosErr == nil || !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// check that both *Error's are correctly initialized to avoid dereference panics
|
||||||
|
if rosErr.rosErr == nil || e.rosErr == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// messages are equal if their error codes match
|
||||||
|
return rosErr.rosErr.Code == e.rosErr.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapError wraps the rosetta error with additional context
|
||||||
|
func WrapError(err *Error, msg string) *Error {
|
||||||
|
return &Error{rosErr: &types.Error{
|
||||||
|
Code: err.rosErr.Code,
|
||||||
|
Message: err.rosErr.Message,
|
||||||
|
Description: err.rosErr.Description,
|
||||||
|
Retriable: err.rosErr.Retriable,
|
||||||
|
Details: map[string]interface{}{
|
||||||
|
"info": msg,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToRosetta attempts to converting an error into a rosetta
|
||||||
|
// error, if the error cannot be converted it will be parsed as unknown
|
||||||
|
func ToRosetta(err error) *types.Error {
|
||||||
|
// if it's null or not known
|
||||||
|
rosErr, ok := err.(*Error)
|
||||||
|
if rosErr == nil || !ok {
|
||||||
|
return ToRosetta(WrapError(ErrUnknown, ErrUnknown.Error()))
|
||||||
|
}
|
||||||
|
return rosErr.rosErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromGRPCToRosettaError converts a gRPC error to rosetta error
|
||||||
|
func FromGRPCToRosettaError(err error) *Error {
|
||||||
|
status, ok := grpcstatus.FromError(err)
|
||||||
|
if !ok {
|
||||||
|
return WrapError(ErrUnknown, err.Error())
|
||||||
|
}
|
||||||
|
switch status.Code() {
|
||||||
|
case grpccodes.NotFound:
|
||||||
|
return WrapError(ErrNotFound, status.Message())
|
||||||
|
case grpccodes.FailedPrecondition:
|
||||||
|
return WrapError(ErrBadArgument, status.Message())
|
||||||
|
case grpccodes.InvalidArgument:
|
||||||
|
return WrapError(ErrBadArgument, status.Message())
|
||||||
|
case grpccodes.Internal:
|
||||||
|
return WrapError(ErrInternal, status.Message())
|
||||||
|
default:
|
||||||
|
return WrapError(ErrUnknown, status.Message())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterError(code int32, message string, retryable bool, description string) *Error {
|
||||||
|
e := &Error{rosErr: &types.Error{
|
||||||
|
Code: code,
|
||||||
|
Message: message,
|
||||||
|
Description: &description,
|
||||||
|
Retriable: retryable,
|
||||||
|
Details: nil,
|
||||||
|
}}
|
||||||
|
registry.add(e)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default error list
|
||||||
|
var (
|
||||||
|
// ErrUnknown defines an unknown error, if this is returned it means
|
||||||
|
// the library is ignoring an error
|
||||||
|
ErrUnknown = RegisterError(0, "unknown", false, "unknown error")
|
||||||
|
// ErrOffline is returned when there is an attempt to query an endpoint in offline mode
|
||||||
|
ErrOffline = RegisterError(1, "cannot query endpoint in offline mode", false, "returned when querying an online endpoint in offline mode")
|
||||||
|
// ErrNetworkNotSupported is returned when there is an attempt to query a network which is not supported
|
||||||
|
ErrNetworkNotSupported = RegisterError(2, "network is not supported", false, "returned when querying a non supported network")
|
||||||
|
// ErrCodec is returned when there's an error while marshalling or unmarshalling data
|
||||||
|
ErrCodec = RegisterError(3, "encode/decode error", true, "returned when there are errors encoding or decoding information to and from the node")
|
||||||
|
// ErrInvalidOperation is returned when the operation supplied to rosetta is not a valid one
|
||||||
|
ErrInvalidOperation = RegisterError(4, "invalid operation", false, "returned when the operation is not valid")
|
||||||
|
// ErrInvalidTransaction is returned when the provided hex bytes of a TX are not valid
|
||||||
|
ErrInvalidTransaction = RegisterError(5, "invalid transaction", false, "returned when the transaction is invalid")
|
||||||
|
// ErrInvalidAddress is returned when the byte of the address are bad
|
||||||
|
ErrInvalidAddress = RegisterError(7, "invalid address", false, "returned when the address is malformed")
|
||||||
|
// ErrInvalidPubkey is returned when the public key is invalid
|
||||||
|
ErrInvalidPubkey = RegisterError(8, "invalid pubkey", false, "returned when the public key is invalid")
|
||||||
|
// ErrInterpreting is returned when there are errors interpreting the data from the node, most likely related to breaking changes, version incompatibilities
|
||||||
|
ErrInterpreting = RegisterError(9, "error interpreting data from node", false, "returned when there are issues interpreting requests or response from node")
|
||||||
|
ErrInvalidMemo = RegisterError(11, "invalid memo", false, "returned when the memo is invalid")
|
||||||
|
// ErrBadArgument is returned when the request is malformed
|
||||||
|
ErrBadArgument = RegisterError(400, "bad argument", false, "request is malformed")
|
||||||
|
// ErrNotFound is returned when the required object was not found
|
||||||
|
// retry is set to true because something that is not found now
|
||||||
|
// might be found later, example: a TX
|
||||||
|
ErrNotFound = RegisterError(404, "not found", true, "returned when the node does not find what the client is asking for")
|
||||||
|
// ErrInternal is returned when the node is experiencing internal errors
|
||||||
|
ErrInternal = RegisterError(500, "internal error", false, "returned when the node experiences internal errors")
|
||||||
|
// ErrBadGateway is returned when there are problems interacting with the nodes
|
||||||
|
ErrBadGateway = RegisterError(502, "bad gateway", true, "return when the node is unreachable")
|
||||||
|
// ErrNotImplemented is returned when a method is not implemented yet
|
||||||
|
ErrNotImplemented = RegisterError(14, "not implemented", false, "returned when querying an endpoint which is not implemented")
|
||||||
|
// ErrUnsupportedCurve is returned when the curve specified is not supported
|
||||||
|
ErrUnsupportedCurve = RegisterError(15, "unsupported curve, expected secp256k1", false, "returned when using an unsupported crypto curve")
|
||||||
|
)
|
|
@ -0,0 +1,68 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegisterError(t *testing.T) {
|
||||||
|
var error *Error
|
||||||
|
// this is the number of errors registered by default in errors.go
|
||||||
|
registeredErrorsCount := 16
|
||||||
|
assert.Equal(t, len(registry.list()), registeredErrorsCount)
|
||||||
|
assert.ElementsMatch(t, registry.list(), ListErrors())
|
||||||
|
// add a new Error
|
||||||
|
error = RegisterError(69, "nice!", false, "nice!")
|
||||||
|
assert.NotNil(t, error)
|
||||||
|
// now we have a new error
|
||||||
|
registeredErrorsCount++
|
||||||
|
assert.Equal(t, len(ListErrors()), registeredErrorsCount)
|
||||||
|
// re-register an error should not change anything
|
||||||
|
error = RegisterError(69, "nice!", false, "nice!")
|
||||||
|
assert.Equal(t, len(ListErrors()), registeredErrorsCount)
|
||||||
|
|
||||||
|
// test sealing
|
||||||
|
assert.Equal(t, registry.sealed, false)
|
||||||
|
errors := SealAndListErrors()
|
||||||
|
assert.Equal(t, registry.sealed, true)
|
||||||
|
assert.Equal(t, len(errors), registeredErrorsCount)
|
||||||
|
// add a new error on a sealed registry
|
||||||
|
error = RegisterError(1024, "bytes", false, "bytes")
|
||||||
|
assert.NotNil(t, error)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestError_Error(t *testing.T) {
|
||||||
|
var error *Error
|
||||||
|
// nil cases
|
||||||
|
assert.False(t, ErrOffline.Is(error))
|
||||||
|
error = &Error{}
|
||||||
|
assert.False(t, ErrOffline.Is(error))
|
||||||
|
// wrong type
|
||||||
|
assert.False(t, ErrOffline.Is(&MyError{}))
|
||||||
|
// test with wrapping an error
|
||||||
|
error = WrapError(ErrOffline, "offline")
|
||||||
|
assert.True(t, ErrOffline.Is(error))
|
||||||
|
|
||||||
|
// test equality
|
||||||
|
assert.False(t, ErrOffline.Is(ErrBadGateway))
|
||||||
|
assert.True(t, ErrBadGateway.Is(ErrBadGateway))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToRosetta(t *testing.T) {
|
||||||
|
var error *Error
|
||||||
|
// nil case
|
||||||
|
assert.NotNil(t, ToRosetta(error))
|
||||||
|
// wrong type
|
||||||
|
assert.NotNil(t, ToRosetta(&MyError{}))
|
||||||
|
}
|
||||||
|
|
||||||
|
type MyError struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MyError) Error() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (e *MyError) Is(err error) bool {
|
||||||
|
return true
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type errorRegistry struct {
|
||||||
|
mu *sync.RWMutex
|
||||||
|
sealed bool
|
||||||
|
errors map[int32]*types.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *errorRegistry) add(err *Error) {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
if r.sealed {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register errors after seal will be ignored")
|
||||||
|
}
|
||||||
|
if _, ok := r.errors[err.rosErr.Code]; ok {
|
||||||
|
_, _ = fmt.Fprintln(os.Stderr, "[ROSETTA] WARNING: attempts to register an already registered error will be ignored, code: ", err.rosErr.Code)
|
||||||
|
}
|
||||||
|
r.errors[err.rosErr.Code] = err.rosErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r errorRegistry) list() []*types.Error {
|
||||||
|
r.mu.RLock()
|
||||||
|
defer r.mu.RUnlock()
|
||||||
|
rosErrs := make([]*types.Error, 0, len(registry.errors))
|
||||||
|
for _, v := range r.errors {
|
||||||
|
rosErrs = append(rosErrs, v)
|
||||||
|
}
|
||||||
|
return rosErrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *errorRegistry) seal() {
|
||||||
|
r.mu.Lock()
|
||||||
|
defer r.mu.Unlock()
|
||||||
|
r.sealed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var registry = errorRegistry{
|
||||||
|
mu: new(sync.RWMutex),
|
||||||
|
errors: make(map[int32]*types.Error),
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConstructionCombine Combine creates a network-specific transaction from an unsigned transaction
|
||||||
|
// and an array of provided signatures. The signed transaction returned from this method will be
|
||||||
|
// sent to the /construction/submit endpoint by the caller.
|
||||||
|
func (on OnlineNetwork) ConstructionCombine(ctx context.Context, request *types.ConstructionCombineRequest) (*types.ConstructionCombineResponse, *types.Error) {
|
||||||
|
txBytes, err := hex.DecodeString(request.UnsignedTransaction)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
signedTx, err := on.client.SignedTx(ctx, txBytes, request.Signatures)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ConstructionCombineResponse{
|
||||||
|
SignedTransaction: hex.EncodeToString(signedTx),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionDerive Derive returns the AccountIdentifier associated with a public key.
|
||||||
|
func (on OnlineNetwork) ConstructionDerive(_ context.Context, request *types.ConstructionDeriveRequest) (*types.ConstructionDeriveResponse, *types.Error) {
|
||||||
|
account, err := on.client.AccountIdentifierFromPublicKey(request.PublicKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
return &types.ConstructionDeriveResponse{
|
||||||
|
AccountIdentifier: account,
|
||||||
|
Metadata: nil,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionHash TransactionHash returns the network-specific transaction hash for a signed
|
||||||
|
// transaction.
|
||||||
|
func (on OnlineNetwork) ConstructionHash(ctx context.Context, request *types.ConstructionHashRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||||
|
bz, err := hex.DecodeString(request.SignedTransaction)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(errors.WrapError(errors.ErrInvalidTransaction, "error decoding tx"))
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := sha256.Sum256(bz)
|
||||||
|
bzHash := hash[:]
|
||||||
|
hashString := hex.EncodeToString(bzHash)
|
||||||
|
|
||||||
|
return &types.TransactionIdentifierResponse{
|
||||||
|
TransactionIdentifier: &types.TransactionIdentifier{
|
||||||
|
Hash: strings.ToUpper(hashString),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionMetadata Get any information required to construct a transaction for a specific
|
||||||
|
// network (i.e. ChainID, Gas, Memo, ...).
|
||||||
|
func (on OnlineNetwork) ConstructionMetadata(ctx context.Context, request *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) {
|
||||||
|
metadata, err := on.client.ConstructionMetadataFromOptions(ctx, request.Options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.ConstructionMetadataResponse{
|
||||||
|
Metadata: metadata,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionParse Parse is called on both unsigned and signed transactions to understand the
|
||||||
|
// intent of the formulated transaction. This is run as a sanity check before signing (after
|
||||||
|
// /construction/payloads) and before broadcast (after /construction/combine).
|
||||||
|
func (on OnlineNetwork) ConstructionParse(ctx context.Context, request *types.ConstructionParseRequest) (*types.ConstructionParseResponse, *types.Error) {
|
||||||
|
txBytes, err := hex.DecodeString(request.Transaction)
|
||||||
|
if err != nil {
|
||||||
|
err := errors.WrapError(errors.ErrInvalidTransaction, err.Error())
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
ops, signers, err := on.client.TxOperationsAndSignersAccountIdentifiers(request.Signed, txBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
return &types.ConstructionParseResponse{
|
||||||
|
Operations: ops,
|
||||||
|
AccountIdentifierSigners: signers,
|
||||||
|
Metadata: nil,
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionPayloads Payloads is called with an array of operations and the response from
|
||||||
|
// /construction/metadata. It returns an unsigned transaction blob and a collection of payloads that
|
||||||
|
// must be signed by particular AccountIdentifiers using a certain SignatureType.
|
||||||
|
func (on OnlineNetwork) ConstructionPayloads(ctx context.Context, request *types.ConstructionPayloadsRequest) (*types.ConstructionPayloadsResponse, *types.Error) {
|
||||||
|
payload, err := on.client.ConstructionPayload(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
return payload, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionPreprocess Preprocess is called prior to /construction/payloads to construct a
|
||||||
|
// request for any metadata that is needed for transaction construction given (i.e. account nonce).
|
||||||
|
func (on OnlineNetwork) ConstructionPreprocess(ctx context.Context, request *types.ConstructionPreprocessRequest) (*types.ConstructionPreprocessResponse, *types.Error) {
|
||||||
|
options, err := on.client.PreprocessOperationsToOptions(ctx, request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return options, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionSubmit Submit a pre-signed transaction to the node. This call does not block on the
|
||||||
|
// transaction being included in a block. Rather, it returns immediately with an indication of
|
||||||
|
// whether or not the transaction was included in the mempool.
|
||||||
|
func (on OnlineNetwork) ConstructionSubmit(ctx context.Context, request *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||||
|
txBytes, err := hex.DecodeString(request.SignedTransaction)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, meta, err := on.client.PostTx(txBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.TransactionIdentifierResponse{
|
||||||
|
TransactionIdentifier: res,
|
||||||
|
Metadata: meta,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AccountBalance retrieves the account balance of an address
|
||||||
|
// rosetta requires us to fetch the block information too
|
||||||
|
func (on OnlineNetwork) AccountBalance(ctx context.Context, request *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) {
|
||||||
|
var (
|
||||||
|
height int64
|
||||||
|
block crgtypes.BlockResponse
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case request.BlockIdentifier == nil:
|
||||||
|
block, err = on.client.BlockByHeight(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
case request.BlockIdentifier.Hash != nil:
|
||||||
|
block, err = on.client.BlockByHash(ctx, *request.BlockIdentifier.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
height = block.Block.Index
|
||||||
|
case request.BlockIdentifier.Index != nil:
|
||||||
|
height = *request.BlockIdentifier.Index
|
||||||
|
block, err = on.client.BlockByHeight(ctx, &height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
accountCoins, err := on.client.Balances(ctx, request.AccountIdentifier.Address, &height)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.AccountBalanceResponse{
|
||||||
|
BlockIdentifier: block.Block,
|
||||||
|
Balances: accountCoins,
|
||||||
|
Metadata: nil,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block gets the transactions in the given block
|
||||||
|
func (on OnlineNetwork) Block(ctx context.Context, request *types.BlockRequest) (*types.BlockResponse, *types.Error) {
|
||||||
|
var (
|
||||||
|
blockResponse crgtypes.BlockTransactionsResponse
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
// block identifier is assumed not to be nil as rosetta will do this check for us
|
||||||
|
// check if we have to query via hash or block number
|
||||||
|
switch {
|
||||||
|
case request.BlockIdentifier.Hash != nil:
|
||||||
|
blockResponse, err = on.client.BlockTransactionsByHash(ctx, *request.BlockIdentifier.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
case request.BlockIdentifier.Index != nil:
|
||||||
|
blockResponse, err = on.client.BlockTransactionsByHeight(ctx, request.BlockIdentifier.Index)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err := errors.WrapError(errors.ErrBadArgument, "at least one of hash or index needs to be specified")
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.BlockResponse{
|
||||||
|
Block: &types.Block{
|
||||||
|
BlockIdentifier: blockResponse.Block,
|
||||||
|
ParentBlockIdentifier: blockResponse.ParentBlock,
|
||||||
|
Timestamp: blockResponse.MillisecondTimestamp,
|
||||||
|
Transactions: blockResponse.Transactions,
|
||||||
|
Metadata: nil,
|
||||||
|
},
|
||||||
|
OtherTransactions: nil,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BlockTransaction gets the given transaction in the specified block, we do not need to check the block itself too
|
||||||
|
// due to the fact that tendermint achieves instant finality
|
||||||
|
func (on OnlineNetwork) BlockTransaction(ctx context.Context, request *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) {
|
||||||
|
tx, err := on.client.GetTx(ctx, request.TransactionIdentifier.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.BlockTransactionResponse{
|
||||||
|
Transaction: tx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mempool fetches the transactions contained in the mempool
|
||||||
|
func (on OnlineNetwork) Mempool(ctx context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) {
|
||||||
|
txs, err := on.client.Mempool(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.MempoolResponse{
|
||||||
|
TransactionIdentifiers: txs,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MempoolTransaction fetches a single transaction in the mempool
|
||||||
|
// NOTE: it is not implemented yet
|
||||||
|
func (on OnlineNetwork) MempoolTransaction(ctx context.Context, request *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) {
|
||||||
|
tx, err := on.client.GetUnconfirmedTx(ctx, request.TransactionIdentifier.Hash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.MempoolTransactionResponse{
|
||||||
|
Transaction: tx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (on OnlineNetwork) NetworkList(_ context.Context, _ *types.MetadataRequest) (*types.NetworkListResponse, *types.Error) {
|
||||||
|
return &types.NetworkListResponse{NetworkIdentifiers: []*types.NetworkIdentifier{on.network}}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (on OnlineNetwork) NetworkOptions(_ context.Context, _ *types.NetworkRequest) (*types.NetworkOptionsResponse, *types.Error) {
|
||||||
|
return on.networkOptions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (on OnlineNetwork) NetworkStatus(ctx context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) {
|
||||||
|
block, err := on.client.BlockByHeight(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
peers, err := on.client.Peers(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
syncStatus, err := on.client.Status(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.ToRosetta(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.NetworkStatusResponse{
|
||||||
|
CurrentBlockIdentifier: block.Block,
|
||||||
|
CurrentBlockTimestamp: block.MillisecondTimestamp,
|
||||||
|
GenesisBlockIdentifier: on.genesisBlockIdentifier,
|
||||||
|
OldestBlockIdentifier: nil,
|
||||||
|
SyncStatus: syncStatus,
|
||||||
|
Peers: peers,
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
|
||||||
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewOffline instantiates the instance of an offline network
|
||||||
|
// whilst the offline network does not support the DataAPI,
|
||||||
|
// it supports a subset of the construction API.
|
||||||
|
func NewOffline(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) {
|
||||||
|
return OfflineNetwork{
|
||||||
|
OnlineNetwork{
|
||||||
|
client: client,
|
||||||
|
network: network,
|
||||||
|
networkOptions: networkOptionsFromClient(client),
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OfflineNetwork implements an offline data API
|
||||||
|
// which is basically a data API that constantly
|
||||||
|
// returns errors, because it cannot be used if offline
|
||||||
|
type OfflineNetwork struct {
|
||||||
|
OnlineNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement DataAPI in offline mode, which means no method is available
|
||||||
|
func (o OfflineNetwork) AccountBalance(_ context.Context, _ *types.AccountBalanceRequest) (*types.AccountBalanceResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) Block(_ context.Context, _ *types.BlockRequest) (*types.BlockResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) BlockTransaction(_ context.Context, _ *types.BlockTransactionRequest) (*types.BlockTransactionResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) Mempool(_ context.Context, _ *types.NetworkRequest) (*types.MempoolResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) MempoolTransaction(_ context.Context, _ *types.MempoolTransactionRequest) (*types.MempoolTransactionResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) NetworkStatus(_ context.Context, _ *types.NetworkRequest) (*types.NetworkStatusResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) ConstructionSubmit(_ context.Context, _ *types.ConstructionSubmitRequest) (*types.TransactionIdentifierResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OfflineNetwork) ConstructionMetadata(_ context.Context, _ *types.ConstructionMetadataRequest) (*types.ConstructionMetadataResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
|
||||||
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// genesisBlockFetchTimeout defines a timeout to fetch the genesis block
|
||||||
|
const genesisBlockFetchTimeout = 15 * time.Second
|
||||||
|
|
||||||
|
// NewOnlineNetwork builds a single network adapter.
|
||||||
|
// It will get the Genesis block on the beginning to avoid calling it everytime.
|
||||||
|
func NewOnlineNetwork(network *types.NetworkIdentifier, client crgtypes.Client) (crgtypes.API, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), genesisBlockFetchTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var genesisHeight int64 = 1
|
||||||
|
block, err := client.BlockByHeight(ctx, &genesisHeight)
|
||||||
|
if err != nil {
|
||||||
|
return OnlineNetwork{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return OnlineNetwork{
|
||||||
|
client: client,
|
||||||
|
network: network,
|
||||||
|
networkOptions: networkOptionsFromClient(client),
|
||||||
|
genesisBlockIdentifier: block.Block,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnlineNetwork groups together all the components required for the full rosetta implementation
|
||||||
|
type OnlineNetwork struct {
|
||||||
|
client crgtypes.Client // used to query cosmos app + tendermint
|
||||||
|
|
||||||
|
network *types.NetworkIdentifier // identifies the network, it's static
|
||||||
|
networkOptions *types.NetworkOptionsResponse // identifies the network options, it's static
|
||||||
|
|
||||||
|
genesisBlockIdentifier *types.BlockIdentifier // identifies genesis block, it's static
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountsCoins - relevant only for UTXO based chain
|
||||||
|
// see https://www.rosetta-api.org/docs/AccountApi.html#accountcoins
|
||||||
|
func (o OnlineNetwork) AccountCoins(_ context.Context, _ *types.AccountCoinsRequest) (*types.AccountCoinsResponse, *types.Error) {
|
||||||
|
return nil, crgerrs.ToRosetta(crgerrs.ErrOffline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// networkOptionsFromClient builds network options given the client
|
||||||
|
func networkOptionsFromClient(client crgtypes.Client) *types.NetworkOptionsResponse {
|
||||||
|
return &types.NetworkOptionsResponse{
|
||||||
|
Version: &types.Version{
|
||||||
|
RosettaVersion: crgtypes.SpecVersion,
|
||||||
|
NodeVersion: client.Version(),
|
||||||
|
},
|
||||||
|
Allow: &types.Allow{
|
||||||
|
OperationStatuses: client.OperationStatuses(),
|
||||||
|
OperationTypes: client.SupportedOperations(),
|
||||||
|
Errors: crgerrs.SealAndListErrors(),
|
||||||
|
HistoricalBalanceLookup: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,116 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
assert "github.com/coinbase/rosetta-sdk-go/asserter"
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/server"
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta/lib/internal/service"
|
||||||
|
crgtypes "github.com/cosmos/cosmos-sdk/server/rosetta/lib/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const DefaultRetries = 5
|
||||||
|
const DefaultRetryWait = 5 * time.Second
|
||||||
|
|
||||||
|
// Settings define the rosetta server settings
|
||||||
|
type Settings struct {
|
||||||
|
// Network contains the information regarding the network
|
||||||
|
Network *types.NetworkIdentifier
|
||||||
|
// Client is the online API handler
|
||||||
|
Client crgtypes.Client
|
||||||
|
// Listen is the address the handler will listen at
|
||||||
|
Listen string
|
||||||
|
// Offline defines if the rosetta service should be exposed in offline mode
|
||||||
|
Offline bool
|
||||||
|
// Retries is the number of readiness checks that will be attempted when instantiating the handler
|
||||||
|
// valid only for online API
|
||||||
|
Retries int
|
||||||
|
// RetryWait is the time that will be waited between retries
|
||||||
|
RetryWait time.Duration
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
h http.Handler
|
||||||
|
addr string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Server) Start() error {
|
||||||
|
return http.ListenAndServe(h.addr, h.h)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(settings Settings) (Server, error) {
|
||||||
|
asserter, err := assert.NewServer(
|
||||||
|
settings.Client.SupportedOperations(),
|
||||||
|
true,
|
||||||
|
[]*types.NetworkIdentifier{settings.Network},
|
||||||
|
nil,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return Server{}, fmt.Errorf("cannot build asserter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
adapter crgtypes.API
|
||||||
|
)
|
||||||
|
switch settings.Offline {
|
||||||
|
case true:
|
||||||
|
adapter, err = newOfflineAdapter(settings)
|
||||||
|
case false:
|
||||||
|
adapter, err = newOnlineAdapter(settings)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return Server{}, err
|
||||||
|
}
|
||||||
|
h := server.NewRouter(
|
||||||
|
server.NewAccountAPIController(adapter, asserter),
|
||||||
|
server.NewBlockAPIController(adapter, asserter),
|
||||||
|
server.NewNetworkAPIController(adapter, asserter),
|
||||||
|
server.NewMempoolAPIController(adapter, asserter),
|
||||||
|
server.NewConstructionAPIController(adapter, asserter),
|
||||||
|
)
|
||||||
|
|
||||||
|
return Server{
|
||||||
|
h: h,
|
||||||
|
addr: settings.Listen,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOfflineAdapter(settings Settings) (crgtypes.API, error) {
|
||||||
|
if settings.Client == nil {
|
||||||
|
return nil, fmt.Errorf("client is nil")
|
||||||
|
}
|
||||||
|
return service.NewOffline(settings.Network, settings.Client)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newOnlineAdapter(settings Settings) (crgtypes.API, error) {
|
||||||
|
if settings.Client == nil {
|
||||||
|
return nil, fmt.Errorf("client is nil")
|
||||||
|
}
|
||||||
|
if settings.Retries <= 0 {
|
||||||
|
settings.Retries = DefaultRetries
|
||||||
|
}
|
||||||
|
if settings.RetryWait == 0 {
|
||||||
|
settings.RetryWait = DefaultRetryWait
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
err = settings.Client.Bootstrap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < settings.Retries; i++ {
|
||||||
|
err = settings.Client.Ready()
|
||||||
|
if err != nil {
|
||||||
|
time.Sleep(settings.RetryWait)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return service.NewOnlineNetwork(settings.Network, settings.Client)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("maximum number of retries exceeded, last error: %w", err)
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/server"
|
||||||
|
"github.com/coinbase/rosetta-sdk-go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SpecVersion defines the specification of rosetta
|
||||||
|
const SpecVersion = ""
|
||||||
|
|
||||||
|
// NetworkInformationProvider defines the interface used to provide information regarding
|
||||||
|
// the network and the version of the cosmos sdk used
|
||||||
|
type NetworkInformationProvider interface {
|
||||||
|
// SupportedOperations lists the operations supported by the implementation
|
||||||
|
SupportedOperations() []string
|
||||||
|
// OperationStatuses returns the list of statuses supported by the implementation
|
||||||
|
OperationStatuses() []*types.OperationStatus
|
||||||
|
// Version returns the version of the node
|
||||||
|
Version() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client defines the API the client implementation should provide.
|
||||||
|
type Client interface {
|
||||||
|
// Bootstrap Needed if the client needs to perform some action before connecting.
|
||||||
|
Bootstrap() error
|
||||||
|
// Ready checks if the servicer constraints for queries are satisfied
|
||||||
|
// for example the node might still not be ready, it's useful in process
|
||||||
|
// when the rosetta instance might come up before the node itself
|
||||||
|
// the servicer must return nil if the node is ready
|
||||||
|
Ready() error
|
||||||
|
|
||||||
|
// Data API
|
||||||
|
|
||||||
|
// Balances fetches the balance of the given address
|
||||||
|
// if height is not nil, then the balance will be displayed
|
||||||
|
// at the provided height, otherwise last block balance will be returned
|
||||||
|
Balances(ctx context.Context, addr string, height *int64) ([]*types.Amount, error)
|
||||||
|
// BlockByHash gets a block and its transaction at the provided height
|
||||||
|
BlockByHash(ctx context.Context, hash string) (BlockResponse, error)
|
||||||
|
// BlockByHeight gets a block given its height, if height is nil then last block is returned
|
||||||
|
BlockByHeight(ctx context.Context, height *int64) (BlockResponse, error)
|
||||||
|
// BlockTransactionsByHash gets the block, parent block and transactions
|
||||||
|
// given the block hash.
|
||||||
|
BlockTransactionsByHash(ctx context.Context, hash string) (BlockTransactionsResponse, error)
|
||||||
|
// BlockTransactionsByHeight gets the block, parent block and transactions
|
||||||
|
// given the block hash.
|
||||||
|
BlockTransactionsByHeight(ctx context.Context, height *int64) (BlockTransactionsResponse, error)
|
||||||
|
// GetTx gets a transaction given its hash
|
||||||
|
GetTx(ctx context.Context, hash string) (*types.Transaction, error)
|
||||||
|
// GetUnconfirmedTx gets an unconfirmed Tx given its hash
|
||||||
|
// NOTE(fdymylja): NOT IMPLEMENTED YET!
|
||||||
|
GetUnconfirmedTx(ctx context.Context, hash string) (*types.Transaction, error)
|
||||||
|
// Mempool returns the list of the current non confirmed transactions
|
||||||
|
Mempool(ctx context.Context) ([]*types.TransactionIdentifier, error)
|
||||||
|
// Peers gets the peers currently connected to the node
|
||||||
|
Peers(ctx context.Context) ([]*types.Peer, error)
|
||||||
|
// Status returns the node status, such as sync data, version etc
|
||||||
|
Status(ctx context.Context) (*types.SyncStatus, error)
|
||||||
|
|
||||||
|
// Construction API
|
||||||
|
|
||||||
|
// PostTx posts txBytes to the node and returns the transaction identifier plus metadata related
|
||||||
|
// to the transaction itself.
|
||||||
|
PostTx(txBytes []byte) (res *types.TransactionIdentifier, meta map[string]interface{}, err error)
|
||||||
|
// ConstructionMetadataFromOptions builds metadata map from an option map
|
||||||
|
ConstructionMetadataFromOptions(ctx context.Context, options map[string]interface{}) (meta map[string]interface{}, err error)
|
||||||
|
OfflineClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// OfflineClient defines the functionalities supported without having access to the node
|
||||||
|
type OfflineClient interface {
|
||||||
|
NetworkInformationProvider
|
||||||
|
// SignedTx returns the signed transaction given the tx bytes (msgs) plus the signatures
|
||||||
|
SignedTx(ctx context.Context, txBytes []byte, sigs []*types.Signature) (signedTxBytes []byte, err error)
|
||||||
|
// TxOperationsAndSignersAccountIdentifiers returns the operations related to a transaction and the account
|
||||||
|
// identifiers if the transaction is signed
|
||||||
|
TxOperationsAndSignersAccountIdentifiers(signed bool, hexBytes []byte) (ops []*types.Operation, signers []*types.AccountIdentifier, err error)
|
||||||
|
// ConstructionPayload returns the construction payload given the request
|
||||||
|
ConstructionPayload(ctx context.Context, req *types.ConstructionPayloadsRequest) (resp *types.ConstructionPayloadsResponse, err error)
|
||||||
|
// PreprocessOperationsToOptions returns the options given the preprocess operations
|
||||||
|
PreprocessOperationsToOptions(ctx context.Context, req *types.ConstructionPreprocessRequest) (resp *types.ConstructionPreprocessResponse, err error)
|
||||||
|
// AccountIdentifierFromPublicKey returns the account identifier given the public key
|
||||||
|
AccountIdentifierFromPublicKey(pubKey *types.PublicKey) (*types.AccountIdentifier, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockTransactionsResponse struct {
|
||||||
|
BlockResponse
|
||||||
|
Transactions []*types.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
type BlockResponse struct {
|
||||||
|
Block *types.BlockIdentifier
|
||||||
|
ParentBlock *types.BlockIdentifier
|
||||||
|
MillisecondTimestamp int64
|
||||||
|
TxCount int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// API defines the exposed APIs
|
||||||
|
// if the service is online
|
||||||
|
type API interface {
|
||||||
|
DataAPI
|
||||||
|
ConstructionAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataAPI defines the full data API implementation
|
||||||
|
type DataAPI interface {
|
||||||
|
server.NetworkAPIServicer
|
||||||
|
server.AccountAPIServicer
|
||||||
|
server.BlockAPIServicer
|
||||||
|
server.MempoolAPIServicer
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ server.ConstructionAPIServicer = ConstructionAPI(nil)
|
||||||
|
|
||||||
|
// ConstructionAPI defines the full construction API with
|
||||||
|
// the online and offline endpoints
|
||||||
|
type ConstructionAPI interface {
|
||||||
|
ConstructionOnlineAPI
|
||||||
|
ConstructionOfflineAPI
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionOnlineAPI defines the construction methods
|
||||||
|
// allowed in an online implementation
|
||||||
|
type ConstructionOnlineAPI interface {
|
||||||
|
ConstructionMetadata(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionMetadataRequest,
|
||||||
|
) (*types.ConstructionMetadataResponse, *types.Error)
|
||||||
|
ConstructionSubmit(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionSubmitRequest,
|
||||||
|
) (*types.TransactionIdentifierResponse, *types.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConstructionOfflineAPI defines the construction methods
|
||||||
|
// allowed
|
||||||
|
type ConstructionOfflineAPI interface {
|
||||||
|
ConstructionCombine(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionCombineRequest,
|
||||||
|
) (*types.ConstructionCombineResponse, *types.Error)
|
||||||
|
ConstructionDerive(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionDeriveRequest,
|
||||||
|
) (*types.ConstructionDeriveResponse, *types.Error)
|
||||||
|
ConstructionHash(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionHashRequest,
|
||||||
|
) (*types.TransactionIdentifierResponse, *types.Error)
|
||||||
|
ConstructionParse(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionParseRequest,
|
||||||
|
) (*types.ConstructionParseResponse, *types.Error)
|
||||||
|
ConstructionPayloads(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionPayloadsRequest,
|
||||||
|
) (*types.ConstructionPayloadsResponse, *types.Error)
|
||||||
|
ConstructionPreprocess(
|
||||||
|
context.Context,
|
||||||
|
*types.ConstructionPreprocessRequest,
|
||||||
|
) (*types.ConstructionPreprocessResponse, *types.Error)
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
crgerrs "github.com/tendermint/cosmos-rosetta-gateway/errors"
|
crgerrs "github.com/cosmos/cosmos-sdk/server/rosetta/lib/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// timeToMilliseconds converts time to milliseconds timestamp
|
// timeToMilliseconds converts time to milliseconds timestamp
|
||||||
|
|
|
@ -9,14 +9,11 @@ import (
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
||||||
crgserver "github.com/tendermint/cosmos-rosetta-gateway/server"
|
|
||||||
"github.com/tendermint/tendermint/abci/server"
|
"github.com/tendermint/tendermint/abci/server"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
tmos "github.com/tendermint/tendermint/libs/os"
|
tmos "github.com/tendermint/tendermint/libs/os"
|
||||||
|
@ -26,6 +23,9 @@ import (
|
||||||
"github.com/tendermint/tendermint/proxy"
|
"github.com/tendermint/tendermint/proxy"
|
||||||
"github.com/tendermint/tendermint/rpc/client/local"
|
"github.com/tendermint/tendermint/rpc/client/local"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||||
|
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
"github.com/cosmos/cosmos-sdk/server/api"
|
"github.com/cosmos/cosmos-sdk/server/api"
|
||||||
|
|
|
@ -78,6 +78,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
|
func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) {
|
||||||
|
cfg := sdk.GetConfig()
|
||||||
|
cfg.Seal()
|
||||||
|
|
||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome),
|
genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome),
|
||||||
genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome),
|
genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome),
|
||||||
|
|
|
@ -64,11 +64,13 @@ type Metrics struct {
|
||||||
prometheusEnabled bool
|
prometheusEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GatherResponse is the response type of registered metrics
|
||||||
type GatherResponse struct {
|
type GatherResponse struct {
|
||||||
Metrics []byte
|
Metrics []byte
|
||||||
ContentType string
|
ContentType string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of Metrics
|
||||||
func New(cfg Config) (*Metrics, error) {
|
func New(cfg Config) (*Metrics, error) {
|
||||||
if !cfg.Enabled {
|
if !cfg.Enabled {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
@ -13,6 +13,7 @@ const (
|
||||||
MetricLabelNameModule = "module"
|
MetricLabelNameModule = "module"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewLabel creates a new instance of Label with name and value
|
||||||
func NewLabel(name, value string) metrics.Label {
|
func NewLabel(name, value string) metrics.Label {
|
||||||
return metrics.Label{Name: name, Value: value}
|
return metrics.Label{Name: name, Value: value}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
|
|
||||||
const flagLong = "long"
|
const flagLong = "long"
|
||||||
|
|
||||||
|
// NewVersionCommand returns a CLI command to interactively print the application binary version information.
|
||||||
func NewVersionCommand() *cobra.Command {
|
func NewVersionCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "version",
|
Use: "version",
|
||||||
|
|
|
@ -31,7 +31,7 @@ type AccountKeeperI interface {
|
||||||
// Remove an account from the store.
|
// Remove an account from the store.
|
||||||
RemoveAccount(sdk.Context, types.AccountI)
|
RemoveAccount(sdk.Context, types.AccountI)
|
||||||
|
|
||||||
// Iterate over all accounts, calling the provided function. Stop iteraiton when it returns false.
|
// Iterate over all accounts, calling the provided function. Stop iteration when it returns true.
|
||||||
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
||||||
|
|
||||||
// Fetch the public key of an account at a specified address
|
// Fetch the public key of an account at a specified address
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v034 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v034 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
package v034
|
package v034
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
// DONTCOVER
|
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v034"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.36
|
|
||||||
// genesis state. This migration removes the CollectedFees coins from the old
|
|
||||||
// FeeCollectorKeeper.
|
|
||||||
func Migrate(oldGenState v034auth.GenesisState) GenesisState {
|
|
||||||
return NewGenesisState(oldGenState.Params)
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v034"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMigrate(t *testing.T) {
|
|
||||||
var genesisState GenesisState
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
genesisState = Migrate(v034auth.GenesisState{
|
|
||||||
CollectedFees: types.Coins{
|
|
||||||
{
|
|
||||||
Amount: types.NewInt(10),
|
|
||||||
Denom: "stake",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Params: v034auth.Params{}, // forwarded structure: filling and checking will be testing a no-op
|
|
||||||
})
|
|
||||||
})
|
|
||||||
require.Equal(t, genesisState, GenesisState{Params: v034auth.Params{}})
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
// DONTCOVER
|
|
||||||
package v036
|
|
||||||
|
|
||||||
import v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v034"
|
|
||||||
|
|
||||||
const (
|
|
||||||
ModuleName = "auth"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
GenesisState struct {
|
|
||||||
Params v034auth.Params `json:"params"`
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewGenesisState(params v034auth.Params) GenesisState {
|
|
||||||
return GenesisState{params}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package v038
|
|
||||||
|
|
||||||
import (
|
|
||||||
v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v036"
|
|
||||||
v036genaccounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v036"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.38
|
|
||||||
// genesis state.
|
|
||||||
func Migrate(authGenState v036auth.GenesisState, genAccountsGenState v036genaccounts.GenesisState) GenesisState {
|
|
||||||
accounts := make(GenesisAccounts, len(genAccountsGenState))
|
|
||||||
|
|
||||||
for i, acc := range genAccountsGenState {
|
|
||||||
var genAccount GenesisAccount
|
|
||||||
|
|
||||||
baseAccount := NewBaseAccount(acc.Address, acc.Coins.Sort(), nil, acc.AccountNumber, acc.Sequence)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case !acc.OriginalVesting.IsZero():
|
|
||||||
baseVestingAccount := NewBaseVestingAccount(
|
|
||||||
baseAccount, acc.OriginalVesting.Sort(), acc.DelegatedFree.Sort(),
|
|
||||||
acc.DelegatedVesting.Sort(), acc.EndTime,
|
|
||||||
)
|
|
||||||
|
|
||||||
if acc.StartTime != 0 && acc.EndTime != 0 {
|
|
||||||
// continuous vesting account type
|
|
||||||
genAccount = NewContinuousVestingAccountRaw(baseVestingAccount, acc.StartTime)
|
|
||||||
} else if acc.EndTime != 0 {
|
|
||||||
// delayed vesting account type
|
|
||||||
genAccount = NewDelayedVestingAccountRaw(baseVestingAccount)
|
|
||||||
}
|
|
||||||
|
|
||||||
case acc.ModuleName != "":
|
|
||||||
// module account type
|
|
||||||
genAccount = NewModuleAccount(baseAccount, acc.ModuleName, acc.ModulePermissions...)
|
|
||||||
|
|
||||||
default:
|
|
||||||
// standard account type
|
|
||||||
genAccount = baseAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts[i] = genAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts = SanitizeGenesisAccounts(accounts)
|
|
||||||
|
|
||||||
if err := ValidateGenAccounts(accounts); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewGenesisState(authGenState.Params, accounts)
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
package v038
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v034"
|
|
||||||
v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v036"
|
|
||||||
v036genaccounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v036"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func accAddressFromBech32(t *testing.T, addrStr string) sdk.AccAddress {
|
|
||||||
addr, err := sdk.AccAddressFromBech32(addrStr)
|
|
||||||
require.NoError(t, err)
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigrate(t *testing.T) {
|
|
||||||
var genesisState GenesisState
|
|
||||||
|
|
||||||
params := v034auth.Params{
|
|
||||||
MaxMemoCharacters: 10,
|
|
||||||
TxSigLimit: 10,
|
|
||||||
TxSizeCostPerByte: 10,
|
|
||||||
SigVerifyCostED25519: 10,
|
|
||||||
SigVerifyCostSecp256k1: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
acc1 := v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos1f9xjhxm0plzrh9cskf4qee4pc2xwp0n0556gh0"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)),
|
|
||||||
Sequence: 1,
|
|
||||||
AccountNumber: 1,
|
|
||||||
}
|
|
||||||
acc2 := v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000000)),
|
|
||||||
Sequence: 4,
|
|
||||||
AccountNumber: 2,
|
|
||||||
ModuleName: "bonded_tokens_pool",
|
|
||||||
ModulePermissions: []string{"burner", "staking"},
|
|
||||||
}
|
|
||||||
acc3 := v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos17n9sztlhx32tfy0tg0zc2ttmkeeth50yyuv9he"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 10000205)),
|
|
||||||
OriginalVesting: sdk.NewCoins(sdk.NewInt64Coin("stake", 10000205)),
|
|
||||||
StartTime: time.Now().Unix(),
|
|
||||||
EndTime: time.Now().Add(48 * time.Hour).Unix(),
|
|
||||||
Sequence: 5,
|
|
||||||
AccountNumber: 3,
|
|
||||||
}
|
|
||||||
acc4 := v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos1fmk5elg4r62mlexd36tqjcwyafs7mek0js5m4d"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 10000205)),
|
|
||||||
OriginalVesting: sdk.NewCoins(sdk.NewInt64Coin("stake", 10000205)),
|
|
||||||
EndTime: time.Now().Add(48 * time.Hour).Unix(),
|
|
||||||
Sequence: 15,
|
|
||||||
AccountNumber: 4,
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
genesisState = Migrate(
|
|
||||||
v036auth.GenesisState{
|
|
||||||
Params: params,
|
|
||||||
},
|
|
||||||
v036genaccounts.GenesisState{acc1, acc2, acc3, acc4},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
expectedAcc1 := NewBaseAccount(acc1.Address, acc1.Coins, nil, acc1.AccountNumber, acc1.Sequence)
|
|
||||||
expectedAcc2 := NewModuleAccount(
|
|
||||||
NewBaseAccount(acc2.Address, acc2.Coins, nil, acc2.AccountNumber, acc2.Sequence),
|
|
||||||
acc2.ModuleName, acc2.ModulePermissions...,
|
|
||||||
)
|
|
||||||
expectedAcc3 := NewContinuousVestingAccountRaw(
|
|
||||||
NewBaseVestingAccount(
|
|
||||||
NewBaseAccount(acc3.Address, acc3.Coins, nil, acc3.AccountNumber, acc3.Sequence),
|
|
||||||
acc3.OriginalVesting, acc3.DelegatedFree, acc3.DelegatedVesting, acc3.EndTime,
|
|
||||||
),
|
|
||||||
acc3.StartTime,
|
|
||||||
)
|
|
||||||
expectedAcc4 := NewDelayedVestingAccountRaw(
|
|
||||||
NewBaseVestingAccount(
|
|
||||||
NewBaseAccount(acc4.Address, acc4.Coins, nil, acc4.AccountNumber, acc4.Sequence),
|
|
||||||
acc4.OriginalVesting, acc4.DelegatedFree, acc4.DelegatedVesting, acc4.EndTime,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
require.Equal(
|
|
||||||
t, genesisState, GenesisState{
|
|
||||||
Params: params,
|
|
||||||
Accounts: GenesisAccounts{expectedAcc1, expectedAcc2, expectedAcc3, expectedAcc4},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigrateInvalid(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
acc v036genaccounts.GenesisAccount
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"module account with invalid name",
|
|
||||||
v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000000)),
|
|
||||||
Sequence: 4,
|
|
||||||
AccountNumber: 2,
|
|
||||||
ModuleName: " ",
|
|
||||||
ModulePermissions: []string{"burner", "staking"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module account with invalid permissions",
|
|
||||||
v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000000)),
|
|
||||||
Sequence: 4,
|
|
||||||
AccountNumber: 2,
|
|
||||||
ModuleName: "bonded_tokens_pool",
|
|
||||||
ModulePermissions: []string{""},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"module account with invalid address",
|
|
||||||
v036genaccounts.GenesisAccount{
|
|
||||||
Address: accAddressFromBech32(t, "cosmos17n9sztlhx32tfy0tg0zc2ttmkeeth50yyuv9he"),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000000)),
|
|
||||||
Sequence: 4,
|
|
||||||
AccountNumber: 2,
|
|
||||||
ModuleName: "bonded_tokens_pool",
|
|
||||||
ModulePermissions: []string{"burner", "staking"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
tc := tc
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
require.Panics(t, func() {
|
|
||||||
Migrate(
|
|
||||||
v036auth.GenesisState{
|
|
||||||
Params: v034auth.Params{
|
|
||||||
MaxMemoCharacters: 10,
|
|
||||||
TxSigLimit: 10,
|
|
||||||
TxSizeCostPerByte: 10,
|
|
||||||
SigVerifyCostED25519: 10,
|
|
||||||
SigVerifyCostSecp256k1: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
v036genaccounts.GenesisState{tc.acc},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v038 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v038 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
package v038
|
package v038
|
||||||
|
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package v039
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v038"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.38 and migrates it to v0.39
|
|
||||||
// genesis state.
|
|
||||||
func Migrate(oldAuthGenState v038auth.GenesisState) GenesisState {
|
|
||||||
accounts := make(v038auth.GenesisAccounts, len(oldAuthGenState.Accounts))
|
|
||||||
|
|
||||||
for i, acc := range oldAuthGenState.Accounts {
|
|
||||||
switch t := acc.(type) {
|
|
||||||
case *v038auth.BaseAccount:
|
|
||||||
accounts[i] = NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence)
|
|
||||||
|
|
||||||
case *v038auth.BaseVestingAccount:
|
|
||||||
accounts[i] = NewBaseVestingAccount(
|
|
||||||
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
|
|
||||||
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
|
|
||||||
)
|
|
||||||
|
|
||||||
case *v038auth.ContinuousVestingAccount:
|
|
||||||
accounts[i] = NewContinuousVestingAccountRaw(
|
|
||||||
NewBaseVestingAccount(
|
|
||||||
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
|
|
||||||
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
|
|
||||||
),
|
|
||||||
t.StartTime,
|
|
||||||
)
|
|
||||||
|
|
||||||
case *v038auth.DelayedVestingAccount:
|
|
||||||
accounts[i] = NewDelayedVestingAccountRaw(
|
|
||||||
NewBaseVestingAccount(
|
|
||||||
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
|
|
||||||
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
case *v038auth.ModuleAccount:
|
|
||||||
accounts[i] = NewModuleAccount(
|
|
||||||
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
|
|
||||||
t.Name, t.Permissions...,
|
|
||||||
)
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unexpected account type: %T", acc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
accounts = v038auth.SanitizeGenesisAccounts(accounts)
|
|
||||||
|
|
||||||
if err := v038auth.ValidateGenAccounts(accounts); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewGenesisState(oldAuthGenState.Params, accounts)
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
package v039_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v038"
|
|
||||||
v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v039"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMigrate(t *testing.T) {
|
|
||||||
aminoCdc := codec.NewLegacyAmino()
|
|
||||||
v039auth.RegisterLegacyAminoCodec(aminoCdc)
|
|
||||||
|
|
||||||
pub1 := ed25519.GenPrivKeyFromSecret([]byte("acc1")).PubKey()
|
|
||||||
pub2 := secp256k1.GenPrivKeyFromSecret([]byte("acc2")).PubKey()
|
|
||||||
|
|
||||||
acc1 := v038auth.BaseAccount{
|
|
||||||
Address: sdk.AccAddress(pub1.Address()),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)),
|
|
||||||
Sequence: 1,
|
|
||||||
AccountNumber: 1,
|
|
||||||
PubKey: pub1,
|
|
||||||
}
|
|
||||||
acc2 := v038auth.BaseAccount{
|
|
||||||
Address: sdk.AccAddress(pub2.Address()),
|
|
||||||
Coins: sdk.NewCoins(sdk.NewInt64Coin("stake", 400000)),
|
|
||||||
Sequence: 2,
|
|
||||||
AccountNumber: 2,
|
|
||||||
PubKey: pub2,
|
|
||||||
}
|
|
||||||
|
|
||||||
migrated := v039auth.Migrate(
|
|
||||||
v038auth.GenesisState{
|
|
||||||
Accounts: v038auth.GenesisAccounts{&acc1, &acc2},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
expectedAcc1 := v039auth.NewBaseAccount(acc1.Address, acc1.Coins, acc1.PubKey, acc1.AccountNumber, acc1.Sequence)
|
|
||||||
expectedAcc2 := v039auth.NewBaseAccount(acc2.Address, acc2.Coins, acc2.PubKey, acc2.AccountNumber, acc2.Sequence)
|
|
||||||
|
|
||||||
require.Equal(
|
|
||||||
t, migrated, v039auth.GenesisState{
|
|
||||||
Accounts: v038auth.GenesisAccounts{expectedAcc1, expectedAcc2},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
json, err := aminoCdc.MarshalJSONIndent(migrated, "", " ")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
expectedJSON := `{
|
|
||||||
"params": {
|
|
||||||
"max_memo_characters": "0",
|
|
||||||
"tx_sig_limit": "0",
|
|
||||||
"tx_size_cost_per_byte": "0",
|
|
||||||
"sig_verify_cost_ed25519": "0",
|
|
||||||
"sig_verify_cost_secp256k1": "0"
|
|
||||||
},
|
|
||||||
"accounts": [
|
|
||||||
{
|
|
||||||
"type": "cosmos-sdk/Account",
|
|
||||||
"value": {
|
|
||||||
"address": "cosmos1j7skdhh9raxdmfhmcy2gxz8hgn0jnhfmujjsfe",
|
|
||||||
"coins": [
|
|
||||||
{
|
|
||||||
"denom": "stake",
|
|
||||||
"amount": "400000"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"public_key": {
|
|
||||||
"type": "tendermint/PubKeyEd25519",
|
|
||||||
"value": "eB0AcLMLKFRNFfh4XAAMstexfAIUQQCDnfjLZ2KJg+A="
|
|
||||||
},
|
|
||||||
"account_number": "1",
|
|
||||||
"sequence": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "cosmos-sdk/Account",
|
|
||||||
"value": {
|
|
||||||
"address": "cosmos1v57fx2l2rt6ehujuu99u2fw05779m5e2ux4z2h",
|
|
||||||
"coins": [
|
|
||||||
{
|
|
||||||
"denom": "stake",
|
|
||||||
"amount": "400000"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"public_key": {
|
|
||||||
"type": "tendermint/PubKeySecp256k1",
|
|
||||||
"value": "AruDygh5HprMOpHOEato85dLgAsybMJVyxBGUa3KuWCr"
|
|
||||||
},
|
|
||||||
"account_number": "2",
|
|
||||||
"sequence": "2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`
|
|
||||||
require.Equal(t, expectedJSON, string(json))
|
|
||||||
}
|
|
|
@ -4,41 +4,37 @@ order: 3
|
||||||
|
|
||||||
# AnteHandlers
|
# AnteHandlers
|
||||||
|
|
||||||
## Handlers
|
The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool.
|
||||||
|
The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/v0.43.0-alpha1/docs/architecture/adr-010-modular-antehandler.md).
|
||||||
|
|
||||||
The auth module presently has no transaction handlers of its own, but does expose
|
Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`.
|
||||||
the special `AnteHandler`, used for performing basic validity checks on a transaction,
|
|
||||||
such that it could be thrown out of the mempool. Note that the ante handler is called on
|
|
||||||
`CheckTx`, but _also_ on `DeliverTx`, as Tendermint proposers presently have the ability
|
|
||||||
to include in their proposed block transactions which fail `CheckTx`.
|
|
||||||
|
|
||||||
### Ante Handler
|
## Decorators
|
||||||
|
|
||||||
```go
|
The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order:
|
||||||
anteHandler(ak AccountKeeper, fck FeeCollectionKeeper, tx sdk.Tx)
|
|
||||||
if !tx.(StdTx)
|
|
||||||
fail with "not a StdTx"
|
|
||||||
|
|
||||||
if isCheckTx and tx.Fee < config.SubjectiveMinimumFee
|
- `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used.
|
||||||
fail with "insufficient fee for mempool inclusion"
|
|
||||||
|
|
||||||
if tx.ValidateBasic() != nil
|
- `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions.
|
||||||
fail with "tx failed ValidateBasic"
|
|
||||||
|
|
||||||
if tx.Fee > 0
|
- `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`.
|
||||||
account = GetAccount(tx.GetSigners()[0])
|
|
||||||
coins := acount.GetCoins()
|
|
||||||
if coins < tx.Fee
|
|
||||||
fail with "insufficient fee to pay for transaction"
|
|
||||||
account.SetCoins(coins - tx.Fee)
|
|
||||||
fck.AddCollectedFees(tx.Fee)
|
|
||||||
|
|
||||||
for index, signature in tx.GetSignatures()
|
- `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error.
|
||||||
account = GetAccount(tx.GetSigners()[index])
|
|
||||||
bytesToSign := StdSignBytes(chainID, acc.GetAccountNumber(),
|
|
||||||
acc.GetSequence(), tx.Fee, tx.Msgs, tx.Memo)
|
|
||||||
if !signature.Verify(bytesToSign)
|
|
||||||
fail with "invalid signature"
|
|
||||||
|
|
||||||
return
|
- `TxTimeoutHeightDecorator`: Check for a `tx` height timeout.
|
||||||
```
|
|
||||||
|
- `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error.
|
||||||
|
|
||||||
|
- `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters.
|
||||||
|
|
||||||
|
- `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it will deduct fees from the fee granter account.
|
||||||
|
|
||||||
|
- `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context.
|
||||||
|
|
||||||
|
- `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters.
|
||||||
|
|
||||||
|
- `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||||
|
|
||||||
|
- `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`.
|
||||||
|
|
||||||
|
- `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks.
|
||||||
|
|
|
@ -29,7 +29,7 @@ type AccountKeeperI interface {
|
||||||
// Remove an account from the store.
|
// Remove an account from the store.
|
||||||
RemoveAccount(sdk.Context, types.AccountI)
|
RemoveAccount(sdk.Context, types.AccountI)
|
||||||
|
|
||||||
// Iterate over all accounts, calling the provided function. Stop iteraiton when it returns false.
|
// Iterate over all accounts, calling the provided function. Stop iteration when it returns true.
|
||||||
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
IterateAccounts(sdk.Context, func(types.AccountI) bool)
|
||||||
|
|
||||||
// Fetch the public key of an account at a specified address
|
// Fetch the public key of an account at a specified address
|
||||||
|
|
|
@ -15,8 +15,8 @@ type Authorization interface {
|
||||||
// which will process and accept or reject a request.
|
// which will process and accept or reject a request.
|
||||||
MsgTypeURL() string
|
MsgTypeURL() string
|
||||||
|
|
||||||
// Accept determines whether this grant permits the provided sdk.ServiceMsg to be performed, and if
|
// Accept determines whether this grant permits the provided sdk.Msg to be performed,
|
||||||
// so provides an upgraded authorization instance.
|
// and if so provides an upgraded authorization instance.
|
||||||
Accept(ctx sdk.Context, msg sdk.Msg) (AcceptResponse, error)
|
Accept(ctx sdk.Context, msg sdk.Msg) (AcceptResponse, error)
|
||||||
|
|
||||||
// ValidateBasic does a simple validation check that
|
// ValidateBasic does a simple validation check that
|
||||||
|
|
|
@ -13,4 +13,5 @@ type AccountKeeper interface {
|
||||||
// BankKeeper defines the expected interface needed to retrieve account balances.
|
// BankKeeper defines the expected interface needed to retrieve account balances.
|
||||||
type BankKeeper interface {
|
type BankKeeper interface {
|
||||||
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
|
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
|
||||||
|
IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (suite *TestSuite) TestGRPCQueryAuthorization() {
|
func (suite *TestSuite) TestGRPCQueryAuthorization() {
|
||||||
|
|
|
@ -32,19 +32,19 @@ func TestDecodeStore(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
expectErr bool
|
||||||
expectedLog string
|
expectedLog string
|
||||||
}{
|
}{
|
||||||
{"Grant", fmt.Sprintf("%v\n%v", grant, grant)},
|
{"Grant", false, fmt.Sprintf("%v\n%v", grant, grant)},
|
||||||
{"other", ""},
|
{"other", true, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
i, tt := i, tt
|
i, tt := i, tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
switch i {
|
if tt.expectErr {
|
||||||
case len(tests) - 1:
|
|
||||||
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
|
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
|
||||||
default:
|
} else {
|
||||||
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
|
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,35 +1,59 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenAuthorizationGrant returns an empty slice of authorization grants.
|
// genGrant returns a slice of authorization grants.
|
||||||
func GenAuthorizationGrant(_ *rand.Rand, _ []simtypes.Account) []authz.GrantAuthorization {
|
func genGrant(r *rand.Rand, accounts []simtypes.Account) []authz.GrantAuthorization {
|
||||||
return []authz.GrantAuthorization{}
|
authorizations := make([]authz.GrantAuthorization, len(accounts)-1)
|
||||||
|
for i := 0; i < len(accounts)-1; i++ {
|
||||||
|
granter := accounts[i]
|
||||||
|
grantee := accounts[i+1]
|
||||||
|
authorizations[i] = authz.GrantAuthorization{
|
||||||
|
Granter: granter.Address.String(),
|
||||||
|
Grantee: grantee.Address.String(),
|
||||||
|
Authorization: generateRandomGrant(r),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorizations
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRandomGrant(r *rand.Rand) *codectypes.Any {
|
||||||
|
authorizations := make([]*codectypes.Any, 2)
|
||||||
|
authorizations[0] = newAnyAuthorization(banktypes.NewSendAuthorization(sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(1000)))))
|
||||||
|
authorizations[1] = newAnyAuthorization(authz.NewGenericAuthorization(sdk.MsgTypeURL(&govtypes.MsgSubmitProposal{})))
|
||||||
|
|
||||||
|
return authorizations[r.Intn(len(authorizations))]
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAnyAuthorization(a authz.Authorization) *codectypes.Any {
|
||||||
|
any, err := codectypes.NewAnyWithValue(a)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return any
|
||||||
}
|
}
|
||||||
|
|
||||||
// RandomizedGenState generates a random GenesisState for authz.
|
// RandomizedGenState generates a random GenesisState for authz.
|
||||||
func RandomizedGenState(simState *module.SimulationState) {
|
func RandomizedGenState(simState *module.SimulationState) {
|
||||||
var grants []authz.GrantAuthorization
|
var grants []authz.GrantAuthorization
|
||||||
|
|
||||||
simState.AppParams.GetOrGenerate(
|
simState.AppParams.GetOrGenerate(
|
||||||
simState.Cdc, "authz", &grants, simState.Rand,
|
simState.Cdc, "authz", &grants, simState.Rand,
|
||||||
func(r *rand.Rand) { grants = GenAuthorizationGrant(r, simState.Accounts) },
|
func(r *rand.Rand) { grants = genGrant(r, simState.Accounts) },
|
||||||
)
|
)
|
||||||
|
|
||||||
authzGrantsGenesis := authz.NewGenesisState(grants)
|
authzGrantsGenesis := authz.NewGenesisState(grants)
|
||||||
|
|
||||||
bz, err := json.MarshalIndent(&authzGrantsGenesis, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", authz.ModuleName, bz)
|
|
||||||
simState.GenState[authz.ModuleName] = simState.Cdc.MustMarshalJSON(authzGrantsGenesis)
|
simState.GenState[authz.ModuleName] = simState.Cdc.MustMarshalJSON(authzGrantsGenesis)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
@ -16,15 +15,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRandomizedGenState(t *testing.T) {
|
func TestRandomizedGenState(t *testing.T) {
|
||||||
interfaceRegistry := codectypes.NewInterfaceRegistry()
|
app := simapp.Setup(false)
|
||||||
cdc := codec.NewProtoCodec(interfaceRegistry)
|
|
||||||
|
|
||||||
s := rand.NewSource(1)
|
s := rand.NewSource(1)
|
||||||
r := rand.New(s)
|
r := rand.New(s)
|
||||||
|
|
||||||
simState := module.SimulationState{
|
simState := module.SimulationState{
|
||||||
AppParams: make(simtypes.AppParams),
|
AppParams: make(simtypes.AppParams),
|
||||||
Cdc: cdc,
|
Cdc: app.AppCodec(),
|
||||||
Rand: r,
|
Rand: r,
|
||||||
NumBonded: 3,
|
NumBonded: 3,
|
||||||
Accounts: simtypes.RandomAccounts(r, 3),
|
Accounts: simtypes.RandomAccounts(r, 3),
|
||||||
|
@ -36,5 +34,5 @@ func TestRandomizedGenState(t *testing.T) {
|
||||||
var authzGenesis authz.GenesisState
|
var authzGenesis authz.GenesisState
|
||||||
simState.Cdc.MustUnmarshalJSON(simState.GenState[authz.ModuleName], &authzGenesis)
|
simState.Cdc.MustUnmarshalJSON(simState.GenState[authz.ModuleName], &authzGenesis)
|
||||||
|
|
||||||
require.Len(t, authzGenesis.Authorization, 0)
|
require.Len(t, authzGenesis.Authorization, len(simState.Accounts)-1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package simulation
|
package simulation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -12,23 +14,33 @@ import (
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
|
||||||
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
|
"github.com/cosmos/cosmos-sdk/x/authz/keeper"
|
||||||
|
|
||||||
banktype "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktype "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
)
|
)
|
||||||
|
|
||||||
// authz message types
|
// authz message types
|
||||||
var (
|
var (
|
||||||
TypeMsgGrantAuthorization = sdk.MsgTypeURL(&authz.MsgGrant{})
|
TypeMsgGrant = sdk.MsgTypeURL(&authz.MsgGrant{})
|
||||||
TypeMsgRevokeAuthorization = sdk.MsgTypeURL(&authz.MsgRevoke{})
|
TypeMsgRevoke = sdk.MsgTypeURL(&authz.MsgRevoke{})
|
||||||
TypeMsgExecDelegated = sdk.MsgTypeURL(&authz.MsgExec{})
|
TypeMsgExec = sdk.MsgTypeURL(&authz.MsgExec{})
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simulation operation weights constants
|
// Simulation operation weights constants
|
||||||
const (
|
const (
|
||||||
OpWeightMsgGrantAuthorization = "op_weight_msg_grant"
|
OpWeightMsgGrant = "op_weight_msg_grant"
|
||||||
OpWeightRevokeAuthorization = "op_weight_msg_revoke"
|
OpWeightRevoke = "op_weight_msg_revoke"
|
||||||
OpWeightExecAuthorized = "op_weight_msg_execute"
|
OpWeightExec = "op_weight_msg_execute"
|
||||||
|
)
|
||||||
|
|
||||||
|
// authz operations weights
|
||||||
|
const (
|
||||||
|
WeightGrant = 100
|
||||||
|
WeightRevoke = 90
|
||||||
|
WeightExec = 90
|
||||||
)
|
)
|
||||||
|
|
||||||
// WeightedOperations returns all the operations from the module with their respective weights
|
// WeightedOperations returns all the operations from the module with their respective weights
|
||||||
|
@ -36,91 +48,91 @@ func WeightedOperations(
|
||||||
appParams simtypes.AppParams, cdc codec.JSONCodec, ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simulation.WeightedOperations {
|
appParams simtypes.AppParams, cdc codec.JSONCodec, ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simulation.WeightedOperations {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
weightMsgGrantAuthorization int
|
weightMsgGrant int
|
||||||
weightRevokeAuthorization int
|
weightRevoke int
|
||||||
weightExecAuthorized int
|
weightExec int
|
||||||
)
|
)
|
||||||
|
|
||||||
appParams.GetOrGenerate(cdc, OpWeightMsgGrantAuthorization, &weightMsgGrantAuthorization, nil,
|
appParams.GetOrGenerate(cdc, OpWeightMsgGrant, &weightMsgGrant, nil,
|
||||||
func(_ *rand.Rand) {
|
func(_ *rand.Rand) {
|
||||||
weightMsgGrantAuthorization = simappparams.DefaultWeightMsgDelegate
|
weightMsgGrant = WeightGrant
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
appParams.GetOrGenerate(cdc, OpWeightRevokeAuthorization, &weightRevokeAuthorization, nil,
|
appParams.GetOrGenerate(cdc, OpWeightRevoke, &weightRevoke, nil,
|
||||||
func(_ *rand.Rand) {
|
func(_ *rand.Rand) {
|
||||||
weightRevokeAuthorization = simappparams.DefaultWeightMsgUndelegate
|
weightRevoke = WeightRevoke
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
appParams.GetOrGenerate(cdc, OpWeightExecAuthorized, &weightExecAuthorized, nil,
|
appParams.GetOrGenerate(cdc, OpWeightExec, &weightExec, nil,
|
||||||
func(_ *rand.Rand) {
|
func(_ *rand.Rand) {
|
||||||
weightExecAuthorized = simappparams.DefaultWeightMsgSend
|
weightExec = WeightExec
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return simulation.WeightedOperations{
|
return simulation.WeightedOperations{
|
||||||
simulation.NewWeightedOperation(
|
simulation.NewWeightedOperation(
|
||||||
weightMsgGrantAuthorization,
|
weightMsgGrant,
|
||||||
SimulateMsgGrantAuthorization(ak, bk, k, protoCdc),
|
SimulateMsgGrant(ak, bk, k, protoCdc),
|
||||||
),
|
),
|
||||||
simulation.NewWeightedOperation(
|
simulation.NewWeightedOperation(
|
||||||
weightRevokeAuthorization,
|
weightRevoke,
|
||||||
SimulateMsgRevokeAuthorization(ak, bk, k, protoCdc),
|
SimulateMsgRevoke(ak, bk, k, protoCdc),
|
||||||
),
|
),
|
||||||
simulation.NewWeightedOperation(
|
simulation.NewWeightedOperation(
|
||||||
weightExecAuthorized,
|
weightExec,
|
||||||
SimulateMsgExecuteAuthorized(ak, bk, k, appCdc, protoCdc),
|
SimulateMsgExec(ak, bk, k, appCdc, protoCdc),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgGrantAuthorization generates a MsgGrantAuthorization with random values.
|
// SimulateMsgGrant generates a MsgGrant with random values.
|
||||||
// nolint: funlen
|
func SimulateMsgGrant(ak authz.AccountKeeper, bk authz.BankKeeper, _ keeper.Keeper,
|
||||||
func SimulateMsgGrantAuthorization(ak authz.AccountKeeper, bk authz.BankKeeper, _ keeper.Keeper,
|
|
||||||
protoCdc *codec.ProtoCodec) simtypes.Operation {
|
protoCdc *codec.ProtoCodec) simtypes.Operation {
|
||||||
return func(
|
return func(
|
||||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
granter := accs[0]
|
granter, _ := simtypes.RandomAcc(r, accs)
|
||||||
grantee := accs[1]
|
grantee, _ := simtypes.RandomAcc(r, accs)
|
||||||
|
|
||||||
account := ak.GetAccount(ctx, granter.Address)
|
if granter.Address.Equals(grantee.Address) {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "granter and grantee are same"), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
|
granterAcc := ak.GetAccount(ctx, granter.Address)
|
||||||
|
spendableCoins := bk.SpendableCoins(ctx, granter.Address)
|
||||||
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
|
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
blockTime := ctx.BlockTime()
|
|
||||||
spendLimit := spendableCoins.Sub(fees)
|
spendLimit := spendableCoins.Sub(fees)
|
||||||
if spendLimit == nil {
|
if spendLimit == nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrantAuthorization, "spend limit is nil"), nil, nil
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "spend limit is nil"), nil, nil
|
||||||
}
|
}
|
||||||
msg, err := authz.NewMsgGrant(granter.Address, grantee.Address,
|
|
||||||
banktype.NewSendAuthorization(spendLimit), blockTime.AddDate(1, 0, 0))
|
|
||||||
|
|
||||||
|
expiration := ctx.BlockTime().AddDate(1, 0, 0)
|
||||||
|
msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, generateRandomAuthorization(r, spendLimit), expiration)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrantAuthorization, err.Error()), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err
|
||||||
}
|
}
|
||||||
txGen := simappparams.MakeTestEncodingConfig().TxConfig
|
txCfg := simappparams.MakeTestEncodingConfig().TxConfig
|
||||||
tx, err := helpers.GenTx(
|
tx, err := helpers.GenTx(
|
||||||
txGen,
|
txCfg,
|
||||||
[]sdk.Msg{msg},
|
[]sdk.Msg{msg},
|
||||||
fees,
|
fees,
|
||||||
helpers.DefaultGenTxGas,
|
helpers.DefaultGenTxGas,
|
||||||
chainID,
|
chainID,
|
||||||
[]uint64{account.GetAccountNumber()},
|
[]uint64{granterAcc.GetAccountNumber()},
|
||||||
[]uint64{account.GetSequence()},
|
[]uint64{granterAcc.GetSequence()},
|
||||||
granter.PrivKey,
|
granter.PrivKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrantAuthorization, "unable to generate mock tx"), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "unable to generate mock tx"), nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
|
_, _, err = app.Deliver(txCfg.TxEncoder(), tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
|
||||||
}
|
}
|
||||||
|
@ -128,18 +140,25 @@ func SimulateMsgGrantAuthorization(ak authz.AccountKeeper, bk authz.BankKeeper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgRevokeAuthorization generates a MsgRevokeAuthorization with random values.
|
func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization {
|
||||||
// nolint: funlen
|
authorizations := make([]authz.Authorization, 2)
|
||||||
func SimulateMsgRevokeAuthorization(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, protoCdc *codec.ProtoCodec) simtypes.Operation {
|
authorizations[0] = banktype.NewSendAuthorization(spendLimit)
|
||||||
|
authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{}))
|
||||||
|
|
||||||
|
return authorizations[r.Intn(len(authorizations))]
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMsgRevoke generates a MsgRevoke with random values.
|
||||||
|
func SimulateMsgRevoke(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, protoCdc *codec.ProtoCodec) simtypes.Operation {
|
||||||
return func(
|
return func(
|
||||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
var granterAddr, granteeAddr sdk.AccAddress
|
||||||
|
var grant authz.Grant
|
||||||
hasGrant := false
|
hasGrant := false
|
||||||
var targetGrant authz.Grant
|
|
||||||
var granterAddr sdk.AccAddress
|
k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, g authz.Grant) bool {
|
||||||
var granteeAddr sdk.AccAddress
|
grant = g
|
||||||
k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool {
|
|
||||||
targetGrant = grant
|
|
||||||
granterAddr = granter
|
granterAddr = granter
|
||||||
granteeAddr = grantee
|
granteeAddr = grantee
|
||||||
hasGrant = true
|
hasGrant = true
|
||||||
|
@ -147,51 +166,52 @@ func SimulateMsgRevokeAuthorization(ak authz.AccountKeeper, bk authz.BankKeeper,
|
||||||
})
|
})
|
||||||
|
|
||||||
if !hasGrant {
|
if !hasGrant {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevokeAuthorization, "no grants"), nil, nil
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "no grants"), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
granter, ok := simtypes.FindAccount(accs, granterAddr)
|
granterAcc, ok := simtypes.FindAccount(accs, granterAddr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevokeAuthorization, "Account not found"), nil, nil
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "account not found")
|
||||||
}
|
}
|
||||||
account := ak.GetAccount(ctx, granter.Address)
|
|
||||||
|
|
||||||
spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
|
spendableCoins := bk.SpendableCoins(ctx, granterAddr)
|
||||||
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
|
fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevokeAuthorization, "fee error"), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "fee error"), nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
auth := targetGrant.GetAuthorization()
|
a := grant.GetAuthorization()
|
||||||
msg := authz.NewMsgRevoke(granterAddr, granteeAddr, auth.MsgTypeURL())
|
msg := authz.NewMsgRevoke(granterAddr, granteeAddr, a.MsgTypeURL())
|
||||||
txGen := simappparams.MakeTestEncodingConfig().TxConfig
|
txCfg := simappparams.MakeTestEncodingConfig().TxConfig
|
||||||
|
account := ak.GetAccount(ctx, granterAddr)
|
||||||
tx, err := helpers.GenTx(
|
tx, err := helpers.GenTx(
|
||||||
txGen,
|
txCfg,
|
||||||
[]sdk.Msg{&msg},
|
[]sdk.Msg{&msg},
|
||||||
fees,
|
fees,
|
||||||
helpers.DefaultGenTxGas,
|
helpers.DefaultGenTxGas,
|
||||||
chainID,
|
chainID,
|
||||||
[]uint64{account.GetAccountNumber()},
|
[]uint64{account.GetAccountNumber()},
|
||||||
[]uint64{account.GetSequence()},
|
[]uint64{account.GetSequence()},
|
||||||
granter.PrivKey,
|
granterAcc.PrivKey,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevokeAuthorization, err.Error()), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, err.Error()), nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
|
_, _, err = app.Deliver(txCfg.TxEncoder(), tx)
|
||||||
return simtypes.NewOperationMsg(&msg, true, "", protoCdc), nil, err
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "unable to deliver tx"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return simtypes.NewOperationMsg(&msg, true, "", protoCdc), nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateMsgExecuteAuthorized generates a MsgExecuteAuthorized with random values.
|
// SimulateMsgExec generates a MsgExec with random values.
|
||||||
// nolint: funlen
|
func SimulateMsgExec(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, cdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simtypes.Operation {
|
||||||
func SimulateMsgExecuteAuthorized(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, cdc cdctypes.AnyUnpacker, protoCdc *codec.ProtoCodec) simtypes.Operation {
|
|
||||||
return func(
|
return func(
|
||||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
|
||||||
hasGrant := false
|
hasGrant := false
|
||||||
var targetGrant authz.Grant
|
var targetGrant authz.Grant
|
||||||
var granterAddr sdk.AccAddress
|
var granterAddr sdk.AccAddress
|
||||||
|
@ -205,67 +225,73 @@ func SimulateMsgExecuteAuthorized(ak authz.AccountKeeper, bk authz.BankKeeper, k
|
||||||
})
|
})
|
||||||
|
|
||||||
if !hasGrant {
|
if !hasGrant {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "Not found"), nil, nil
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "no grant found"), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
grantee, _ := simtypes.FindAccount(accs, granteeAddr)
|
grantee, ok := simtypes.FindAccount(accs, granteeAddr)
|
||||||
granterAccount := ak.GetAccount(ctx, granterAddr)
|
if !ok {
|
||||||
granteeAccount := ak.GetAccount(ctx, granteeAddr)
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "grantee account not found")
|
||||||
|
}
|
||||||
|
|
||||||
granterspendableCoins := bk.SpendableCoins(ctx, granterAccount.GetAddress())
|
if _, ok := simtypes.FindAccount(accs, granterAddr); !ok {
|
||||||
if granterspendableCoins.Empty() {
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "granter account not found")
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "no coins"), nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if targetGrant.Expiration.Before(ctx.BlockHeader().Time) {
|
if targetGrant.Expiration.Before(ctx.BlockHeader().Time) {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "grant expired"), nil, nil
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "grant expired"), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
granteespendableCoins := bk.SpendableCoins(ctx, granteeAccount.GetAddress())
|
coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(int64(simtypes.RandIntBetween(r, 100, 1000000)))))
|
||||||
fees, err := simtypes.RandomFees(r, ctx, granteespendableCoins)
|
|
||||||
|
// Check send_enabled status of each sent coin denom
|
||||||
|
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if targetGrant.Authorization.TypeUrl == fmt.Sprintf("/%s", proto.MessageName(&banktype.SendAuthorization{})) {
|
||||||
|
sendAuthorization := targetGrant.GetAuthorization().(*banktype.SendAuthorization)
|
||||||
|
if sendAuthorization.SpendLimit.IsAllLT(coins) {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "over spend limit"), nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
granterspendableCoins := bk.SpendableCoins(ctx, granterAddr)
|
||||||
|
if granterspendableCoins.IsAllLTE(coins) {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "insufficient funds"), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
granteeSpendableCoins := bk.SpendableCoins(ctx, granteeAddr)
|
||||||
|
fees, err := simtypes.RandomFees(r, ctx, granteeSpendableCoins)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "fee error"), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "fee error"), nil, err
|
||||||
}
|
|
||||||
sendCoins := sdk.NewCoins(sdk.NewCoin("foo", sdk.NewInt(10)))
|
|
||||||
|
|
||||||
execMsg := banktype.NewMsgSend(
|
|
||||||
granterAddr,
|
|
||||||
granteeAddr,
|
|
||||||
sendCoins,
|
|
||||||
)
|
|
||||||
|
|
||||||
msg := authz.NewMsgExec(grantee.Address, []sdk.Msg{execMsg})
|
|
||||||
sendGrant := targetGrant.Authorization.GetCachedValue().(*banktype.SendAuthorization)
|
|
||||||
_, err = sendGrant.Accept(ctx, execMsg)
|
|
||||||
if err != nil {
|
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, err.Error()), nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
txGen := simappparams.MakeTestEncodingConfig().TxConfig
|
msg := authz.NewMsgExec(granteeAddr, []sdk.Msg{banktype.NewMsgSend(granterAddr, granteeAddr, coins)})
|
||||||
|
txCfg := simappparams.MakeTestEncodingConfig().TxConfig
|
||||||
|
granteeAcc := ak.GetAccount(ctx, granteeAddr)
|
||||||
|
|
||||||
tx, err := helpers.GenTx(
|
tx, err := helpers.GenTx(
|
||||||
txGen,
|
txCfg,
|
||||||
[]sdk.Msg{&msg},
|
[]sdk.Msg{&msg},
|
||||||
fees,
|
fees,
|
||||||
helpers.DefaultGenTxGas,
|
helpers.DefaultGenTxGas,
|
||||||
chainID,
|
chainID,
|
||||||
[]uint64{granteeAccount.GetAccountNumber()},
|
[]uint64{granteeAcc.GetAccountNumber()},
|
||||||
[]uint64{granteeAccount.GetSequence()},
|
[]uint64{granteeAcc.GetSequence()},
|
||||||
grantee.PrivKey,
|
grantee.PrivKey,
|
||||||
)
|
)
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = app.Deliver(txCfg.TxEncoder(), tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, err.Error()), nil, err
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err
|
||||||
}
|
}
|
||||||
_, _, err = app.Deliver(txGen.TxEncoder(), tx)
|
|
||||||
|
err = msg.UnpackInterfaces(cdc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "insufficient fee") {
|
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "unmarshal error"), nil, err
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "insufficient fee"), nil, nil
|
|
||||||
}
|
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, err.Error()), nil, err
|
|
||||||
}
|
|
||||||
msg.UnpackInterfaces(cdc)
|
|
||||||
if err != nil {
|
|
||||||
return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExecDelegated, "unmarshal error"), nil, err
|
|
||||||
}
|
}
|
||||||
return simtypes.NewOperationMsg(&msg, true, "success", protoCdc), nil, nil
|
return simtypes.NewOperationMsg(&msg, true, "success", protoCdc), nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ import (
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/simapp"
|
"github.com/cosmos/cosmos-sdk/simapp"
|
||||||
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/authz"
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
@ -54,9 +53,9 @@ func (suite *SimTestSuite) TestWeightedOperations() {
|
||||||
opMsgRoute string
|
opMsgRoute string
|
||||||
opMsgName string
|
opMsgName string
|
||||||
}{
|
}{
|
||||||
{simappparams.DefaultWeightMsgDelegate, authz.ModuleName, simulation.TypeMsgGrantAuthorization},
|
{simulation.WeightGrant, authz.ModuleName, simulation.TypeMsgGrant},
|
||||||
{simappparams.DefaultWeightMsgUndelegate, authz.ModuleName, simulation.TypeMsgRevokeAuthorization},
|
{simulation.WeightRevoke, authz.ModuleName, simulation.TypeMsgRevoke},
|
||||||
{simappparams.DefaultWeightMsgSend, authz.ModuleName, simulation.TypeMsgExecDelegated},
|
{simulation.WeightExec, authz.ModuleName, simulation.TypeMsgExec},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, w := range weightesOps {
|
for i, w := range weightesOps {
|
||||||
|
@ -74,7 +73,7 @@ func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Ac
|
||||||
accounts := simtypes.RandomAccounts(r, n)
|
accounts := simtypes.RandomAccounts(r, n)
|
||||||
|
|
||||||
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
||||||
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
|
initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt))
|
||||||
|
|
||||||
// add coins to the accounts
|
// add coins to the accounts
|
||||||
for _, account := range accounts {
|
for _, account := range accounts {
|
||||||
|
@ -86,8 +85,7 @@ func (suite *SimTestSuite) getTestingAccounts(r *rand.Rand, n int) []simtypes.Ac
|
||||||
return accounts
|
return accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SimTestSuite) TestSimulateGrantAuthorization() {
|
func (suite *SimTestSuite) TestSimulateGrant() {
|
||||||
// setup 3 accounts
|
|
||||||
s := rand.NewSource(1)
|
s := rand.NewSource(1)
|
||||||
r := rand.New(s)
|
r := rand.New(s)
|
||||||
accounts := suite.getTestingAccounts(r, 2)
|
accounts := suite.getTestingAccounts(r, 2)
|
||||||
|
@ -106,7 +104,7 @@ func (suite *SimTestSuite) TestSimulateGrantAuthorization() {
|
||||||
grantee := accounts[1]
|
grantee := accounts[1]
|
||||||
|
|
||||||
// execute operation
|
// execute operation
|
||||||
op := simulation.SimulateMsgGrantAuthorization(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
|
op := simulation.SimulateMsgGrant(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
|
||||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, ctx, accounts, "")
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, ctx, accounts, "")
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
@ -119,9 +117,9 @@ func (suite *SimTestSuite) TestSimulateGrantAuthorization() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SimTestSuite) TestSimulateRevokeAuthorization() {
|
func (suite *SimTestSuite) TestSimulateRevoke() {
|
||||||
// setup 3 accounts
|
// setup 3 accounts
|
||||||
s := rand.NewSource(1)
|
s := rand.NewSource(2)
|
||||||
r := rand.New(s)
|
r := rand.New(s)
|
||||||
accounts := suite.getTestingAccounts(r, 3)
|
accounts := suite.getTestingAccounts(r, 3)
|
||||||
|
|
||||||
|
@ -133,7 +131,7 @@ func (suite *SimTestSuite) TestSimulateRevokeAuthorization() {
|
||||||
}})
|
}})
|
||||||
|
|
||||||
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
||||||
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
|
initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt))
|
||||||
|
|
||||||
granter := accounts[0]
|
granter := accounts[0]
|
||||||
grantee := accounts[1]
|
grantee := accounts[1]
|
||||||
|
@ -143,7 +141,7 @@ func (suite *SimTestSuite) TestSimulateRevokeAuthorization() {
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
// execute operation
|
// execute operation
|
||||||
op := simulation.SimulateMsgRevokeAuthorization(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
|
op := simulation.SimulateMsgRevoke(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.protoCdc)
|
||||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
@ -158,7 +156,7 @@ func (suite *SimTestSuite) TestSimulateRevokeAuthorization() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *SimTestSuite) TestSimulateExecAuthorization() {
|
func (suite *SimTestSuite) TestSimulateExec() {
|
||||||
// setup 3 accounts
|
// setup 3 accounts
|
||||||
s := rand.NewSource(1)
|
s := rand.NewSource(1)
|
||||||
r := rand.New(s)
|
r := rand.New(s)
|
||||||
|
@ -168,7 +166,7 @@ func (suite *SimTestSuite) TestSimulateExecAuthorization() {
|
||||||
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
||||||
|
|
||||||
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
initAmt := suite.app.StakingKeeper.TokensFromConsensusPower(suite.ctx, 200000)
|
||||||
initCoins := sdk.NewCoins(sdk.NewCoin("foo", initAmt))
|
initCoins := sdk.NewCoins(sdk.NewCoin("stake", initAmt))
|
||||||
|
|
||||||
granter := accounts[0]
|
granter := accounts[0]
|
||||||
grantee := accounts[1]
|
grantee := accounts[1]
|
||||||
|
@ -178,7 +176,7 @@ func (suite *SimTestSuite) TestSimulateExecAuthorization() {
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
// execute operation
|
// execute operation
|
||||||
op := simulation.SimulateMsgExecuteAuthorized(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.app.AppCodec(), suite.protoCdc)
|
op := simulation.SimulateMsgExec(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.AuthzKeeper, suite.app.AppCodec(), suite.protoCdc)
|
||||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v036 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v036 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
package v036
|
package v036
|
||||||
|
|
||||||
|
@ -12,9 +15,3 @@ type (
|
||||||
Supply sdk.Coins `json:"supply" yaml:"supply"`
|
Supply sdk.Coins `json:"supply" yaml:"supply"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func EmptyGenesisState() GenesisState {
|
|
||||||
return GenesisState{
|
|
||||||
Supply: sdk.NewCoins(), // leave this empty as it's filled on initialization
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v038 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v038 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
package v038
|
package v038
|
||||||
|
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
"github.com/cosmos/cosmos-sdk/x/bank/keeper"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio
|
||||||
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
accs []simtypes.Account, chainID string,
|
accs []simtypes.Account, chainID string,
|
||||||
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
simAccount, toSimAcc, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
from, to, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||||
|
|
||||||
// Check send_enabled status of each coin denom
|
// Check send_enabled status of each coin denom
|
||||||
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
||||||
|
@ -69,9 +70,39 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Operatio
|
||||||
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, "skip all transfers"), nil, nil
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, "skip all transfers"), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := types.NewMsgSend(simAccount.Address, toSimAcc.Address, coins)
|
msg := types.NewMsgSend(from.Address, to.Address, coins)
|
||||||
|
|
||||||
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{simAccount.PrivKey})
|
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey})
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMsgSendToModuleAccount tests and runs a single msg send where both
|
||||||
|
// accounts already exist.
|
||||||
|
func SimulateMsgSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation {
|
||||||
|
return func(
|
||||||
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
|
accs []simtypes.Account, chainID string,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
from := accs[0]
|
||||||
|
|
||||||
|
to := getModuleAccounts(ak, ctx, moduleAccCount)[0]
|
||||||
|
|
||||||
|
spendable := bk.SpendableCoins(ctx, from.Address)
|
||||||
|
coins := simtypes.RandSubsetCoins(r, spendable)
|
||||||
|
|
||||||
|
// Check send_enabled status of each coin denom
|
||||||
|
if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgSend, err.Error()), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := types.NewMsgSend(from.Address, to.Address, coins)
|
||||||
|
|
||||||
|
err := sendMsgSend(r, app, bk, ak, msg, ctx, chainID, []cryptotypes.PrivKey{from.PrivKey})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||||
}
|
}
|
||||||
|
@ -150,11 +181,11 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
||||||
var totalSentCoins sdk.Coins
|
var totalSentCoins sdk.Coins
|
||||||
for i := range inputs {
|
for i := range inputs {
|
||||||
// generate random input fields, ignore to address
|
// generate random input fields, ignore to address
|
||||||
simAccount, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
from, _, coins, skip := randomSendFields(r, ctx, accs, bk, ak)
|
||||||
|
|
||||||
// make sure account is fresh and not used in previous input
|
// make sure account is fresh and not used in previous input
|
||||||
for usedAddrs[simAccount.Address.String()] {
|
for usedAddrs[from.Address.String()] {
|
||||||
simAccount, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak)
|
from, _, coins, skip = randomSendFields(r, ctx, accs, bk, ak)
|
||||||
}
|
}
|
||||||
|
|
||||||
if skip {
|
if skip {
|
||||||
|
@ -162,13 +193,13 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
||||||
}
|
}
|
||||||
|
|
||||||
// set input address in used address map
|
// set input address in used address map
|
||||||
usedAddrs[simAccount.Address.String()] = true
|
usedAddrs[from.Address.String()] = true
|
||||||
|
|
||||||
// set signer privkey
|
// set signer privkey
|
||||||
privs[i] = simAccount.PrivKey
|
privs[i] = from.PrivKey
|
||||||
|
|
||||||
// set next input and accumulate total sent coins
|
// set next input and accumulate total sent coins
|
||||||
inputs[i] = types.NewInput(simAccount.Address, coins)
|
inputs[i] = types.NewInput(from.Address, coins)
|
||||||
totalSentCoins = totalSentCoins.Add(coins...)
|
totalSentCoins = totalSentCoins.Add(coins...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +226,8 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove any output that has no coins
|
// remove any output that has no coins
|
||||||
i := 0
|
|
||||||
for i < len(outputs) {
|
for i := 0; i < len(outputs); {
|
||||||
if outputs[i].Coins.Empty() {
|
if outputs[i].Coins.Empty() {
|
||||||
outputs[i] = outputs[len(outputs)-1]
|
outputs[i] = outputs[len(outputs)-1]
|
||||||
outputs = outputs[:len(outputs)-1]
|
outputs = outputs[:len(outputs)-1]
|
||||||
|
@ -210,7 +241,73 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simtypes.Ope
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
Outputs: outputs,
|
Outputs: outputs,
|
||||||
}
|
}
|
||||||
|
err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs)
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return simtypes.NewOperationMsg(msg, true, "", nil), nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMsgMultiSendToModuleAccount sends coins to Module Accounts
|
||||||
|
func SimulateMsgMultiSendToModuleAccount(ak types.AccountKeeper, bk keeper.Keeper, moduleAccCount int) simtypes.Operation {
|
||||||
|
return func(
|
||||||
|
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context,
|
||||||
|
accs []simtypes.Account, chainID string,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
|
||||||
|
inputs := make([]types.Input, 2)
|
||||||
|
outputs := make([]types.Output, moduleAccCount)
|
||||||
|
// collect signer privKeys
|
||||||
|
privs := make([]cryptotypes.PrivKey, len(inputs))
|
||||||
|
|
||||||
|
var totalSentCoins sdk.Coins
|
||||||
|
for i := range inputs {
|
||||||
|
sender := accs[i]
|
||||||
|
privs[i] = sender.PrivKey
|
||||||
|
spendable := bk.SpendableCoins(ctx, sender.Address)
|
||||||
|
coins := simtypes.RandSubsetCoins(r, spendable)
|
||||||
|
inputs[i] = types.NewInput(sender.Address, coins)
|
||||||
|
totalSentCoins = totalSentCoins.Add(coins...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bk.IsSendEnabledCoins(ctx, totalSentCoins...); err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgMultiSend, err.Error()), nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
moduleAccounts := getModuleAccounts(ak, ctx, moduleAccCount)
|
||||||
|
for i := range outputs {
|
||||||
|
var outCoins sdk.Coins
|
||||||
|
// split total sent coins into random subsets for output
|
||||||
|
if i == len(outputs)-1 {
|
||||||
|
outCoins = totalSentCoins
|
||||||
|
} else {
|
||||||
|
// take random subset of remaining coins for output
|
||||||
|
// and update remaining coins
|
||||||
|
outCoins = simtypes.RandSubsetCoins(r, totalSentCoins)
|
||||||
|
totalSentCoins = totalSentCoins.Sub(outCoins)
|
||||||
|
}
|
||||||
|
|
||||||
|
outputs[i] = types.NewOutput(moduleAccounts[i].Address, outCoins)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove any output that has no coins
|
||||||
|
|
||||||
|
for i := 0; i < len(outputs); {
|
||||||
|
if outputs[i].Coins.Empty() {
|
||||||
|
outputs[i] = outputs[len(outputs)-1]
|
||||||
|
outputs = outputs[:len(outputs)-1]
|
||||||
|
} else {
|
||||||
|
// continue onto next coin
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &types.MsgMultiSend{
|
||||||
|
Inputs: inputs,
|
||||||
|
Outputs: outputs,
|
||||||
|
}
|
||||||
err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs)
|
err := sendMsgMultiSend(r, app, bk, ak, msg, ctx, chainID, privs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
return simtypes.NoOpMsg(types.ModuleName, msg.Type(), "invalid transfers"), nil, err
|
||||||
|
@ -291,25 +388,44 @@ func randomSendFields(
|
||||||
r *rand.Rand, ctx sdk.Context, accs []simtypes.Account, bk keeper.Keeper, ak types.AccountKeeper,
|
r *rand.Rand, ctx sdk.Context, accs []simtypes.Account, bk keeper.Keeper, ak types.AccountKeeper,
|
||||||
) (simtypes.Account, simtypes.Account, sdk.Coins, bool) {
|
) (simtypes.Account, simtypes.Account, sdk.Coins, bool) {
|
||||||
|
|
||||||
simAccount, _ := simtypes.RandomAcc(r, accs)
|
from, _ := simtypes.RandomAcc(r, accs)
|
||||||
toSimAcc, _ := simtypes.RandomAcc(r, accs)
|
to, _ := simtypes.RandomAcc(r, accs)
|
||||||
|
|
||||||
// disallow sending money to yourself
|
// disallow sending money to yourself
|
||||||
for simAccount.PubKey.Equals(toSimAcc.PubKey) {
|
for from.PubKey.Equals(to.PubKey) {
|
||||||
toSimAcc, _ = simtypes.RandomAcc(r, accs)
|
to, _ = simtypes.RandomAcc(r, accs)
|
||||||
}
|
}
|
||||||
|
|
||||||
acc := ak.GetAccount(ctx, simAccount.Address)
|
acc := ak.GetAccount(ctx, from.Address)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return simAccount, toSimAcc, nil, true
|
return from, to, nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
spendable := bk.SpendableCoins(ctx, acc.GetAddress())
|
spendable := bk.SpendableCoins(ctx, acc.GetAddress())
|
||||||
|
|
||||||
sendCoins := simtypes.RandSubsetCoins(r, spendable)
|
sendCoins := simtypes.RandSubsetCoins(r, spendable)
|
||||||
if sendCoins.Empty() {
|
if sendCoins.Empty() {
|
||||||
return simAccount, toSimAcc, nil, true
|
return from, to, nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
return simAccount, toSimAcc, sendCoins, false
|
return from, to, sendCoins, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func getModuleAccounts(ak types.AccountKeeper, ctx sdk.Context, moduleAccCount int) []simtypes.Account {
|
||||||
|
|
||||||
|
moduleAccounts := make([]simtypes.Account, moduleAccCount)
|
||||||
|
|
||||||
|
for i := 0; i < moduleAccCount; i++ {
|
||||||
|
addr := ak.GetModuleAddress(distributiontypes.ModuleName)
|
||||||
|
acc := ak.GetAccount(ctx, addr)
|
||||||
|
mAcc := simtypes.Account{
|
||||||
|
Address: acc.GetAddress(),
|
||||||
|
PrivKey: nil,
|
||||||
|
ConsKey: nil,
|
||||||
|
PubKey: acc.GetPubKey(),
|
||||||
|
}
|
||||||
|
moduleAccounts[i] = mAcc
|
||||||
|
}
|
||||||
|
|
||||||
|
return moduleAccounts
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,18 +104,80 @@ func (suite *SimTestSuite) TestSimulateMsgMultiSend() {
|
||||||
// execute operation
|
// execute operation
|
||||||
op := simulation.SimulateMsgMultiSend(suite.app.AccountKeeper, suite.app.BankKeeper)
|
op := simulation.SimulateMsgMultiSend(suite.app.AccountKeeper, suite.app.BankKeeper)
|
||||||
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||||
suite.Require().NoError(err)
|
require := suite.Require()
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
var msg types.MsgMultiSend
|
var msg types.MsgMultiSend
|
||||||
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||||
|
|
||||||
suite.Require().True(operationMsg.OK)
|
require.True(operationMsg.OK)
|
||||||
suite.Require().Len(msg.Inputs, 3)
|
require.Len(msg.Inputs, 3)
|
||||||
suite.Require().Equal("cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Inputs[1].Address)
|
require.Equal("cosmos1p8wcgrjr4pjju90xg6u9cgq55dxwq8j7u4x9a0", msg.Inputs[1].Address)
|
||||||
suite.Require().Equal("185121068stake", msg.Inputs[1].Coins.String())
|
require.Equal("185121068stake", msg.Inputs[1].Coins.String())
|
||||||
suite.Require().Len(msg.Outputs, 2)
|
require.Len(msg.Outputs, 2)
|
||||||
suite.Require().Equal("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Outputs[1].Address)
|
require.Equal("cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Outputs[1].Address)
|
||||||
suite.Require().Equal("260469617stake", msg.Outputs[1].Coins.String())
|
require.Equal("260469617stake", msg.Outputs[1].Coins.String())
|
||||||
|
require.Equal(types.TypeMsgMultiSend, msg.Type())
|
||||||
|
require.Equal(types.ModuleName, msg.Route())
|
||||||
|
require.Len(futureOperations, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *SimTestSuite) TestSimulateModuleAccountMsgSend() {
|
||||||
|
const (
|
||||||
|
accCount = 1
|
||||||
|
moduleAccCount = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
s := rand.NewSource(1)
|
||||||
|
r := rand.New(s)
|
||||||
|
accounts := suite.getTestingAccounts(r, accCount)
|
||||||
|
|
||||||
|
// begin a new block
|
||||||
|
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
||||||
|
|
||||||
|
// execute operation
|
||||||
|
op := simulation.SimulateMsgSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, moduleAccCount)
|
||||||
|
|
||||||
|
s = rand.NewSource(1)
|
||||||
|
r = rand.New(s)
|
||||||
|
|
||||||
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||||
|
suite.Require().Error(err)
|
||||||
|
|
||||||
|
var msg types.MsgSend
|
||||||
|
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||||
|
|
||||||
|
suite.Require().False(operationMsg.OK)
|
||||||
|
suite.Require().Equal(operationMsg.Comment, "invalid transfers")
|
||||||
|
suite.Require().Equal(types.TypeMsgSend, msg.Type())
|
||||||
|
suite.Require().Equal(types.ModuleName, msg.Route())
|
||||||
|
suite.Require().Len(futureOperations, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *SimTestSuite) TestSimulateMsgMultiSendToModuleAccount() {
|
||||||
|
const (
|
||||||
|
accCount = 2
|
||||||
|
mAccCount = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
s := rand.NewSource(1)
|
||||||
|
r := rand.New(s)
|
||||||
|
accounts := suite.getTestingAccounts(r, accCount)
|
||||||
|
|
||||||
|
// begin a new block
|
||||||
|
suite.app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: suite.app.LastBlockHeight() + 1, AppHash: suite.app.LastCommitID().Hash}})
|
||||||
|
|
||||||
|
// execute operation
|
||||||
|
op := simulation.SimulateMsgMultiSendToModuleAccount(suite.app.AccountKeeper, suite.app.BankKeeper, mAccCount)
|
||||||
|
|
||||||
|
operationMsg, futureOperations, err := op(r, suite.app.BaseApp, suite.ctx, accounts, "")
|
||||||
|
suite.Require().Error(err)
|
||||||
|
|
||||||
|
var msg types.MsgMultiSend
|
||||||
|
types.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg)
|
||||||
|
|
||||||
|
suite.Require().False(operationMsg.OK) // sending tokens to a module account should fail
|
||||||
|
suite.Require().Equal(operationMsg.Comment, "invalid transfers")
|
||||||
suite.Require().Equal(types.TypeMsgMultiSend, msg.Type())
|
suite.Require().Equal(types.TypeMsgMultiSend, msg.Type())
|
||||||
suite.Require().Equal(types.ModuleName, msg.Route())
|
suite.Require().Equal(types.ModuleName, msg.Route())
|
||||||
suite.Require().Len(futureOperations, 0)
|
suite.Require().Len(futureOperations, 0)
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v034 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v034 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
package v034
|
package v034
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
v034distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v034"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.36
|
|
||||||
// genesis state. All entries are identical except for validator slashing events
|
|
||||||
// which now include the period.
|
|
||||||
func Migrate(oldGenState v034distr.GenesisState) GenesisState {
|
|
||||||
// migrate slash events which now have the period included
|
|
||||||
slashEvents := make([]ValidatorSlashEventRecord, len(oldGenState.ValidatorSlashEvents))
|
|
||||||
for i, se := range oldGenState.ValidatorSlashEvents {
|
|
||||||
slashEvents[i] = ValidatorSlashEventRecord{
|
|
||||||
ValidatorAddress: se.ValidatorAddress,
|
|
||||||
Height: se.Height,
|
|
||||||
Period: se.Event.ValidatorPeriod,
|
|
||||||
Event: se.Event,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewGenesisState(
|
|
||||||
oldGenState.FeePool, oldGenState.CommunityTax, oldGenState.BaseProposerReward,
|
|
||||||
oldGenState.BonusProposerReward, oldGenState.WithdrawAddrEnabled,
|
|
||||||
oldGenState.DelegatorWithdrawInfos, oldGenState.PreviousProposer,
|
|
||||||
oldGenState.OutstandingRewards, oldGenState.ValidatorAccumulatedCommissions,
|
|
||||||
oldGenState.ValidatorHistoricalRewards, oldGenState.ValidatorCurrentRewards,
|
|
||||||
oldGenState.DelegatorStartingInfos, slashEvents,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v034distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v034"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
priv = secp256k1.GenPrivKey()
|
|
||||||
addr = types.AccAddress(priv.PubKey().Address())
|
|
||||||
valAddr, _ = types.ValAddressFromBech32(addr.String())
|
|
||||||
|
|
||||||
event = v034distr.ValidatorSlashEvent{
|
|
||||||
ValidatorPeriod: 1,
|
|
||||||
Fraction: types.Dec{},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMigrate(t *testing.T) {
|
|
||||||
var genesisState GenesisState
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
genesisState = Migrate(v034distr.GenesisState{
|
|
||||||
ValidatorSlashEvents: []v034distr.ValidatorSlashEventRecord{
|
|
||||||
{
|
|
||||||
ValidatorAddress: valAddr,
|
|
||||||
Height: 1,
|
|
||||||
Event: event,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
require.Equal(t, genesisState.ValidatorSlashEvents[0], ValidatorSlashEventRecord{
|
|
||||||
ValidatorAddress: valAddr,
|
|
||||||
Height: 1,
|
|
||||||
Period: event.ValidatorPeriod,
|
|
||||||
Event: event,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigrateEmptyRecord(t *testing.T) {
|
|
||||||
var genesisState GenesisState
|
|
||||||
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
genesisState = Migrate(v034distr.GenesisState{
|
|
||||||
ValidatorSlashEvents: []v034distr.ValidatorSlashEventRecord{{}},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
require.Equal(t, genesisState.ValidatorSlashEvents[0], ValidatorSlashEventRecord{
|
|
||||||
ValidatorAddress: valAddr,
|
|
||||||
Height: 0,
|
|
||||||
Period: 0,
|
|
||||||
Event: v034distr.ValidatorSlashEvent{
|
|
||||||
ValidatorPeriod: 0,
|
|
||||||
Fraction: types.Dec{},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v036 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v036 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
// DONTCOVER
|
// DONTCOVER
|
||||||
package v036
|
package v036
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package v038
|
|
||||||
|
|
||||||
// DONTCOVER
|
|
||||||
|
|
||||||
import (
|
|
||||||
v036distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v036"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.36 or v0.37 and migrates it to
|
|
||||||
// v0.38 genesis state. All entries are identical except for parameters.
|
|
||||||
func Migrate(oldGenState v036distr.GenesisState) GenesisState {
|
|
||||||
params := Params{
|
|
||||||
CommunityTax: oldGenState.CommunityTax,
|
|
||||||
BaseProposerReward: oldGenState.BaseProposerReward,
|
|
||||||
BonusProposerReward: oldGenState.BonusProposerReward,
|
|
||||||
WithdrawAddrEnabled: oldGenState.WithdrawAddrEnabled,
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewGenesisState(
|
|
||||||
params, oldGenState.FeePool,
|
|
||||||
oldGenState.DelegatorWithdrawInfos, oldGenState.PreviousProposer,
|
|
||||||
oldGenState.OutstandingRewards, oldGenState.ValidatorAccumulatedCommissions,
|
|
||||||
oldGenState.ValidatorHistoricalRewards, oldGenState.ValidatorCurrentRewards,
|
|
||||||
oldGenState.DelegatorStartingInfos, oldGenState.ValidatorSlashEvents,
|
|
||||||
)
|
|
||||||
}
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v038 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v038 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
package v038
|
package v038
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Package v038 is used for legacy migration scripts. Actual migration scripts
|
||||||
|
// for v038 have been removed, but the v039->v042 migration script still
|
||||||
|
// references types from this file, so we're keeping it for now.
|
||||||
package v038
|
package v038
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package feegrant
|
package feegrant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/gogo/protobuf/proto"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
"github.com/gogo/protobuf/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Revisit this once we have propoer gas fee framework.
|
// TODO: Revisit this once we have propoer gas fee framework.
|
||||||
|
|
|
@ -4,11 +4,12 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMsgGrantAllowance(t *testing.T) {
|
func TestMsgGrantAllowance(t *testing.T) {
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
Package genaccounts is now deprecated.
|
|
||||||
|
|
||||||
IMPORTANT: This module has been replaced by ADR 011: Generalize Module Accounts.
|
|
||||||
The ADR can be found here: https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-011-generalize-genesis-accounts.md.
|
|
||||||
|
|
||||||
Genesis accounts that existed in the genesis application state under `app_state.accounts`
|
|
||||||
now exists under the x/auth module's genesis state under the `app_state.auth.accounts` key.
|
|
||||||
Migration can be performed via x/auth/legacy/v038/migrate.go. In addition, because genesis
|
|
||||||
accounts are now generalized via an interface, it is now up to the application to
|
|
||||||
define the concrete types and the respective client logic to add them to a genesis
|
|
||||||
state/file. For an example implementation of the `add-genesis-account` command please
|
|
||||||
refer to https://github.com/cosmos/gaia/pull/122.
|
|
||||||
*/
|
|
||||||
package genaccounts
|
|
|
@ -1,27 +0,0 @@
|
||||||
// DONTCOVER
|
|
||||||
package v034
|
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ModuleName = "accounts"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
GenesisAccount struct {
|
|
||||||
Address sdk.AccAddress `json:"address"`
|
|
||||||
Coins sdk.Coins `json:"coins"`
|
|
||||||
Sequence uint64 `json:"sequence_number"`
|
|
||||||
AccountNumber uint64 `json:"account_number"`
|
|
||||||
|
|
||||||
OriginalVesting sdk.Coins `json:"original_vesting"`
|
|
||||||
DelegatedFree sdk.Coins `json:"delegated_free"`
|
|
||||||
DelegatedVesting sdk.Coins `json:"delegated_vesting"`
|
|
||||||
StartTime int64 `json:"start_time"`
|
|
||||||
EndTime int64 `json:"end_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
GenesisState []GenesisAccount
|
|
||||||
)
|
|
|
@ -1,179 +0,0 @@
|
||||||
// DONTCOVER
|
|
||||||
// nolint
|
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v034distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v034"
|
|
||||||
v034accounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v034"
|
|
||||||
v034gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v034"
|
|
||||||
v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v034"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
notBondedPoolName = "not_bonded_tokens_pool"
|
|
||||||
bondedPoolName = "bonded_tokens_pool"
|
|
||||||
feeCollectorName = "fee_collector"
|
|
||||||
mintModuleName = "mint"
|
|
||||||
|
|
||||||
basic = "basic"
|
|
||||||
minter = "minter"
|
|
||||||
burner = "burner"
|
|
||||||
staking = "staking"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.36
|
|
||||||
// genesis state. It deletes the governance base accounts and creates the new module accounts.
|
|
||||||
// The remaining accounts are updated to the new GenesisAccount type from 0.36
|
|
||||||
func Migrate(
|
|
||||||
oldGenState v034accounts.GenesisState, fees sdk.Coins, communityPool sdk.DecCoins,
|
|
||||||
deposits []v034gov.DepositWithMetadata, vals v034staking.Validators, ubds []v034staking.UnbondingDelegation,
|
|
||||||
valOutRewards []v034distr.ValidatorOutstandingRewardsRecord, bondDenom, distrModuleName, govModuleName string,
|
|
||||||
) GenesisState {
|
|
||||||
|
|
||||||
depositedCoinsAccAddr := sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
|
|
||||||
burnedDepositCoinsAccAddr := sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
|
|
||||||
|
|
||||||
bondedAmt := sdk.ZeroInt()
|
|
||||||
notBondedAmt := sdk.ZeroInt()
|
|
||||||
|
|
||||||
// remove the two previous governance base accounts for deposits and burned
|
|
||||||
// coins from rejected proposals add six new module accounts:
|
|
||||||
// distribution, gov, mint, fee collector, bonded and not bonded pool
|
|
||||||
var (
|
|
||||||
newGenState GenesisState
|
|
||||||
govCoins sdk.Coins
|
|
||||||
extraAccounts = 6
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, acc := range oldGenState {
|
|
||||||
switch {
|
|
||||||
case acc.Address.Equals(depositedCoinsAccAddr):
|
|
||||||
// remove gov deposits base account
|
|
||||||
govCoins = acc.Coins
|
|
||||||
extraAccounts -= 1
|
|
||||||
|
|
||||||
case acc.Address.Equals(burnedDepositCoinsAccAddr):
|
|
||||||
// remove gov burned deposits base account
|
|
||||||
extraAccounts -= 1
|
|
||||||
|
|
||||||
default:
|
|
||||||
newGenState = append(
|
|
||||||
newGenState,
|
|
||||||
NewGenesisAccount(
|
|
||||||
acc.Address, acc.Coins, acc.Sequence,
|
|
||||||
acc.OriginalVesting, acc.DelegatedFree, acc.DelegatedVesting,
|
|
||||||
acc.StartTime, acc.EndTime, "", []string{},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var expDeposits sdk.Coins
|
|
||||||
for _, deposit := range deposits {
|
|
||||||
expDeposits = expDeposits.Add(deposit.Deposit.Amount...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !expDeposits.IsEqual(govCoins) {
|
|
||||||
panic(
|
|
||||||
fmt.Sprintf(
|
|
||||||
"pre migration deposit base account coins ≠ stored deposits coins (%s ≠ %s)",
|
|
||||||
expDeposits.String(), govCoins.String(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// get staking module accounts coins
|
|
||||||
for _, validator := range vals {
|
|
||||||
switch validator.Status {
|
|
||||||
case v034staking.Bonded:
|
|
||||||
bondedAmt = bondedAmt.Add(validator.Tokens)
|
|
||||||
|
|
||||||
case v034staking.Unbonding, v034staking.Unbonded:
|
|
||||||
notBondedAmt = notBondedAmt.Add(validator.Tokens)
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic("invalid validator status")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, ubd := range ubds {
|
|
||||||
for _, entry := range ubd.Entries {
|
|
||||||
notBondedAmt = notBondedAmt.Add(entry.Balance)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, bondedAmt))
|
|
||||||
notBondedCoins := sdk.NewCoins(sdk.NewCoin(bondDenom, notBondedAmt))
|
|
||||||
|
|
||||||
// get distr module account coins
|
|
||||||
var distrDecCoins sdk.DecCoins
|
|
||||||
for _, reward := range valOutRewards {
|
|
||||||
distrDecCoins = distrDecCoins.Add(reward.OutstandingRewards...)
|
|
||||||
}
|
|
||||||
|
|
||||||
distrCoins, _ := distrDecCoins.Add(communityPool...).TruncateDecimal()
|
|
||||||
|
|
||||||
// get module account addresses
|
|
||||||
feeCollectorAddr := sdk.AccAddress(crypto.AddressHash([]byte(feeCollectorName)))
|
|
||||||
govAddr := sdk.AccAddress(crypto.AddressHash([]byte(govModuleName)))
|
|
||||||
bondedAddr := sdk.AccAddress(crypto.AddressHash([]byte(bondedPoolName)))
|
|
||||||
notBondedAddr := sdk.AccAddress(crypto.AddressHash([]byte(notBondedPoolName)))
|
|
||||||
distrAddr := sdk.AccAddress(crypto.AddressHash([]byte(distrModuleName)))
|
|
||||||
mintAddr := sdk.AccAddress(crypto.AddressHash([]byte(mintModuleName)))
|
|
||||||
|
|
||||||
// create module genesis accounts
|
|
||||||
feeCollectorModuleAcc := NewGenesisAccount(
|
|
||||||
feeCollectorAddr, fees, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, feeCollectorName, []string{basic},
|
|
||||||
)
|
|
||||||
govModuleAcc := NewGenesisAccount(
|
|
||||||
govAddr, govCoins, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, govModuleName, []string{burner},
|
|
||||||
)
|
|
||||||
distrModuleAcc := NewGenesisAccount(
|
|
||||||
distrAddr, distrCoins, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, distrModuleName, []string{basic},
|
|
||||||
)
|
|
||||||
bondedModuleAcc := NewGenesisAccount(
|
|
||||||
bondedAddr, bondedCoins, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, bondedPoolName, []string{burner, staking},
|
|
||||||
)
|
|
||||||
notBondedModuleAcc := NewGenesisAccount(
|
|
||||||
notBondedAddr, notBondedCoins, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, notBondedPoolName, []string{burner, staking},
|
|
||||||
)
|
|
||||||
mintModuleAcc := NewGenesisAccount(
|
|
||||||
mintAddr, sdk.Coins{}, 0,
|
|
||||||
sdk.Coins{}, sdk.Coins{}, sdk.Coins{},
|
|
||||||
0, 0, mintModuleName, []string{minter},
|
|
||||||
)
|
|
||||||
|
|
||||||
newGenState = append(
|
|
||||||
newGenState,
|
|
||||||
[]GenesisAccount{
|
|
||||||
feeCollectorModuleAcc, govModuleAcc, distrModuleAcc,
|
|
||||||
bondedModuleAcc, notBondedModuleAcc, mintModuleAcc,
|
|
||||||
}...,
|
|
||||||
)
|
|
||||||
|
|
||||||
// verify the total number of accounts is correct
|
|
||||||
if len(newGenState) != len(oldGenState)+extraAccounts {
|
|
||||||
panic(
|
|
||||||
fmt.Sprintf(
|
|
||||||
"invalid total number of genesis accounts; got: %d, expected: %d",
|
|
||||||
len(newGenState), len(oldGenState)+extraAccounts),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return newGenState
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
|
||||||
"github.com/cosmos/cosmos-sdk/types"
|
|
||||||
v034distr "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v034"
|
|
||||||
v034accounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v034"
|
|
||||||
v034gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v034"
|
|
||||||
v034staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v034"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
priv = secp256k1.GenPrivKey()
|
|
||||||
addr = types.AccAddress(priv.PubKey().Address())
|
|
||||||
depositedCoinsAccAddr = types.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
|
|
||||||
burnedDepositCoinsAccAddr = types.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
|
|
||||||
|
|
||||||
coins = types.Coins{types.NewInt64Coin(types.DefaultBondDenom, 10)}
|
|
||||||
halfCoins = types.Coins{types.NewInt64Coin(types.DefaultBondDenom, 5)}
|
|
||||||
|
|
||||||
accountDeposited = v034accounts.GenesisAccount{
|
|
||||||
Address: depositedCoinsAccAddr,
|
|
||||||
Coins: coins,
|
|
||||||
Sequence: 1,
|
|
||||||
AccountNumber: 1,
|
|
||||||
|
|
||||||
OriginalVesting: coins,
|
|
||||||
DelegatedFree: coins,
|
|
||||||
DelegatedVesting: coins,
|
|
||||||
StartTime: 0,
|
|
||||||
EndTime: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
accountBurned = v034accounts.GenesisAccount{
|
|
||||||
Address: burnedDepositCoinsAccAddr,
|
|
||||||
Coins: coins,
|
|
||||||
Sequence: 2,
|
|
||||||
AccountNumber: 2,
|
|
||||||
|
|
||||||
OriginalVesting: coins,
|
|
||||||
DelegatedFree: coins,
|
|
||||||
DelegatedVesting: coins,
|
|
||||||
StartTime: 0,
|
|
||||||
EndTime: 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
deposit = v034gov.DepositWithMetadata{
|
|
||||||
ProposalID: 1,
|
|
||||||
Deposit: v034gov.Deposit{
|
|
||||||
ProposalID: 1,
|
|
||||||
Depositor: addr,
|
|
||||||
Amount: coins,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMigrateEmptyRecord(t *testing.T) {
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
accounts v034accounts.GenesisState
|
|
||||||
deposits []v034gov.DepositWithMetadata
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
}{
|
|
||||||
{"No Accounts", args{v034accounts.GenesisState{}, []v034gov.DepositWithMetadata{}}},
|
|
||||||
{"Deposited account", args{v034accounts.GenesisState{accountDeposited}, []v034gov.DepositWithMetadata{deposit}}},
|
|
||||||
{"Burned account", args{v034accounts.GenesisState{accountBurned}, []v034gov.DepositWithMetadata{}}},
|
|
||||||
{"Burned and deposited accounts", args{v034accounts.GenesisState{accountDeposited, accountBurned}, []v034gov.DepositWithMetadata{deposit}}},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
tt := tt
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
require.NotPanics(t, func() {
|
|
||||||
Migrate(
|
|
||||||
tt.args.accounts,
|
|
||||||
types.Coins{},
|
|
||||||
types.DecCoins{},
|
|
||||||
tt.args.deposits,
|
|
||||||
v034staking.Validators{},
|
|
||||||
[]v034staking.UnbondingDelegation{},
|
|
||||||
[]v034distr.ValidatorOutstandingRewardsRecord{},
|
|
||||||
types.DefaultBondDenom,
|
|
||||||
v034distr.ModuleName,
|
|
||||||
v034gov.ModuleName,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMigrateWrongDeposit(t *testing.T) {
|
|
||||||
require.Panics(t, func() {
|
|
||||||
Migrate(
|
|
||||||
v034accounts.GenesisState{
|
|
||||||
accountDeposited,
|
|
||||||
accountBurned,
|
|
||||||
},
|
|
||||||
types.Coins{},
|
|
||||||
types.DecCoins{},
|
|
||||||
[]v034gov.DepositWithMetadata{
|
|
||||||
{
|
|
||||||
ProposalID: 1,
|
|
||||||
Deposit: v034gov.Deposit{
|
|
||||||
ProposalID: 1,
|
|
||||||
Depositor: addr,
|
|
||||||
Amount: halfCoins,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
v034staking.Validators{},
|
|
||||||
[]v034staking.UnbondingDelegation{},
|
|
||||||
[]v034distr.ValidatorOutstandingRewardsRecord{},
|
|
||||||
types.DefaultBondDenom,
|
|
||||||
v034distr.ModuleName,
|
|
||||||
v034gov.ModuleName,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
// DONTCOVER
|
|
||||||
package v036
|
|
||||||
|
|
||||||
import (
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ModuleName = "accounts"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
GenesisAccount struct {
|
|
||||||
Address sdk.AccAddress `json:"address" yaml:"address"`
|
|
||||||
Coins sdk.Coins `json:"coins" yaml:"coins"`
|
|
||||||
Sequence uint64 `json:"sequence_number" yaml:"sequence_number"`
|
|
||||||
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
|
||||||
|
|
||||||
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"`
|
|
||||||
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"`
|
|
||||||
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"`
|
|
||||||
StartTime int64 `json:"start_time" yaml:"start_time"`
|
|
||||||
EndTime int64 `json:"end_time" yaml:"end_time"`
|
|
||||||
|
|
||||||
ModuleName string `json:"module_name" yaml:"module_name"`
|
|
||||||
ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"`
|
|
||||||
}
|
|
||||||
|
|
||||||
GenesisState []GenesisAccount
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewGenesisAccount creates a new GenesisAccount object
|
|
||||||
func NewGenesisAccount(
|
|
||||||
address sdk.AccAddress, coins sdk.Coins, sequence uint64,
|
|
||||||
vestingAmount, delFree, delVesting sdk.Coins, vestingStartTime, vestingEndTime int64,
|
|
||||||
module string, permissions []string,
|
|
||||||
) GenesisAccount {
|
|
||||||
|
|
||||||
return GenesisAccount{
|
|
||||||
Address: address,
|
|
||||||
Coins: coins,
|
|
||||||
Sequence: sequence,
|
|
||||||
AccountNumber: 0, // ignored set by the account keeper during InitGenesis
|
|
||||||
OriginalVesting: vestingAmount,
|
|
||||||
DelegatedFree: delFree,
|
|
||||||
DelegatedVesting: delVesting,
|
|
||||||
StartTime: vestingStartTime,
|
|
||||||
EndTime: vestingEndTime,
|
|
||||||
ModuleName: module,
|
|
||||||
ModulePermissions: permissions,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,9 +14,6 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/version"
|
"github.com/cosmos/cosmos-sdk/version"
|
||||||
v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v036"
|
|
||||||
v038 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v038"
|
|
||||||
v039 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v039"
|
|
||||||
v040 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v040"
|
v040 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v040"
|
||||||
v043 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v043"
|
v043 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v043"
|
||||||
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||||
|
@ -28,9 +25,6 @@ const flagGenesisTime = "genesis-time"
|
||||||
//
|
//
|
||||||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/5041
|
// Ref: https://github.com/cosmos/cosmos-sdk/issues/5041
|
||||||
var migrationMap = types.MigrationMap{
|
var migrationMap = types.MigrationMap{
|
||||||
"v0.36": v036.Migrate,
|
|
||||||
"v0.38": v038.Migrate, // NOTE: v0.37 and v0.38 are genesis compatible.
|
|
||||||
"v0.39": v039.Migrate,
|
|
||||||
"v0.42": v040.Migrate, // NOTE: v0.40, v0.41 and v0.42 are genesis compatible.
|
"v0.42": v040.Migrate, // NOTE: v0.40, v0.41 and v0.42 are genesis compatible.
|
||||||
"v0.43": v043.Migrate,
|
"v0.43": v043.Migrate,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,6 @@ func (s *IntegrationTestSuite) TestMigrateGenesis() {
|
||||||
expErrMsg string
|
expErrMsg string
|
||||||
check func(jsonOut string)
|
check func(jsonOut string)
|
||||||
}{
|
}{
|
||||||
{
|
|
||||||
"migrate 0.34 to 0.36",
|
|
||||||
`{"chain_id":"test","app_state":{}}`,
|
|
||||||
"v0.36",
|
|
||||||
false, "", func(_ string) {},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"migrate 0.37 to 0.42",
|
"migrate 0.37 to 0.42",
|
||||||
v037Exported,
|
v037Exported,
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue