From e71257aeb789c689c3ff9a848dbb11ddb9b129a0 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 27 Apr 2022 12:07:11 -0400 Subject: [PATCH 01/24] docs: add ADR 054 protobuf semver compatible codegen --- docs/architecture/README.md | 1 + .../adr-054-protobuf-semver-compat-codegen.md | 244 ++++++++++++++++++ 2 files changed, 245 insertions(+) create mode 100644 docs/architecture/adr-054-protobuf-semver-compat-codegen.md diff --git a/docs/architecture/README.md b/docs/architecture/README.md index 18ed71c2df6a..c70642f7ee38 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -78,6 +78,7 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing * [ADR 039: Epoched Staking](./adr-039-epoched-staking.md) * [ADR 040: Storage and SMT State Commitments](./adr-040-storage-and-smt-state-commitments.md) * [ADR 046: Module Params](./adr-046-module-params.md) +* [ADR 054: Protobuf Semver Compatible Codegen](./adr-054-protobuf-semver-compat-codegen.md) ### Draft diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md new file mode 100644 index 000000000000..fa9ce20d8b3b --- /dev/null +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -0,0 +1,244 @@ +# ADR 054: Protobuf Semver Compatible Codegen + +## Changelog + +* 2022-04-27: First draft + +## Status + +PROPOSED + +## Abstract + +> "If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the ADR. +> A short (~200 word) description of the issue being addressed. + +## Context + +There has been [a fair amount of desire](https://github.com/cosmos/cosmos-sdk/discussions/10162) +in the community for semantic versioning in the SDK. How this interacts +with protobuf generated code is [more complex](https://github.com/cosmos/cosmos-sdk/discussions/10162#discussioncomment-1363034) +than it seems at first glance. + +### Problem + +Consider we have a Cosmos SDK module `foo` at a go module v1.x semantic version, +and in that go module there is some generated protobuf code in the protobuf +package `foo.v1` in that module’s `types` package that forms part of the public +API, for instance as part of `Keeper` methods, ex: +```go +// foo/keeper.go + +import "foo/types" + +type Keeper interface { + DoSomething(context.Context, *[]types.Coin) +} +``` + +Now consider that the developer wants to make a breaking change in `foo` that +*does not affect* the `Keeper` interface above at all. So now a new go module +`foo/v2` must be created to follow go semantic versioning. + +The most obvious choice is to move all the code to `foo/v2` including the keeper +so we now have: + +```go +// foo/v2/keeper.go + +import v2types "foo/v2/types" + +type Keeper interface { + DoSomething(context.Context, *[]v2types.Coin) +} +``` + +Note that in this scenario `foo/v2/types` *still* refers to the protobuf package +`foo.v1`! + +Now consider, another go module `bar` with a state machine also at v1.x that +depends on `foo.Keeper`. Let’s say that `bar` doesn’t have any changes but an +app wants to use `foo/v2` together with `bar`. + +Now `bar` can’t be instantiated together with `foo/v2` because it requires the +`foo` v1.x keeper which depends on the generated code in `foo` v1. Even if the +`foo/v2` `Keeper` interface is basically identical to v1 interface, we must +refactor `bar` to work with the new `foo/v2` `Keeper`. And now consumers of +`bar` will also be forced to upgrade to `foo/v2` to get any `bar` updates. +That’s not really a good outcome because it could cause all sorts of downstream +compatibility problems + +To avoid this, we could consider an alternative where `foo/v2` imports `foo` v1 +and exposes the `foo` v1 keeper interface to be compatible. Then `foo/v2` will +need to import the `foo` v1 go module then we have these problems: +* there will be a protobuf namespace conflict because we have the protobuf +package `foo.v1` generated into both `foo/types` and `foo/v2/types` in the +same binary. The startup panic can be disabled with a build flag, but that is a +rather hacky solution. +* `foo/v2` will need to implement a wrapper which converts the `foo/types` +structs to `foo/v2/types` structs which is just unnecessary because they both +represent the *same* protobuf types in `foo.v1`. + +One alternative at this point is to simply tell people not to use go semantic +versioning at all and to keep their packages on `v0.x` forever. This solution, +however, would likely be highly unpopular. + +### API Module Approach + +The first proposed solution was to generate a separate API go module (see +https://github.com/cosmos/cosmos-sdk/discussions/10582). This solution alone, +however, introduces other complexities: + +#### Proto File Versioning + +Versioning of proto files vs the state machine is complicated. The idea with the `api` module is that it stays +forever on `v1.x` and independent proto packages are versioned with package suffixes `v1beta1`, `v1`, `v2`. + +This introduces a bit of a complex versioning scenario where we have a `v1` go module with sub-packages marked alpha or +beta that could be changed or removed. We can deal with this by allowing an explicit exception for packages marked alpha +and beta where those can change independent of the go module version. + +Also it requires state machines to solidify a v1 in a beta or alpha package and then a migration of 1) all the proto +files to v1 and 2) all the state machine code to now reference v1 in two steps at the end of development. If we +call `api` v1 and we have a sub-package `foo/v1` then we really can't break `foo/v1` anymore even if the `foo/v1` state +machine isn't ready. + +**Essentially this makes state machine development more complicated because it prematurely leaks WIP designs to client +libraries.** + +#### Pinned proto images + +As is described in https://github.com/cosmos/cosmos-sdk/discussions/10582), we +would need to pin proto images for state machines in the codec registry +to ensure proper unknown field filtering. This isn't a deal breaker, but it is a bit complex for people to understand +and requires both: + +* an additional build step to configure which may be hard to understand +* fairly complex linting of pinned proto images vs runtime generated + code: https://github.com/cosmos/cosmos-sdk/blob/fdd3d07a28f662c2fabd6007a4a1f64be3a373b3/proto/cosmos/app/v1alpha1/module.proto#L48-L83 + +#### Complex refactoring of interfaces + +As described in https://github.com/cosmos/cosmos-sdk/discussions/10368, all +interface methods on generated code would need to be removed and refactored into +a handler approach. It is a complex refactoring especially of `ValidateBasic` +and alignment on an ideal replacement pattern hasn't been reached yet +(https://github.com/cosmos/cosmos-sdk/pull/11340). + +#### Potential limitations to generated code + +In doing benchmarking of ORM generated code several potential optimizations have emerged and obviously the most +performant optimization would be to generate as much code as possible. But because ORM table descriptors may evolve from +one version to the next with new indexes and fields being added, this makes generated code state machine breaking. +Recall that the API module paradigm requires no state machine breaking logic in generated code. + +## Decision + +To address these issues, we will adopt a hybrid approach which requires changes +to the https://github.com/cosmos/cosmos-proto code generator. + +For client facing code, the API module pattern is still useful given that +care is taken to only publish stable tags when packages are actually stable +and in production. + +For state machine code, the recommended solution is to generate protobuf +code used by the module in an `internal` package and modify the code generator +to *skip global registration* for generated code in internal packages. + +Because there are plenty of cases where we want one module to essentially +be a client of another module, either in `Keeper` method or as proposed in +[ADR 033](./adr-033-protobuf-inter-module-comm.md), modules will need +to use different generated code - for instance from an API module - than +the code used in the state machine itself. + +To address this, we will also modify the code generator to generate interfaces +which allow different concrete structs to be passed into keeper methods and +ADR 033 than those used internally by the module. + +For instance, for a struct `MsgSend`, getters like `GetAmount`, `GetFromAddress`, are already defined so codegen could +create an interface: + +```go +type MsgSendI interface { + protoreflect.ProtoMessage + GetFromAddress() string + GetToAddress() string + GetAmount() []v1beta1.CoinI + + IsCosmosBankV1MsgSend() // this method distinguishes this interface from other proto types which may otherwise implement the same fields. +} +``` + +The gRPC generated server and client could look like this, with the client having +a way to detect the server revision (as described +in https://github.com/cosmos/cosmos-sdk/blob/fdd3d07a28f662c2fabd6007a4a1f64be3a373b3/proto/cosmos/app/v1alpha1/module.proto#L55) +to see which features the server supports if the client is newer: + +```go +type MsgServer interface { + Send(context.Context, MsgSendI) (MsgSendResponseI, error) +} + +type MsgClient interface { + Send(ctx context.Context, in MsgSendI, opts …grpc.CallOption) (MsgSendResponseI, error) + // note that for MsgSendResponseI we would need to have a generated response wrapper type to deal with the case where + // the client is newer than the server + + GetServerRevision() uint64 +} +``` + +This would allow inter-module clients to use different generated code built against potentially different revisions of +the same protobuf package without doing marshaling/unmarshaling between different structs. + +The structs themselves and the ORM could also use these interfaces directly so that the there is no need to do copying +from interfaces to concrete types when dealing with different generated code, ex: + +```go +type MsgSend struct { + FromAddress string + ToAddress string + Amount []v1beta1.CoinI +} + +// for the ORM: +type BalanceTable interface { + Insert(ctx context.Context, balance BalanceI) error + ... +} +``` + +## Consequences + +### Backwards Compatibility + +This approach is more backwards compatible with the existing state machine +code than before, but some changes will be necessitated - first migrating +to the new code generator and secondly modifying `Keeper` methods to use +interfaces rather than concrete structs. + +### Positive + +* no need for pinned proto images in state machines - the codegen would have the correct image +* interface methods can be defined on generated code +* codegen can include other state machine breaking logic, such ORM optimizations + +### Negative + +* file descriptors will need to be manually registered (which is already sort of the case with `RegisterInterfaces`) +* significant changes to the code generator will be required + +### Neutral + + +## Further Discussions + +Further discussions can take place in https://github.com/cosmos/cosmos-sdk/discussions/10582 and within +the Cosmos SDK Framework Working Group. + +## References + +* https://github.com/cosmos/cosmos-sdk/discussions/10162 +* https://github.com/cosmos/cosmos-sdk/discussions/10582 +* https://github.com/cosmos/cosmos-sdk/discussions/10368 +* https://github.com/cosmos/cosmos-sdk/pull/11340 \ No newline at end of file From 75e5adfa584b8a0cee83ee24d25003d696c7d8bb Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 27 Apr 2022 13:51:21 -0400 Subject: [PATCH 02/24] add abstract --- .../adr-054-protobuf-semver-compat-codegen.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index fa9ce20d8b3b..28f580cdc7c3 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -10,8 +10,12 @@ PROPOSED ## Abstract -> "If you can't explain it simply, you don't understand it well enough." Provide a simplified and layman-accessible explanation of the ADR. -> A short (~200 word) description of the issue being addressed. +In order to work well with semantically versioned go modules, some changes to +the cosmos-proto code generator need to be made and best practices need to +be followed. In particular: +* clients should use generated protobuf code in a standalone "API" module +* state machines should use cosmos-proto generated code in `internal/` packages +* protobuf interface types (to be implemented in cosmos-proto) should be used in all public facing API's ## Context From 35ec62ef70206f421b486c2713204bd2b2746eaf Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 8 Nov 2022 09:09:59 -0500 Subject: [PATCH 03/24] WIP --- docs/architecture/adr-054-protobuf-semver-compat-codegen.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index 28f580cdc7c3..c694d6d0d15e 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -87,12 +87,16 @@ One alternative at this point is to simply tell people not to use go semantic versioning at all and to keep their packages on `v0.x` forever. This solution, however, would likely be highly unpopular. -### API Module Approach +### Solutions + +### A) API Module Approach The first proposed solution was to generate a separate API go module (see https://github.com/cosmos/cosmos-sdk/discussions/10582). This solution alone, however, introduces other complexities: +### B) Changes to Generated Code + #### Proto File Versioning Versioning of proto files vs the state machine is complicated. The idea with the `api` module is that it stays From b67cdc04aa108e84bbdf20494af3d3a514736ebe Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 8 Nov 2022 15:59:53 -0500 Subject: [PATCH 04/24] updates --- .../adr-054-protobuf-semver-compat-codegen.md | 85 ++++++++++++++++++- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index c694d6d0d15e..0055aebf7559 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -91,9 +91,88 @@ however, would likely be highly unpopular. ### A) API Module Approach -The first proposed solution was to generate a separate API go module (see -https://github.com/cosmos/cosmos-sdk/discussions/10582). This solution alone, -however, introduces other complexities: +One solution (first proposed in https://github.com/cosmos/cosmos-sdk/discussions/10582) is to isolate all protobuf generated code into a separate module +from the state machine module. This would mean that we could have state machine +go modules `foo` and `foo/v2` which could use a types or API go module say +`foo/api`. This `foo/api` go module would be perpetually on `v1.x` and only +accept non-breaking changes. This would then allow other modules to be +compatible with either `foo` or `foo/v2` as long as the inter-module API only +depends on the types in `foo/api`. + +This approach introduces two complexities which need to be dealt with: +1. if `foo/api` includes any state machine breaking code then this situation is unworkable +because it means that changes to the state machine logic bleed across two go modules +in a hard to reason about manner. Currently, interfaces (such as `sdk.Msg` +or `authz.Authorization` are implemented directly on generated types and these +almost always include state machine breaking logic. +2. the version the protobuf files in `foo/api` at runtime may be different from +the version `foo` or `foo/v2` were built with which could introduce subtle bugs. +For instance, if a field is added to a message in `foo/api` for `foo/v2` but +the original `foo` module doesn't use it, then there may be important data in +that new field which silently gets ignored. + +#### Migrate all interface methods on API types to handlers + +To solve 1), we need to remove all interface implementations from generated +types and start using a handler approach which essentially means that given +a type `X`, we have some sort of router which allows us to resolve some interface +implementation for that type (say `sdk.Msg` or `authz.Authorization`). + +In the case of some methods on `sdk.Msg`, we can replace them with declarative +annotations. For instance, `GetSigners` can already be replaced by the protobuf +annotation `cosmos.msg.v1.signer`. In the future, we may consider some sort +of protobuf validation framework (like https://github.com/bufbuild/protoc-gen-validate +but more Cosmos-specific) to replace `ValidateBasic`. + +#### Pinning State Machine API Compatibility + +One consequence of bundling protobuf types separate from state machine logic is how it affects API forwards +compatibility. By default, protobuf as we're using it is forwards compatible - meaning that newer clients can talk to +older state machines. This can cause problems, however, if fields are added to older messages and clients try to use +these new fields against older state machines. + +For example, say someone adds a field to a message to set an optional expiration time on some operation. If the newer +client sends a message an older state machine with this new expiration field set, the state machine will reject it +based on [ADR 020 Unknown Field Filtering](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). + +This will break down, however, if we package API types separately because an app developer may use an API version that's +newer that the state machine version and then clients can send a message with an expiration time, the state machine will +accept it but ignore it, which is a bug. This isn't a problem now because the protobuf types are codegen'ed directly +into the state machine code so there can be no discrepancy. + +If we migrate to an API module, we will need to pin the API compatibility version in the state machine. Here are two +potential ways to do this: + +##### "Since" Annotations + +In the [Protobuf package versioning discussion](https://github.com/cosmos/cosmos-sdk/discussions/10406) we agreed to +take [approach 2: annotations using "Since" comments](https://github.com/cosmos/cosmos-sdk/pull/10434) to help clients +deal with forwards compatibility gracefully by only enabling newer API features when they know they're talking to a +newer chain. We could use these same annotations in state machines and instruct unknown field filtering to reject +fields in newer API versions if they are present in protobuf generated code. + + +##### Embed raw proto files in state machines + +This would involve using [golang embed](https://pkg.go.dev/embed) to force state machines to embed the proto files they +intended to use in the binary and registering them with the `InterfaceRegistry` which will use them for unknown field +filtering. By using the `embed.FS` type we can force module developers to copy .proto files into the module path and +update them when they want to support newer APIs. A warning could be emitted if an older API verison is registered and +a newer one is available in generated code, alerting modular developers and/or apps to upgrade. + +This second approach is probably less fragile than the "Since" annotations because it could be easy to mess up API +versions with annotations. While these annotations are a good solution for clients like CosmJs which want to support +multiple chains, we need things to be a little stricter inside state machines. + + +To solve 2), state machine modules must be able to specify what the version of +the protobuf files was that they were built against. The simplest way to +do this may be to embed the protobuf `FileDescriptor`s into the module itself +so that these `FileDescriptor`s are used at runtime rather than the ones that +are built into the `foo/api` which may be different. This would involve the +following steps: +1. a build step executed during `make proto-gen` that runs `buf build` to pack the `FileDescriptor`s into an image file +2. a go embed directive to embed the image file ### B) Changes to Generated Code From d96e4f4d9651cc4645ca3fa74cb59b14b0ad6a12 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 15 Nov 2022 13:05:20 -0500 Subject: [PATCH 05/24] revert --- api/amino/amino.pulsar.go | 3 +-- api/cosmos/app/runtime/v1alpha1/module.pulsar.go | 9 ++++----- api/cosmos/app/v1alpha1/config.pulsar.go | 7 +++---- api/cosmos/app/v1alpha1/module.pulsar.go | 7 +++---- api/cosmos/app/v1alpha1/query.pulsar.go | 7 +++---- api/cosmos/auth/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/auth/v1beta1/auth.pulsar.go | 9 ++++----- api/cosmos/auth/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/auth/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/auth/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/authz/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/authz/v1beta1/authz.pulsar.go | 9 ++++----- api/cosmos/authz/v1beta1/event.pulsar.go | 7 +++---- api/cosmos/authz/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/authz/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/authz/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/autocli/v1/options.pulsar.go | 9 ++++----- api/cosmos/autocli/v1/query.pulsar.go | 11 +++++------ api/cosmos/bank/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/bank/v1beta1/authz.pulsar.go | 9 ++++----- api/cosmos/bank/v1beta1/bank.pulsar.go | 9 ++++----- api/cosmos/bank/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/bank/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/bank/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/base/abci/v1beta1/abci.pulsar.go | 9 ++++----- api/cosmos/base/kv/v1beta1/kv.pulsar.go | 7 +++---- api/cosmos/base/node/v1beta1/query.pulsar.go | 7 +++---- .../base/query/v1beta1/pagination.pulsar.go | 7 +++---- .../base/reflection/v1beta1/reflection.pulsar.go | 7 +++---- .../base/reflection/v2alpha1/reflection.pulsar.go | 7 +++---- .../base/snapshots/v1beta1/snapshot.pulsar.go | 7 +++---- .../base/store/v1beta1/commit_info.pulsar.go | 7 +++---- api/cosmos/base/store/v1beta1/listening.pulsar.go | 7 +++---- .../base/tendermint/v1beta1/query.pulsar.go | 9 ++++----- .../base/tendermint/v1beta1/types.pulsar.go | 9 ++++----- api/cosmos/base/v1beta1/coin.pulsar.go | 9 ++++----- api/cosmos/capability/module/v1/module.pulsar.go | 9 ++++----- .../capability/v1beta1/capability.pulsar.go | 9 ++++----- api/cosmos/capability/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/consensus/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/consensus/v1/query.pulsar.go | 9 ++++----- api/cosmos/consensus/v1/tx.pulsar.go | 9 ++++----- api/cosmos/crisis/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/crisis/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/crisis/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/crypto/ed25519/keys.pulsar.go | 9 ++++----- api/cosmos/crypto/hd/v1/hd.pulsar.go | 9 ++++----- api/cosmos/crypto/keyring/v1/record.pulsar.go | 9 ++++----- api/cosmos/crypto/multisig/keys.pulsar.go | 9 ++++----- .../crypto/multisig/v1beta1/multisig.pulsar.go | 7 +++---- api/cosmos/crypto/secp256k1/keys.pulsar.go | 9 ++++----- api/cosmos/crypto/secp256r1/keys.pulsar.go | 7 +++---- .../distribution/module/v1/module.pulsar.go | 9 ++++----- .../distribution/v1beta1/distribution.pulsar.go | 9 ++++----- api/cosmos/distribution/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/distribution/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/distribution/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/evidence/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/evidence/v1beta1/evidence.pulsar.go | 9 ++++----- api/cosmos/evidence/v1beta1/genesis.pulsar.go | 7 +++---- api/cosmos/evidence/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/evidence/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/feegrant/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/feegrant/v1beta1/feegrant.pulsar.go | 9 ++++----- api/cosmos/feegrant/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/feegrant/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/feegrant/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/genutil/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/genutil/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/gov/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/gov/v1/genesis.pulsar.go | 15 +++++++-------- api/cosmos/gov/v1/gov.pulsar.go | 9 ++++----- api/cosmos/gov/v1/query.pulsar.go | 11 +++++------ api/cosmos/gov/v1/tx.pulsar.go | 9 ++++----- api/cosmos/gov/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/gov/v1beta1/gov.pulsar.go | 9 ++++----- api/cosmos/gov/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/gov/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/group/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/group/v1/events.pulsar.go | 7 +++---- api/cosmos/group/v1/genesis.pulsar.go | 7 +++---- api/cosmos/group/v1/query.pulsar.go | 9 ++++----- api/cosmos/group/v1/tx.pulsar.go | 9 ++++----- api/cosmos/group/v1/types.pulsar.go | 9 ++++----- api/cosmos/mint/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/mint/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/mint/v1beta1/mint.pulsar.go | 9 ++++----- api/cosmos/mint/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/mint/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/msg/v1/msg.pulsar.go | 3 +-- api/cosmos/nft/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/nft/v1beta1/event.pulsar.go | 7 +++---- api/cosmos/nft/v1beta1/genesis.pulsar.go | 7 +++---- api/cosmos/nft/v1beta1/nft.pulsar.go | 7 +++---- api/cosmos/nft/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/nft/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/orm/module/v1alpha1/module.pulsar.go | 9 ++++----- api/cosmos/orm/query/v1alpha1/query.pulsar.go | 9 ++++----- api/cosmos/orm/v1/orm.pulsar.go | 7 +++---- api/cosmos/orm/v1alpha1/schema.pulsar.go | 7 +++---- api/cosmos/params/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/params/v1beta1/params.pulsar.go | 9 ++++----- api/cosmos/params/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/query/v1/query.pulsar.go | 3 +-- api/cosmos/reflection/v1/reflection.pulsar.go | 9 ++++----- api/cosmos/slashing/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/slashing/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/slashing/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/slashing/v1beta1/slashing.pulsar.go | 9 ++++----- api/cosmos/slashing/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/staking/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/staking/v1beta1/authz.pulsar.go | 9 ++++----- api/cosmos/staking/v1beta1/genesis.pulsar.go | 9 ++++----- api/cosmos/staking/v1beta1/query.pulsar.go | 9 ++++----- api/cosmos/staking/v1beta1/staking.pulsar.go | 11 +++++------ api/cosmos/staking/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/tx/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/tx/signing/v1beta1/signing.pulsar.go | 9 ++++----- api/cosmos/tx/v1beta1/service.pulsar.go | 9 ++++----- api/cosmos/tx/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/upgrade/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/upgrade/v1beta1/query.pulsar.go | 7 +++---- api/cosmos/upgrade/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/upgrade/v1beta1/upgrade.pulsar.go | 9 ++++----- api/cosmos/vesting/module/v1/module.pulsar.go | 9 ++++----- api/cosmos/vesting/v1beta1/tx.pulsar.go | 9 ++++----- api/cosmos/vesting/v1beta1/vesting.pulsar.go | 9 ++++----- api/tendermint/abci/types.pulsar.go | 9 ++++----- api/tendermint/crypto/keys.pulsar.go | 7 +++---- api/tendermint/crypto/proof.pulsar.go | 9 ++++----- api/tendermint/libs/bits/types.pulsar.go | 7 +++---- api/tendermint/p2p/types.pulsar.go | 7 +++---- api/tendermint/types/block.pulsar.go | 7 +++---- api/tendermint/types/evidence.pulsar.go | 7 +++---- api/tendermint/types/params.pulsar.go | 7 +++---- api/tendermint/types/types.pulsar.go | 9 ++++----- api/tendermint/types/validator.pulsar.go | 9 ++++----- api/tendermint/version/types.pulsar.go | 7 +++---- 138 files changed, 519 insertions(+), 657 deletions(-) diff --git a/api/amino/amino.pulsar.go b/api/amino/amino.pulsar.go index c891d16fcfe1..b6f4a39cd329 100644 --- a/api/amino/amino.pulsar.go +++ b/api/amino/amino.pulsar.go @@ -2,11 +2,10 @@ package amino import ( - reflect "reflect" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" ) // Code generated by protoc-gen-go. DO NOT EDIT. diff --git a/api/cosmos/app/runtime/v1alpha1/module.pulsar.go b/api/cosmos/app/runtime/v1alpha1/module.pulsar.go index ddc7957cc811..56b5ff66fc27 100644 --- a/api/cosmos/app/runtime/v1alpha1/module.pulsar.go +++ b/api/cosmos/app/runtime/v1alpha1/module.pulsar.go @@ -2,16 +2,15 @@ package runtimev1alpha1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Module_2_list)(nil) diff --git a/api/cosmos/app/v1alpha1/config.pulsar.go b/api/cosmos/app/v1alpha1/config.pulsar.go index 9cdc561b92cb..34dfc0d7459c 100644 --- a/api/cosmos/app/v1alpha1/config.pulsar.go +++ b/api/cosmos/app/v1alpha1/config.pulsar.go @@ -3,15 +3,14 @@ package appv1alpha1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Config_1_list)(nil) diff --git a/api/cosmos/app/v1alpha1/module.pulsar.go b/api/cosmos/app/v1alpha1/module.pulsar.go index 07914932e449..914894677e5d 100644 --- a/api/cosmos/app/v1alpha1/module.pulsar.go +++ b/api/cosmos/app/v1alpha1/module.pulsar.go @@ -3,15 +3,14 @@ package appv1alpha1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_ModuleDescriptor_2_list)(nil) diff --git a/api/cosmos/app/v1alpha1/query.pulsar.go b/api/cosmos/app/v1alpha1/query.pulsar.go index 43b4854f79b6..7de26bd84a94 100644 --- a/api/cosmos/app/v1alpha1/query.pulsar.go +++ b/api/cosmos/app/v1alpha1/query.pulsar.go @@ -3,14 +3,13 @@ package appv1alpha1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/auth/module/v1/module.pulsar.go b/api/cosmos/auth/module/v1/module.pulsar.go index 02db65a2befa..2ba0bff52d41 100644 --- a/api/cosmos/auth/module/v1/module.pulsar.go +++ b/api/cosmos/auth/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Module_2_list)(nil) diff --git a/api/cosmos/auth/v1beta1/auth.pulsar.go b/api/cosmos/auth/v1beta1/auth.pulsar.go index c356c7fe3de3..350e83eb532d 100644 --- a/api/cosmos/auth/v1beta1/auth.pulsar.go +++ b/api/cosmos/auth/v1beta1/auth.pulsar.go @@ -2,12 +2,8 @@ package authv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -15,6 +11,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/auth/v1beta1/genesis.pulsar.go b/api/cosmos/auth/v1beta1/genesis.pulsar.go index bb6f0d67198e..427e80bd6c5e 100644 --- a/api/cosmos/auth/v1beta1/genesis.pulsar.go +++ b/api/cosmos/auth/v1beta1/genesis.pulsar.go @@ -2,18 +2,17 @@ package authv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) diff --git a/api/cosmos/auth/v1beta1/query.pulsar.go b/api/cosmos/auth/v1beta1/query.pulsar.go index fa2ce338aee9..cea8222a35fe 100644 --- a/api/cosmos/auth/v1beta1/query.pulsar.go +++ b/api/cosmos/auth/v1beta1/query.pulsar.go @@ -2,13 +2,9 @@ package authv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" _ "cosmossdk.io/api/cosmos/query/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/auth/v1beta1/tx.pulsar.go b/api/cosmos/auth/v1beta1/tx.pulsar.go index f96b48af0c09..cff25a1f6244 100644 --- a/api/cosmos/auth/v1beta1/tx.pulsar.go +++ b/api/cosmos/auth/v1beta1/tx.pulsar.go @@ -2,19 +2,18 @@ package authv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/authz/module/v1/module.pulsar.go b/api/cosmos/authz/module/v1/module.pulsar.go index db20b5b1e943..3d47071ad7af 100644 --- a/api/cosmos/authz/module/v1/module.pulsar.go +++ b/api/cosmos/authz/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/authz/v1beta1/authz.pulsar.go b/api/cosmos/authz/v1beta1/authz.pulsar.go index e1060e571a4d..938b2159fe75 100644 --- a/api/cosmos/authz/v1beta1/authz.pulsar.go +++ b/api/cosmos/authz/v1beta1/authz.pulsar.go @@ -2,12 +2,8 @@ package authzv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/authz/v1beta1/event.pulsar.go b/api/cosmos/authz/v1beta1/event.pulsar.go index fbfdf45ed0d9..88a142363ea2 100644 --- a/api/cosmos/authz/v1beta1/event.pulsar.go +++ b/api/cosmos/authz/v1beta1/event.pulsar.go @@ -3,15 +3,14 @@ package authzv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/authz/v1beta1/genesis.pulsar.go b/api/cosmos/authz/v1beta1/genesis.pulsar.go index cdc14f007a2e..edcab7bbb446 100644 --- a/api/cosmos/authz/v1beta1/genesis.pulsar.go +++ b/api/cosmos/authz/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package authzv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_1_list)(nil) diff --git a/api/cosmos/authz/v1beta1/query.pulsar.go b/api/cosmos/authz/v1beta1/query.pulsar.go index d2a6b900de00..0f776d3cde17 100644 --- a/api/cosmos/authz/v1beta1/query.pulsar.go +++ b/api/cosmos/authz/v1beta1/query.pulsar.go @@ -2,18 +2,17 @@ package authzv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/authz/v1beta1/tx.pulsar.go b/api/cosmos/authz/v1beta1/tx.pulsar.go index aed964e5067a..777d11f73592 100644 --- a/api/cosmos/authz/v1beta1/tx.pulsar.go +++ b/api/cosmos/authz/v1beta1/tx.pulsar.go @@ -2,13 +2,9 @@ package authzv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/autocli/v1/options.pulsar.go b/api/cosmos/autocli/v1/options.pulsar.go index 8cbfff77ca01..bc175f979e1d 100644 --- a/api/cosmos/autocli/v1/options.pulsar.go +++ b/api/cosmos/autocli/v1/options.pulsar.go @@ -3,15 +3,14 @@ package autocliv1 import ( fmt "fmt" - io "io" - reflect "reflect" - sort "sort" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sort "sort" + sync "sync" ) var ( diff --git a/api/cosmos/autocli/v1/query.pulsar.go b/api/cosmos/autocli/v1/query.pulsar.go index 450f81784cfa..ce5f90ba7c69 100644 --- a/api/cosmos/autocli/v1/query.pulsar.go +++ b/api/cosmos/autocli/v1/query.pulsar.go @@ -2,17 +2,16 @@ package autocliv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sort "sort" - sync "sync" - _ "cosmossdk.io/api/cosmos/query/v1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sort "sort" + sync "sync" ) var ( diff --git a/api/cosmos/bank/module/v1/module.pulsar.go b/api/cosmos/bank/module/v1/module.pulsar.go index 9e7e3c189aef..64e252a4af23 100644 --- a/api/cosmos/bank/module/v1/module.pulsar.go +++ b/api/cosmos/bank/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Module_1_list)(nil) diff --git a/api/cosmos/bank/v1beta1/authz.pulsar.go b/api/cosmos/bank/v1beta1/authz.pulsar.go index 5435ef7ee940..bfcbfd3ba578 100644 --- a/api/cosmos/bank/v1beta1/authz.pulsar.go +++ b/api/cosmos/bank/v1beta1/authz.pulsar.go @@ -2,19 +2,18 @@ package bankv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_SendAuthorization_1_list)(nil) diff --git a/api/cosmos/bank/v1beta1/bank.pulsar.go b/api/cosmos/bank/v1beta1/bank.pulsar.go index 5c2e6c89c3ba..e51499479116 100644 --- a/api/cosmos/bank/v1beta1/bank.pulsar.go +++ b/api/cosmos/bank/v1beta1/bank.pulsar.go @@ -2,20 +2,19 @@ package bankv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Params_1_list)(nil) diff --git a/api/cosmos/bank/v1beta1/genesis.pulsar.go b/api/cosmos/bank/v1beta1/genesis.pulsar.go index 7f5c36f9a758..73a8226986d4 100644 --- a/api/cosmos/bank/v1beta1/genesis.pulsar.go +++ b/api/cosmos/bank/v1beta1/genesis.pulsar.go @@ -2,19 +2,18 @@ package bankv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) diff --git a/api/cosmos/bank/v1beta1/query.pulsar.go b/api/cosmos/bank/v1beta1/query.pulsar.go index f56c56f7c747..bfd36bd11895 100644 --- a/api/cosmos/bank/v1beta1/query.pulsar.go +++ b/api/cosmos/bank/v1beta1/query.pulsar.go @@ -2,15 +2,11 @@ package bankv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta11 "cosmossdk.io/api/cosmos/base/query/v1beta1" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/query/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -18,6 +14,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/bank/v1beta1/tx.pulsar.go b/api/cosmos/bank/v1beta1/tx.pulsar.go index 72d66ab35516..96bdddda3037 100644 --- a/api/cosmos/bank/v1beta1/tx.pulsar.go +++ b/api/cosmos/bank/v1beta1/tx.pulsar.go @@ -2,20 +2,19 @@ package bankv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MsgSend_3_list)(nil) diff --git a/api/cosmos/base/abci/v1beta1/abci.pulsar.go b/api/cosmos/base/abci/v1beta1/abci.pulsar.go index cf3623c96274..6d3253676da1 100644 --- a/api/cosmos/base/abci/v1beta1/abci.pulsar.go +++ b/api/cosmos/base/abci/v1beta1/abci.pulsar.go @@ -2,18 +2,17 @@ package abciv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - abci "cosmossdk.io/api/tendermint/abci" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_TxResponse_7_list)(nil) diff --git a/api/cosmos/base/kv/v1beta1/kv.pulsar.go b/api/cosmos/base/kv/v1beta1/kv.pulsar.go index 2077d52dbf47..2207271cc025 100644 --- a/api/cosmos/base/kv/v1beta1/kv.pulsar.go +++ b/api/cosmos/base/kv/v1beta1/kv.pulsar.go @@ -3,15 +3,14 @@ package kvv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Pairs_1_list)(nil) diff --git a/api/cosmos/base/node/v1beta1/query.pulsar.go b/api/cosmos/base/node/v1beta1/query.pulsar.go index b5958abe9720..600b4d5d3668 100644 --- a/api/cosmos/base/node/v1beta1/query.pulsar.go +++ b/api/cosmos/base/node/v1beta1/query.pulsar.go @@ -3,15 +3,14 @@ package nodev1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/query/v1beta1/pagination.pulsar.go b/api/cosmos/base/query/v1beta1/pagination.pulsar.go index ca31557e015d..1d5fe3521990 100644 --- a/api/cosmos/base/query/v1beta1/pagination.pulsar.go +++ b/api/cosmos/base/query/v1beta1/pagination.pulsar.go @@ -3,14 +3,13 @@ package queryv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/reflection/v1beta1/reflection.pulsar.go b/api/cosmos/base/reflection/v1beta1/reflection.pulsar.go index 0f89f5b6a7e4..f886d9174051 100644 --- a/api/cosmos/base/reflection/v1beta1/reflection.pulsar.go +++ b/api/cosmos/base/reflection/v1beta1/reflection.pulsar.go @@ -3,15 +3,14 @@ package reflectionv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/reflection/v2alpha1/reflection.pulsar.go b/api/cosmos/base/reflection/v2alpha1/reflection.pulsar.go index f32a7336b9c5..c0910852b765 100644 --- a/api/cosmos/base/reflection/v2alpha1/reflection.pulsar.go +++ b/api/cosmos/base/reflection/v2alpha1/reflection.pulsar.go @@ -3,15 +3,14 @@ package reflectionv2alpha1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/snapshots/v1beta1/snapshot.pulsar.go b/api/cosmos/base/snapshots/v1beta1/snapshot.pulsar.go index ccc54499ecaa..3e595a928356 100644 --- a/api/cosmos/base/snapshots/v1beta1/snapshot.pulsar.go +++ b/api/cosmos/base/snapshots/v1beta1/snapshot.pulsar.go @@ -3,15 +3,14 @@ package snapshotsv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/store/v1beta1/commit_info.pulsar.go b/api/cosmos/base/store/v1beta1/commit_info.pulsar.go index a4db547919bf..4e259d858705 100644 --- a/api/cosmos/base/store/v1beta1/commit_info.pulsar.go +++ b/api/cosmos/base/store/v1beta1/commit_info.pulsar.go @@ -3,15 +3,14 @@ package storev1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_CommitInfo_2_list)(nil) diff --git a/api/cosmos/base/store/v1beta1/listening.pulsar.go b/api/cosmos/base/store/v1beta1/listening.pulsar.go index 07d4df5a6642..3ab973ac3937 100644 --- a/api/cosmos/base/store/v1beta1/listening.pulsar.go +++ b/api/cosmos/base/store/v1beta1/listening.pulsar.go @@ -3,14 +3,13 @@ package storev1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/tendermint/v1beta1/query.pulsar.go b/api/cosmos/base/tendermint/v1beta1/query.pulsar.go index 1bcf5aeb7333..ace9ead07407 100644 --- a/api/cosmos/base/tendermint/v1beta1/query.pulsar.go +++ b/api/cosmos/base/tendermint/v1beta1/query.pulsar.go @@ -2,15 +2,11 @@ package tendermintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" p2p "cosmossdk.io/api/tendermint/p2p" types "cosmossdk.io/api/tendermint/types" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -19,6 +15,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/tendermint/v1beta1/types.pulsar.go b/api/cosmos/base/tendermint/v1beta1/types.pulsar.go index 094fc2637d5f..3b813632fe64 100644 --- a/api/cosmos/base/tendermint/v1beta1/types.pulsar.go +++ b/api/cosmos/base/tendermint/v1beta1/types.pulsar.go @@ -2,20 +2,19 @@ package tendermintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" types "cosmossdk.io/api/tendermint/types" version "cosmossdk.io/api/tendermint/version" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/base/v1beta1/coin.pulsar.go b/api/cosmos/base/v1beta1/coin.pulsar.go index aa88b78bec21..26b79e11737d 100644 --- a/api/cosmos/base/v1beta1/coin.pulsar.go +++ b/api/cosmos/base/v1beta1/coin.pulsar.go @@ -2,18 +2,17 @@ package basev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/capability/module/v1/module.pulsar.go b/api/cosmos/capability/module/v1/module.pulsar.go index 6a4c1c3a7807..800b6589a870 100644 --- a/api/cosmos/capability/module/v1/module.pulsar.go +++ b/api/cosmos/capability/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/capability/v1beta1/capability.pulsar.go b/api/cosmos/capability/v1beta1/capability.pulsar.go index d09f77969436..aca991141b70 100644 --- a/api/cosmos/capability/v1beta1/capability.pulsar.go +++ b/api/cosmos/capability/v1beta1/capability.pulsar.go @@ -2,17 +2,16 @@ package capabilityv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/capability/v1beta1/genesis.pulsar.go b/api/cosmos/capability/v1beta1/genesis.pulsar.go index 49d2dc2c07e4..171eb7f67660 100644 --- a/api/cosmos/capability/v1beta1/genesis.pulsar.go +++ b/api/cosmos/capability/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package capabilityv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/consensus/module/v1/module.pulsar.go b/api/cosmos/consensus/module/v1/module.pulsar.go index 81a1ca1b8a93..1ec17c3a5e11 100644 --- a/api/cosmos/consensus/module/v1/module.pulsar.go +++ b/api/cosmos/consensus/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/consensus/v1/query.pulsar.go b/api/cosmos/consensus/v1/query.pulsar.go index 373fb2ba4c56..8cce55a6a622 100644 --- a/api/cosmos/consensus/v1/query.pulsar.go +++ b/api/cosmos/consensus/v1/query.pulsar.go @@ -2,17 +2,16 @@ package consensusv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - types "cosmossdk.io/api/tendermint/types" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/consensus/v1/tx.pulsar.go b/api/cosmos/consensus/v1/tx.pulsar.go index 9fbb166d6dd3..fbfaf5d071dc 100644 --- a/api/cosmos/consensus/v1/tx.pulsar.go +++ b/api/cosmos/consensus/v1/tx.pulsar.go @@ -2,18 +2,17 @@ package consensusv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/msg/v1" types "cosmossdk.io/api/tendermint/types" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crisis/module/v1/module.pulsar.go b/api/cosmos/crisis/module/v1/module.pulsar.go index 0d110737ac7b..1971d71c9a59 100644 --- a/api/cosmos/crisis/module/v1/module.pulsar.go +++ b/api/cosmos/crisis/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crisis/v1beta1/genesis.pulsar.go b/api/cosmos/crisis/v1beta1/genesis.pulsar.go index fdb4ca547028..301a23ec5000 100644 --- a/api/cosmos/crisis/v1beta1/genesis.pulsar.go +++ b/api/cosmos/crisis/v1beta1/genesis.pulsar.go @@ -2,18 +2,17 @@ package crisisv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crisis/v1beta1/tx.pulsar.go b/api/cosmos/crisis/v1beta1/tx.pulsar.go index 6215403fc525..5afe16e7cd62 100644 --- a/api/cosmos/crisis/v1beta1/tx.pulsar.go +++ b/api/cosmos/crisis/v1beta1/tx.pulsar.go @@ -2,20 +2,19 @@ package crisisv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crypto/ed25519/keys.pulsar.go b/api/cosmos/crypto/ed25519/keys.pulsar.go index fb7d77e94e2d..13e2cf837e49 100644 --- a/api/cosmos/crypto/ed25519/keys.pulsar.go +++ b/api/cosmos/crypto/ed25519/keys.pulsar.go @@ -2,17 +2,16 @@ package ed25519 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crypto/hd/v1/hd.pulsar.go b/api/cosmos/crypto/hd/v1/hd.pulsar.go index 8e9530a873d6..2ddd2b875dc0 100644 --- a/api/cosmos/crypto/hd/v1/hd.pulsar.go +++ b/api/cosmos/crypto/hd/v1/hd.pulsar.go @@ -2,17 +2,16 @@ package hdv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crypto/keyring/v1/record.pulsar.go b/api/cosmos/crypto/keyring/v1/record.pulsar.go index ee9a43ae5d91..8c04e58545f4 100644 --- a/api/cosmos/crypto/keyring/v1/record.pulsar.go +++ b/api/cosmos/crypto/keyring/v1/record.pulsar.go @@ -2,18 +2,17 @@ package keyringv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1 "cosmossdk.io/api/cosmos/crypto/hd/v1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crypto/multisig/keys.pulsar.go b/api/cosmos/crypto/multisig/keys.pulsar.go index e9717f9f4872..e1f2f1c9c423 100644 --- a/api/cosmos/crypto/multisig/keys.pulsar.go +++ b/api/cosmos/crypto/multisig/keys.pulsar.go @@ -2,18 +2,17 @@ package multisig import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_LegacyAminoPubKey_2_list)(nil) diff --git a/api/cosmos/crypto/multisig/v1beta1/multisig.pulsar.go b/api/cosmos/crypto/multisig/v1beta1/multisig.pulsar.go index 70daa48d0d76..2bf4fc7cd6cc 100644 --- a/api/cosmos/crypto/multisig/v1beta1/multisig.pulsar.go +++ b/api/cosmos/crypto/multisig/v1beta1/multisig.pulsar.go @@ -3,15 +3,14 @@ package multisigv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MultiSignature_1_list)(nil) diff --git a/api/cosmos/crypto/secp256k1/keys.pulsar.go b/api/cosmos/crypto/secp256k1/keys.pulsar.go index 71e44d9ff356..93e13424729b 100644 --- a/api/cosmos/crypto/secp256k1/keys.pulsar.go +++ b/api/cosmos/crypto/secp256k1/keys.pulsar.go @@ -2,17 +2,16 @@ package secp256k1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/crypto/secp256r1/keys.pulsar.go b/api/cosmos/crypto/secp256r1/keys.pulsar.go index fad556f313ee..02f122b0a878 100644 --- a/api/cosmos/crypto/secp256r1/keys.pulsar.go +++ b/api/cosmos/crypto/secp256r1/keys.pulsar.go @@ -3,15 +3,14 @@ package secp256r1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/distribution/module/v1/module.pulsar.go b/api/cosmos/distribution/module/v1/module.pulsar.go index 2068d8395215..1e35d5529417 100644 --- a/api/cosmos/distribution/module/v1/module.pulsar.go +++ b/api/cosmos/distribution/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/distribution/v1beta1/distribution.pulsar.go b/api/cosmos/distribution/v1beta1/distribution.pulsar.go index 51e7ef25cb19..5668e861009d 100644 --- a/api/cosmos/distribution/v1beta1/distribution.pulsar.go +++ b/api/cosmos/distribution/v1beta1/distribution.pulsar.go @@ -2,19 +2,18 @@ package distributionv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/distribution/v1beta1/genesis.pulsar.go b/api/cosmos/distribution/v1beta1/genesis.pulsar.go index 1b39478363f7..9af94e2eedd7 100644 --- a/api/cosmos/distribution/v1beta1/genesis.pulsar.go +++ b/api/cosmos/distribution/v1beta1/genesis.pulsar.go @@ -2,19 +2,18 @@ package distributionv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/distribution/v1beta1/query.pulsar.go b/api/cosmos/distribution/v1beta1/query.pulsar.go index a3be0a2dbf52..ae9656c2e57e 100644 --- a/api/cosmos/distribution/v1beta1/query.pulsar.go +++ b/api/cosmos/distribution/v1beta1/query.pulsar.go @@ -2,14 +2,10 @@ package distributionv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta11 "cosmossdk.io/api/cosmos/base/query/v1beta1" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/distribution/v1beta1/tx.pulsar.go b/api/cosmos/distribution/v1beta1/tx.pulsar.go index e194da0db206..4f1e1af51097 100644 --- a/api/cosmos/distribution/v1beta1/tx.pulsar.go +++ b/api/cosmos/distribution/v1beta1/tx.pulsar.go @@ -2,20 +2,19 @@ package distributionv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/evidence/module/v1/module.pulsar.go b/api/cosmos/evidence/module/v1/module.pulsar.go index c06e956b21b4..27cb57703a02 100644 --- a/api/cosmos/evidence/module/v1/module.pulsar.go +++ b/api/cosmos/evidence/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/evidence/v1beta1/evidence.pulsar.go b/api/cosmos/evidence/v1beta1/evidence.pulsar.go index 5cb3ff13858f..cef8dc055189 100644 --- a/api/cosmos/evidence/v1beta1/evidence.pulsar.go +++ b/api/cosmos/evidence/v1beta1/evidence.pulsar.go @@ -2,12 +2,8 @@ package evidencev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -15,6 +11,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/evidence/v1beta1/genesis.pulsar.go b/api/cosmos/evidence/v1beta1/genesis.pulsar.go index 757adc30755c..41bf5951f0e2 100644 --- a/api/cosmos/evidence/v1beta1/genesis.pulsar.go +++ b/api/cosmos/evidence/v1beta1/genesis.pulsar.go @@ -3,15 +3,14 @@ package evidencev1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_1_list)(nil) diff --git a/api/cosmos/evidence/v1beta1/query.pulsar.go b/api/cosmos/evidence/v1beta1/query.pulsar.go index bbf725a2b7ad..caaf87ae77df 100644 --- a/api/cosmos/evidence/v1beta1/query.pulsar.go +++ b/api/cosmos/evidence/v1beta1/query.pulsar.go @@ -2,12 +2,8 @@ package evidencev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" _ "google.golang.org/genproto/googleapis/api/annotations" @@ -15,6 +11,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/evidence/v1beta1/tx.pulsar.go b/api/cosmos/evidence/v1beta1/tx.pulsar.go index c0c4a9a69ea1..771e8d7a50f0 100644 --- a/api/cosmos/evidence/v1beta1/tx.pulsar.go +++ b/api/cosmos/evidence/v1beta1/tx.pulsar.go @@ -2,13 +2,9 @@ package evidencev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/feegrant/module/v1/module.pulsar.go b/api/cosmos/feegrant/module/v1/module.pulsar.go index 86fa50197311..ab597c9a0319 100644 --- a/api/cosmos/feegrant/module/v1/module.pulsar.go +++ b/api/cosmos/feegrant/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/feegrant/v1beta1/feegrant.pulsar.go b/api/cosmos/feegrant/v1beta1/feegrant.pulsar.go index c3cab6d86fbd..71e521f5edf1 100644 --- a/api/cosmos/feegrant/v1beta1/feegrant.pulsar.go +++ b/api/cosmos/feegrant/v1beta1/feegrant.pulsar.go @@ -2,13 +2,9 @@ package feegrantv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -18,6 +14,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_BasicAllowance_1_list)(nil) diff --git a/api/cosmos/feegrant/v1beta1/genesis.pulsar.go b/api/cosmos/feegrant/v1beta1/genesis.pulsar.go index 98ee45d6208a..459af1b1511d 100644 --- a/api/cosmos/feegrant/v1beta1/genesis.pulsar.go +++ b/api/cosmos/feegrant/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package feegrantv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_1_list)(nil) diff --git a/api/cosmos/feegrant/v1beta1/query.pulsar.go b/api/cosmos/feegrant/v1beta1/query.pulsar.go index 389d6eabca74..e6e62a22666c 100644 --- a/api/cosmos/feegrant/v1beta1/query.pulsar.go +++ b/api/cosmos/feegrant/v1beta1/query.pulsar.go @@ -2,18 +2,17 @@ package feegrantv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/feegrant/v1beta1/tx.pulsar.go b/api/cosmos/feegrant/v1beta1/tx.pulsar.go index 04a44adf7b37..05e2e20a34d0 100644 --- a/api/cosmos/feegrant/v1beta1/tx.pulsar.go +++ b/api/cosmos/feegrant/v1beta1/tx.pulsar.go @@ -2,19 +2,18 @@ package feegrantv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/genutil/module/v1/module.pulsar.go b/api/cosmos/genutil/module/v1/module.pulsar.go index f0b28d1023eb..8c55661e19ff 100644 --- a/api/cosmos/genutil/module/v1/module.pulsar.go +++ b/api/cosmos/genutil/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/genutil/v1beta1/genesis.pulsar.go b/api/cosmos/genutil/v1beta1/genesis.pulsar.go index 7de100fd0ee3..4382a8bc801d 100644 --- a/api/cosmos/genutil/v1beta1/genesis.pulsar.go +++ b/api/cosmos/genutil/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package genutilv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_1_list)(nil) diff --git a/api/cosmos/gov/module/v1/module.pulsar.go b/api/cosmos/gov/module/v1/module.pulsar.go index 9d11925203a7..3e235484cd29 100644 --- a/api/cosmos/gov/module/v1/module.pulsar.go +++ b/api/cosmos/gov/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/gov/v1/genesis.pulsar.go b/api/cosmos/gov/v1/genesis.pulsar.go index 3243b4be2469..645e02ec192e 100644 --- a/api/cosmos/gov/v1/genesis.pulsar.go +++ b/api/cosmos/gov/v1/genesis.pulsar.go @@ -3,14 +3,13 @@ package govv1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) @@ -1177,21 +1176,21 @@ type GenesisState struct { // proposals defines all the proposals present at genesis. Proposals []*Proposal `protobuf:"bytes,4,rep,name=proposals,proto3" json:"proposals,omitempty"` // Deprecated: Prefer to use `params` instead. - // deposit_params defines all the parameters of related to deposit. + // deposit_params defines all the paramaters of related to deposit. // // Deprecated: Do not use. DepositParams *DepositParams `protobuf:"bytes,5,opt,name=deposit_params,json=depositParams,proto3" json:"deposit_params,omitempty"` // Deprecated: Prefer to use `params` instead. - // voting_params defines all the parameters of related to voting. + // voting_params defines all the paramaters of related to voting. // // Deprecated: Do not use. VotingParams *VotingParams `protobuf:"bytes,6,opt,name=voting_params,json=votingParams,proto3" json:"voting_params,omitempty"` // Deprecated: Prefer to use `params` instead. - // tally_params defines all the parameters of related to tally. + // tally_params defines all the paramaters of related to tally. // // Deprecated: Do not use. TallyParams *TallyParams `protobuf:"bytes,7,opt,name=tally_params,json=tallyParams,proto3" json:"tally_params,omitempty"` - // params defines all the parameters of x/gov module. + // params defines all the paramaters of x/gov module. // // Since: cosmos-sdk 0.47 Params *Params `protobuf:"bytes,8,opt,name=params,proto3" json:"params,omitempty"` diff --git a/api/cosmos/gov/v1/gov.pulsar.go b/api/cosmos/gov/v1/gov.pulsar.go index 16785dd8779e..b3dd58910bf1 100644 --- a/api/cosmos/gov/v1/gov.pulsar.go +++ b/api/cosmos/gov/v1/gov.pulsar.go @@ -2,13 +2,9 @@ package govv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -18,6 +14,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/gov/v1/query.pulsar.go b/api/cosmos/gov/v1/query.pulsar.go index 9782419b1d17..677db1c20190 100644 --- a/api/cosmos/gov/v1/query.pulsar.go +++ b/api/cosmos/gov/v1/query.pulsar.go @@ -2,18 +2,17 @@ package govv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( @@ -8320,7 +8319,7 @@ type QueryParamsResponse struct { // // Deprecated: Do not use. TallyParams *TallyParams `protobuf:"bytes,3,opt,name=tally_params,json=tallyParams,proto3" json:"tally_params,omitempty"` - // params defines all the parameters of x/gov module. + // params defines all the paramaters of x/gov module. // // Since: cosmos-sdk 0.47 Params *Params `protobuf:"bytes,4,opt,name=params,proto3" json:"params,omitempty"` diff --git a/api/cosmos/gov/v1/tx.pulsar.go b/api/cosmos/gov/v1/tx.pulsar.go index ebeae9f302cc..2fa6b15ea97c 100644 --- a/api/cosmos/gov/v1/tx.pulsar.go +++ b/api/cosmos/gov/v1/tx.pulsar.go @@ -2,14 +2,10 @@ package govv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MsgSubmitProposal_1_list)(nil) diff --git a/api/cosmos/gov/v1beta1/genesis.pulsar.go b/api/cosmos/gov/v1beta1/genesis.pulsar.go index b94ea16a4ead..b66ffd18f9da 100644 --- a/api/cosmos/gov/v1beta1/genesis.pulsar.go +++ b/api/cosmos/gov/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package govv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) diff --git a/api/cosmos/gov/v1beta1/gov.pulsar.go b/api/cosmos/gov/v1beta1/gov.pulsar.go index 3ec07c8f919d..7f5ad0503ae6 100644 --- a/api/cosmos/gov/v1beta1/gov.pulsar.go +++ b/api/cosmos/gov/v1beta1/gov.pulsar.go @@ -2,13 +2,9 @@ package govv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -18,6 +14,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/gov/v1beta1/query.pulsar.go b/api/cosmos/gov/v1beta1/query.pulsar.go index d233e8e673a9..4ef848fa055d 100644 --- a/api/cosmos/gov/v1beta1/query.pulsar.go +++ b/api/cosmos/gov/v1beta1/query.pulsar.go @@ -2,13 +2,9 @@ package govv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/gov/v1beta1/tx.pulsar.go b/api/cosmos/gov/v1beta1/tx.pulsar.go index 5469866cdb0b..2bc9fd0486eb 100644 --- a/api/cosmos/gov/v1beta1/tx.pulsar.go +++ b/api/cosmos/gov/v1beta1/tx.pulsar.go @@ -2,14 +2,10 @@ package govv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MsgSubmitProposal_2_list)(nil) diff --git a/api/cosmos/group/module/v1/module.pulsar.go b/api/cosmos/group/module/v1/module.pulsar.go index b399315a1808..d79dc4f53698 100644 --- a/api/cosmos/group/module/v1/module.pulsar.go +++ b/api/cosmos/group/module/v1/module.pulsar.go @@ -2,19 +2,18 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/group/v1/events.pulsar.go b/api/cosmos/group/v1/events.pulsar.go index 9f37fd3ce13e..5352013f75c7 100644 --- a/api/cosmos/group/v1/events.pulsar.go +++ b/api/cosmos/group/v1/events.pulsar.go @@ -3,15 +3,14 @@ package groupv1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/group/v1/genesis.pulsar.go b/api/cosmos/group/v1/genesis.pulsar.go index 2f913ce753fe..df985263a9ae 100644 --- a/api/cosmos/group/v1/genesis.pulsar.go +++ b/api/cosmos/group/v1/genesis.pulsar.go @@ -3,14 +3,13 @@ package groupv1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) diff --git a/api/cosmos/group/v1/query.pulsar.go b/api/cosmos/group/v1/query.pulsar.go index 342df86ddeb9..a281a95ce4d2 100644 --- a/api/cosmos/group/v1/query.pulsar.go +++ b/api/cosmos/group/v1/query.pulsar.go @@ -2,13 +2,9 @@ package groupv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/group/v1/tx.pulsar.go b/api/cosmos/group/v1/tx.pulsar.go index a766c613ef22..2d9b105c8cfa 100644 --- a/api/cosmos/group/v1/tx.pulsar.go +++ b/api/cosmos/group/v1/tx.pulsar.go @@ -2,13 +2,9 @@ package groupv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MsgCreateGroup_2_list)(nil) diff --git a/api/cosmos/group/v1/types.pulsar.go b/api/cosmos/group/v1/types.pulsar.go index 36454db1a2e3..392c826184c8 100644 --- a/api/cosmos/group/v1/types.pulsar.go +++ b/api/cosmos/group/v1/types.pulsar.go @@ -2,12 +2,8 @@ package groupv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/mint/module/v1/module.pulsar.go b/api/cosmos/mint/module/v1/module.pulsar.go index 0a4c30f4b5a8..6d9884be4b1d 100644 --- a/api/cosmos/mint/module/v1/module.pulsar.go +++ b/api/cosmos/mint/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/mint/v1beta1/genesis.pulsar.go b/api/cosmos/mint/v1beta1/genesis.pulsar.go index ecbcb061073e..d0ab55cd4025 100644 --- a/api/cosmos/mint/v1beta1/genesis.pulsar.go +++ b/api/cosmos/mint/v1beta1/genesis.pulsar.go @@ -2,17 +2,16 @@ package mintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/mint/v1beta1/mint.pulsar.go b/api/cosmos/mint/v1beta1/mint.pulsar.go index b8019542634b..ee021a461c52 100644 --- a/api/cosmos/mint/v1beta1/mint.pulsar.go +++ b/api/cosmos/mint/v1beta1/mint.pulsar.go @@ -2,18 +2,17 @@ package mintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/mint/v1beta1/query.pulsar.go b/api/cosmos/mint/v1beta1/query.pulsar.go index dcd64b03ee33..6d58cbccadb4 100644 --- a/api/cosmos/mint/v1beta1/query.pulsar.go +++ b/api/cosmos/mint/v1beta1/query.pulsar.go @@ -2,18 +2,17 @@ package mintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/mint/v1beta1/tx.pulsar.go b/api/cosmos/mint/v1beta1/tx.pulsar.go index bbd827351d42..0bc2c3de0589 100644 --- a/api/cosmos/mint/v1beta1/tx.pulsar.go +++ b/api/cosmos/mint/v1beta1/tx.pulsar.go @@ -2,19 +2,18 @@ package mintv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/msg/v1/msg.pulsar.go b/api/cosmos/msg/v1/msg.pulsar.go index 2664b1106586..7bf986dd12c5 100644 --- a/api/cosmos/msg/v1/msg.pulsar.go +++ b/api/cosmos/msg/v1/msg.pulsar.go @@ -2,11 +2,10 @@ package msgv1 import ( - reflect "reflect" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" ) // Code generated by protoc-gen-go. DO NOT EDIT. diff --git a/api/cosmos/nft/module/v1/module.pulsar.go b/api/cosmos/nft/module/v1/module.pulsar.go index 37ed8c586602..b1552f0e7374 100644 --- a/api/cosmos/nft/module/v1/module.pulsar.go +++ b/api/cosmos/nft/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/nft/v1beta1/event.pulsar.go b/api/cosmos/nft/v1beta1/event.pulsar.go index 343a2b33beb4..e67deb473677 100644 --- a/api/cosmos/nft/v1beta1/event.pulsar.go +++ b/api/cosmos/nft/v1beta1/event.pulsar.go @@ -3,14 +3,13 @@ package nftv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/nft/v1beta1/genesis.pulsar.go b/api/cosmos/nft/v1beta1/genesis.pulsar.go index a47db8097767..98980a0e4b03 100644 --- a/api/cosmos/nft/v1beta1/genesis.pulsar.go +++ b/api/cosmos/nft/v1beta1/genesis.pulsar.go @@ -3,14 +3,13 @@ package nftv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_1_list)(nil) diff --git a/api/cosmos/nft/v1beta1/nft.pulsar.go b/api/cosmos/nft/v1beta1/nft.pulsar.go index 2d62273461b9..e5ef55c3564b 100644 --- a/api/cosmos/nft/v1beta1/nft.pulsar.go +++ b/api/cosmos/nft/v1beta1/nft.pulsar.go @@ -3,15 +3,14 @@ package nftv1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/nft/v1beta1/query.pulsar.go b/api/cosmos/nft/v1beta1/query.pulsar.go index b304f6fc62fe..f045f70942a5 100644 --- a/api/cosmos/nft/v1beta1/query.pulsar.go +++ b/api/cosmos/nft/v1beta1/query.pulsar.go @@ -2,17 +2,16 @@ package nftv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/nft/v1beta1/tx.pulsar.go b/api/cosmos/nft/v1beta1/tx.pulsar.go index e3ba0b462e95..246a0a34c1e2 100644 --- a/api/cosmos/nft/v1beta1/tx.pulsar.go +++ b/api/cosmos/nft/v1beta1/tx.pulsar.go @@ -2,17 +2,16 @@ package nftv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/orm/module/v1alpha1/module.pulsar.go b/api/cosmos/orm/module/v1alpha1/module.pulsar.go index 32068b2430c2..61a3f50016b3 100644 --- a/api/cosmos/orm/module/v1alpha1/module.pulsar.go +++ b/api/cosmos/orm/module/v1alpha1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1alpha1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/orm/query/v1alpha1/query.pulsar.go b/api/cosmos/orm/query/v1alpha1/query.pulsar.go index 981cdf3466cb..1cd8e3dec149 100644 --- a/api/cosmos/orm/query/v1alpha1/query.pulsar.go +++ b/api/cosmos/orm/query/v1alpha1/query.pulsar.go @@ -2,12 +2,8 @@ package queryv1alpha1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" @@ -15,6 +11,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GetRequest_3_list)(nil) diff --git a/api/cosmos/orm/v1/orm.pulsar.go b/api/cosmos/orm/v1/orm.pulsar.go index 0a86327c769b..54ac19ce08a5 100644 --- a/api/cosmos/orm/v1/orm.pulsar.go +++ b/api/cosmos/orm/v1/orm.pulsar.go @@ -3,15 +3,14 @@ package ormv1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_TableDescriptor_2_list)(nil) diff --git a/api/cosmos/orm/v1alpha1/schema.pulsar.go b/api/cosmos/orm/v1alpha1/schema.pulsar.go index 7a10784ab7e4..5448367d13d1 100644 --- a/api/cosmos/orm/v1alpha1/schema.pulsar.go +++ b/api/cosmos/orm/v1alpha1/schema.pulsar.go @@ -3,15 +3,14 @@ package ormv1alpha1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_ModuleSchemaDescriptor_1_list)(nil) diff --git a/api/cosmos/params/module/v1/module.pulsar.go b/api/cosmos/params/module/v1/module.pulsar.go index 4a368c066b1e..1d4441751567 100644 --- a/api/cosmos/params/module/v1/module.pulsar.go +++ b/api/cosmos/params/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/params/v1beta1/params.pulsar.go b/api/cosmos/params/v1beta1/params.pulsar.go index ad4c6696591c..2568cc40a790 100644 --- a/api/cosmos/params/v1beta1/params.pulsar.go +++ b/api/cosmos/params/v1beta1/params.pulsar.go @@ -2,18 +2,17 @@ package paramsv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_ParameterChangeProposal_3_list)(nil) diff --git a/api/cosmos/params/v1beta1/query.pulsar.go b/api/cosmos/params/v1beta1/query.pulsar.go index 75974f65b750..ed8bcdbbd781 100644 --- a/api/cosmos/params/v1beta1/query.pulsar.go +++ b/api/cosmos/params/v1beta1/query.pulsar.go @@ -2,18 +2,17 @@ package paramsv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/query/v1/query.pulsar.go b/api/cosmos/query/v1/query.pulsar.go index bf8c3c95252e..0c3a26a6f9a9 100644 --- a/api/cosmos/query/v1/query.pulsar.go +++ b/api/cosmos/query/v1/query.pulsar.go @@ -2,11 +2,10 @@ package queryv1 import ( - reflect "reflect" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" ) // Code generated by protoc-gen-go. DO NOT EDIT. diff --git a/api/cosmos/reflection/v1/reflection.pulsar.go b/api/cosmos/reflection/v1/reflection.pulsar.go index dcbf64188d52..4075e1104397 100644 --- a/api/cosmos/reflection/v1/reflection.pulsar.go +++ b/api/cosmos/reflection/v1/reflection.pulsar.go @@ -2,17 +2,16 @@ package reflectionv1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/query/v1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" descriptorpb "google.golang.org/protobuf/types/descriptorpb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/slashing/module/v1/module.pulsar.go b/api/cosmos/slashing/module/v1/module.pulsar.go index a2f784bc6d2d..941613f66916 100644 --- a/api/cosmos/slashing/module/v1/module.pulsar.go +++ b/api/cosmos/slashing/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/slashing/v1beta1/genesis.pulsar.go b/api/cosmos/slashing/v1beta1/genesis.pulsar.go index f5bff77b7e15..6b753e38fe41 100644 --- a/api/cosmos/slashing/v1beta1/genesis.pulsar.go +++ b/api/cosmos/slashing/v1beta1/genesis.pulsar.go @@ -2,18 +2,17 @@ package slashingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_2_list)(nil) diff --git a/api/cosmos/slashing/v1beta1/query.pulsar.go b/api/cosmos/slashing/v1beta1/query.pulsar.go index 65d59a731292..b28562b40da5 100644 --- a/api/cosmos/slashing/v1beta1/query.pulsar.go +++ b/api/cosmos/slashing/v1beta1/query.pulsar.go @@ -2,13 +2,9 @@ package slashingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/slashing/v1beta1/slashing.pulsar.go b/api/cosmos/slashing/v1beta1/slashing.pulsar.go index 468a5cf5b311..bd1341612949 100644 --- a/api/cosmos/slashing/v1beta1/slashing.pulsar.go +++ b/api/cosmos/slashing/v1beta1/slashing.pulsar.go @@ -2,12 +2,8 @@ package slashingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/slashing/v1beta1/tx.pulsar.go b/api/cosmos/slashing/v1beta1/tx.pulsar.go index e8a41fd9f3d2..079d16bf5f43 100644 --- a/api/cosmos/slashing/v1beta1/tx.pulsar.go +++ b/api/cosmos/slashing/v1beta1/tx.pulsar.go @@ -2,19 +2,18 @@ package slashingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/staking/module/v1/module.pulsar.go b/api/cosmos/staking/module/v1/module.pulsar.go index db41968a4eef..dcb309d625ae 100644 --- a/api/cosmos/staking/module/v1/module.pulsar.go +++ b/api/cosmos/staking/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Module_1_list)(nil) diff --git a/api/cosmos/staking/v1beta1/authz.pulsar.go b/api/cosmos/staking/v1beta1/authz.pulsar.go index 0e6d062962d5..bdb0ce65a14a 100644 --- a/api/cosmos/staking/v1beta1/authz.pulsar.go +++ b/api/cosmos/staking/v1beta1/authz.pulsar.go @@ -2,19 +2,18 @@ package stakingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/staking/v1beta1/genesis.pulsar.go b/api/cosmos/staking/v1beta1/genesis.pulsar.go index 5a647497f4c2..67b645dc1521 100644 --- a/api/cosmos/staking/v1beta1/genesis.pulsar.go +++ b/api/cosmos/staking/v1beta1/genesis.pulsar.go @@ -2,18 +2,17 @@ package stakingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GenesisState_3_list)(nil) diff --git a/api/cosmos/staking/v1beta1/query.pulsar.go b/api/cosmos/staking/v1beta1/query.pulsar.go index dc452860db31..b1905fe7e803 100644 --- a/api/cosmos/staking/v1beta1/query.pulsar.go +++ b/api/cosmos/staking/v1beta1/query.pulsar.go @@ -2,14 +2,10 @@ package stakingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" _ "cosmossdk.io/api/cosmos/query/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/staking/v1beta1/staking.pulsar.go b/api/cosmos/staking/v1beta1/staking.pulsar.go index 8b1c00511e1f..ac22fb75017d 100644 --- a/api/cosmos/staking/v1beta1/staking.pulsar.go +++ b/api/cosmos/staking/v1beta1/staking.pulsar.go @@ -2,15 +2,11 @@ package stakingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" abci "cosmossdk.io/api/tendermint/abci" types "cosmossdk.io/api/tendermint/types" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -20,6 +16,9 @@ import ( anypb "google.golang.org/protobuf/types/known/anypb" durationpb "google.golang.org/protobuf/types/known/durationpb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_HistoricalInfo_2_list)(nil) @@ -12750,7 +12749,7 @@ func (BondStatus) EnumDescriptor() ([]byte, []int) { return file_cosmos_staking_v1beta1_staking_proto_rawDescGZIP(), []int{0} } -// Infraction indicates the infraction a validator committed. +// Infraction indicates the infraction a validator commited. type Infraction int32 const ( diff --git a/api/cosmos/staking/v1beta1/tx.pulsar.go b/api/cosmos/staking/v1beta1/tx.pulsar.go index 130fe492f276..1dbf7a8d49e2 100644 --- a/api/cosmos/staking/v1beta1/tx.pulsar.go +++ b/api/cosmos/staking/v1beta1/tx.pulsar.go @@ -2,14 +2,10 @@ package stakingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -18,6 +14,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/tx/module/v1/module.pulsar.go b/api/cosmos/tx/module/v1/module.pulsar.go index 9a4ab95f4303..bbecf5d7c2e1 100644 --- a/api/cosmos/tx/module/v1/module.pulsar.go +++ b/api/cosmos/tx/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/tx/signing/v1beta1/signing.pulsar.go b/api/cosmos/tx/signing/v1beta1/signing.pulsar.go index 106071efabfe..2a19fc80ce67 100644 --- a/api/cosmos/tx/signing/v1beta1/signing.pulsar.go +++ b/api/cosmos/tx/signing/v1beta1/signing.pulsar.go @@ -2,17 +2,16 @@ package signingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta1 "cosmossdk.io/api/cosmos/crypto/multisig/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_SignatureDescriptors_1_list)(nil) diff --git a/api/cosmos/tx/v1beta1/service.pulsar.go b/api/cosmos/tx/v1beta1/service.pulsar.go index ba27eaa5b101..e4e25547d5e4 100644 --- a/api/cosmos/tx/v1beta1/service.pulsar.go +++ b/api/cosmos/tx/v1beta1/service.pulsar.go @@ -2,19 +2,18 @@ package txv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta11 "cosmossdk.io/api/cosmos/base/abci/v1beta1" v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" types "cosmossdk.io/api/tendermint/types" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_GetTxsEventRequest_1_list)(nil) diff --git a/api/cosmos/tx/v1beta1/tx.pulsar.go b/api/cosmos/tx/v1beta1/tx.pulsar.go index 97451a208b10..54eca117719c 100644 --- a/api/cosmos/tx/v1beta1/tx.pulsar.go +++ b/api/cosmos/tx/v1beta1/tx.pulsar.go @@ -2,14 +2,10 @@ package txv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - v1beta12 "cosmossdk.io/api/cosmos/base/v1beta1" v1beta11 "cosmossdk.io/api/cosmos/crypto/multisig/v1beta1" v1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -17,6 +13,9 @@ import ( protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Tx_3_list)(nil) diff --git a/api/cosmos/upgrade/module/v1/module.pulsar.go b/api/cosmos/upgrade/module/v1/module.pulsar.go index 38c15a8f5ace..241f89ffb28a 100644 --- a/api/cosmos/upgrade/module/v1/module.pulsar.go +++ b/api/cosmos/upgrade/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/upgrade/v1beta1/query.pulsar.go b/api/cosmos/upgrade/v1beta1/query.pulsar.go index e5678631ed4f..ec2d4738f74f 100644 --- a/api/cosmos/upgrade/v1beta1/query.pulsar.go +++ b/api/cosmos/upgrade/v1beta1/query.pulsar.go @@ -3,15 +3,14 @@ package upgradev1beta1 import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/upgrade/v1beta1/tx.pulsar.go b/api/cosmos/upgrade/v1beta1/tx.pulsar.go index 50a0df26ad4c..ce507b9b6feb 100644 --- a/api/cosmos/upgrade/v1beta1/tx.pulsar.go +++ b/api/cosmos/upgrade/v1beta1/tx.pulsar.go @@ -2,19 +2,18 @@ package upgradev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/upgrade/v1beta1/upgrade.pulsar.go b/api/cosmos/upgrade/v1beta1/upgrade.pulsar.go index 4a9028a769ae..d001f4a532b1 100644 --- a/api/cosmos/upgrade/v1beta1/upgrade.pulsar.go +++ b/api/cosmos/upgrade/v1beta1/upgrade.pulsar.go @@ -2,12 +2,8 @@ package upgradev1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" @@ -16,6 +12,9 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" anypb "google.golang.org/protobuf/types/known/anypb" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/vesting/module/v1/module.pulsar.go b/api/cosmos/vesting/module/v1/module.pulsar.go index 8757ffa77683..1e6f34b99373 100644 --- a/api/cosmos/vesting/module/v1/module.pulsar.go +++ b/api/cosmos/vesting/module/v1/module.pulsar.go @@ -2,16 +2,15 @@ package modulev1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/cosmos/vesting/v1beta1/tx.pulsar.go b/api/cosmos/vesting/v1beta1/tx.pulsar.go index b29de6f1bd5c..6c883f75f434 100644 --- a/api/cosmos/vesting/v1beta1/tx.pulsar.go +++ b/api/cosmos/vesting/v1beta1/tx.pulsar.go @@ -2,20 +2,19 @@ package vestingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" _ "cosmossdk.io/api/cosmos/msg/v1" + fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_MsgCreateVestingAccount_3_list)(nil) diff --git a/api/cosmos/vesting/v1beta1/vesting.pulsar.go b/api/cosmos/vesting/v1beta1/vesting.pulsar.go index a385da103f35..abeacb60f8ee 100644 --- a/api/cosmos/vesting/v1beta1/vesting.pulsar.go +++ b/api/cosmos/vesting/v1beta1/vesting.pulsar.go @@ -2,19 +2,18 @@ package vestingv1beta1 import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - _ "cosmossdk.io/api/amino" v1beta11 "cosmossdk.io/api/cosmos/auth/v1beta1" v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_BaseVestingAccount_2_list)(nil) diff --git a/api/tendermint/abci/types.pulsar.go b/api/tendermint/abci/types.pulsar.go index bad46dd08c36..42d240bbcbc1 100644 --- a/api/tendermint/abci/types.pulsar.go +++ b/api/tendermint/abci/types.pulsar.go @@ -2,19 +2,18 @@ package abci import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - crypto "cosmossdk.io/api/tendermint/crypto" types "cosmossdk.io/api/tendermint/types" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/crypto/keys.pulsar.go b/api/tendermint/crypto/keys.pulsar.go index 75c61e187a80..537a21093cd9 100644 --- a/api/tendermint/crypto/keys.pulsar.go +++ b/api/tendermint/crypto/keys.pulsar.go @@ -3,15 +3,14 @@ package crypto import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/crypto/proof.pulsar.go b/api/tendermint/crypto/proof.pulsar.go index 1923145531a6..a3128844e44e 100644 --- a/api/tendermint/crypto/proof.pulsar.go +++ b/api/tendermint/crypto/proof.pulsar.go @@ -3,15 +3,14 @@ package crypto import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_Proof_4_list)(nil) @@ -2920,7 +2919,7 @@ func (x *DominoOp) GetOutput() string { } // ProofOp defines an operation used for calculating Merkle root -// The data could be arbitrary format, providing necessary data +// The data could be arbitrary format, providing nessecary data // for example neighbouring node hash type ProofOp struct { state protoimpl.MessageState diff --git a/api/tendermint/libs/bits/types.pulsar.go b/api/tendermint/libs/bits/types.pulsar.go index 9af2581b22bb..652d5c9366a5 100644 --- a/api/tendermint/libs/bits/types.pulsar.go +++ b/api/tendermint/libs/bits/types.pulsar.go @@ -3,14 +3,13 @@ package bits import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_BitArray_2_list)(nil) diff --git a/api/tendermint/p2p/types.pulsar.go b/api/tendermint/p2p/types.pulsar.go index 09449d4288c1..9bcb152d5481 100644 --- a/api/tendermint/p2p/types.pulsar.go +++ b/api/tendermint/p2p/types.pulsar.go @@ -3,15 +3,14 @@ package p2p import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/types/block.pulsar.go b/api/tendermint/types/block.pulsar.go index 77ecfec8f185..aed0ab7f3409 100644 --- a/api/tendermint/types/block.pulsar.go +++ b/api/tendermint/types/block.pulsar.go @@ -3,15 +3,14 @@ package types import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/types/evidence.pulsar.go b/api/tendermint/types/evidence.pulsar.go index f2ddcadb9d7f..a80b33b79f28 100644 --- a/api/tendermint/types/evidence.pulsar.go +++ b/api/tendermint/types/evidence.pulsar.go @@ -3,16 +3,15 @@ package types import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/types/params.pulsar.go b/api/tendermint/types/params.pulsar.go index fe83ec6bdddc..413d1807c0da 100644 --- a/api/tendermint/types/params.pulsar.go +++ b/api/tendermint/types/params.pulsar.go @@ -3,16 +3,15 @@ package types import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" durationpb "google.golang.org/protobuf/types/known/durationpb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/types/types.pulsar.go b/api/tendermint/types/types.pulsar.go index 9cef20416027..3280c62177ca 100644 --- a/api/tendermint/types/types.pulsar.go +++ b/api/tendermint/types/types.pulsar.go @@ -2,19 +2,18 @@ package types import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - crypto "cosmossdk.io/api/tendermint/crypto" version "cosmossdk.io/api/tendermint/version" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" + io "io" + reflect "reflect" + sync "sync" ) var ( diff --git a/api/tendermint/types/validator.pulsar.go b/api/tendermint/types/validator.pulsar.go index edfdbb6b26f9..477dcecda793 100644 --- a/api/tendermint/types/validator.pulsar.go +++ b/api/tendermint/types/validator.pulsar.go @@ -2,17 +2,16 @@ package types import ( - fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - crypto "cosmossdk.io/api/tendermint/crypto" + fmt "fmt" runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var _ protoreflect.List = (*_ValidatorSet_1_list)(nil) diff --git a/api/tendermint/version/types.pulsar.go b/api/tendermint/version/types.pulsar.go index 292117b4b906..7724eeab87ff 100644 --- a/api/tendermint/version/types.pulsar.go +++ b/api/tendermint/version/types.pulsar.go @@ -3,15 +3,14 @@ package version import ( fmt "fmt" - io "io" - reflect "reflect" - sync "sync" - runtime "github.com/cosmos/cosmos-proto/runtime" _ "github.com/cosmos/gogoproto/gogoproto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoiface "google.golang.org/protobuf/runtime/protoiface" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" ) var ( From 944166a5eff8b2b5066d4ede6b80ac7f08bd9a21 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 15 Nov 2022 13:30:20 -0500 Subject: [PATCH 06/24] WIP --- .../adr-054-protobuf-semver-compat-codegen.md | 71 +++++++++++++++---- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index 0055aebf7559..d04b5ab8f651 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -29,17 +29,41 @@ than it seems at first glance. Consider we have a Cosmos SDK module `foo` at a go module v1.x semantic version, and in that go module there is some generated protobuf code in the protobuf package `foo.v1` in that module’s `types` package that forms part of the public -API, for instance as part of `Keeper` methods, ex: +API, ex: ```go -// foo/keeper.go +// foo/types/tx.pb.go -import "foo/types" +type MsgDoSomething struct { + Sender string + Amount uint64 +} -type Keeper interface { - DoSomething(context.Context, *[]types.Coin) +type MsgServer interface { + DoSomething(context.Context, msg *MsgDoSomething) (*MsgDoSomethingResponse, error) +} + +``` + +Now consider that we want to make an upgrade and release `foo/v2` and also +add a new optional field to `MsgDoSomething`. We might now end up with the +following generated code in `foo/v2/types` if we follow the SDK's current +approach to generated code: + +```go +// foo/v2/types/tx.pb.go +type MsgDoSomething struct { + Sender string + Amount uint64 + // if Condition is non-nil, then the condition must be checked before performing the action + Condition *anypb.Any +} + +type MsgServer interface { + DoSomething(context.Context, msg *MsgDoSomething) (*MsgDoSomethingResponse, error) } ``` + Now consider that the developer wants to make a breaking change in `foo` that *does not affect* the `Keeper` interface above at all. So now a new go module `foo/v2` must be created to follow go semantic versioning. @@ -47,6 +71,7 @@ Now consider that the developer wants to make a breaking change in `foo` that The most obvious choice is to move all the code to `foo/v2` including the keeper so we now have: + ```go // foo/v2/keeper.go @@ -126,6 +151,15 @@ but more Cosmos-specific) to replace `ValidateBasic`. #### Pinning State Machine API Compatibility +To solve 2), state machine modules must be able to specify what the version of +the protobuf files was that they were built against. The simplest way to +do this may be to embed the protobuf `FileDescriptor`s into the module itself +so that these `FileDescriptor`s are used at runtime rather than the ones that +are built into the `foo/api` which may be different. This would involve the +following steps: +1. a build step executed during `make proto-gen` that runs `buf build` to pack the `FileDescriptor`s into an image file +2. a go embed directive to embed the image file + One consequence of bundling protobuf types separate from state machine logic is how it affects API forwards compatibility. By default, protobuf as we're using it is forwards compatible - meaning that newer clients can talk to older state machines. This can cause problems, however, if fields are added to older messages and clients try to use @@ -164,17 +198,26 @@ This second approach is probably less fragile than the "Since" annotations becau versions with annotations. While these annotations are a good solution for clients like CosmJs which want to support multiple chains, we need things to be a little stricter inside state machines. +### B) Changes to Generated Code -To solve 2), state machine modules must be able to specify what the version of -the protobuf files was that they were built against. The simplest way to -do this may be to embed the protobuf `FileDescriptor`s into the module itself -so that these `FileDescriptor`s are used at runtime rather than the ones that -are built into the `foo/api` which may be different. This would involve the -following steps: -1. a build step executed during `make proto-gen` that runs `buf build` to pack the `FileDescriptor`s into an image file -2. a go embed directive to embed the image file +An alternate approach to solving the versioning problem with generated code is to change the generated code itself. +Currently, we face two issues with how protobuf generated code works: +1. there can be only one generated type per protobuf type in the global registry (this can be overridden with special build flags) +2. if there are two generated types for one protobuf type, then they are not compatible -### B) Changes to Generated Code +To solve the global registry problem, we can adapt the code generator to not registry protobuf types with the global +registry if the generated code is placed in an `internal/` package. This will require modules to register their types +with the app-level level protobuf registry manually. This is similar to what modules already do with registering types +with the amino codec and `InterfaceRegistry`. + +Dealing with incompatible types is more difficult. Imagine we have an ADR 033 module client which is using the type +`github.com/cosmos/cosmos-sdk/x/bank/types.MsgSend`, but the bank module itself is using +`github.com/cosmos/cosmos-sdk/x/bank/v2/internal/types.MsgSend` in its `MsgServer` implementation. It won't be possible +to directly convert one `MsgSend` to the other the way protobuf types are currently generated. + +If we changed protobuf generated types to only expose interfaces and then implemented the storage of the types using +some set of zero-copy memory buffers, then we could simply pass the memory buffers from one implementation of the +types to another. #### Proto File Versioning From a6bbe0da22591993ef4ffced856ce081281d5033 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 11:01:42 -0500 Subject: [PATCH 07/24] updates --- .../adr-054-protobuf-semver-compat-codegen.md | 154 +++++++++--------- 1 file changed, 79 insertions(+), 75 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index d04b5ab8f651..af450d46abb2 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -10,12 +10,7 @@ PROPOSED ## Abstract -In order to work well with semantically versioned go modules, some changes to -the cosmos-proto code generator need to be made and best practices need to -be followed. In particular: -* clients should use generated protobuf code in a standalone "API" module -* state machines should use cosmos-proto generated code in `internal/` packages -* protobuf interface types (to be implemented in cosmos-proto) should be used in all public facing API's +TODO ## Context @@ -26,91 +21,100 @@ than it seems at first glance. ### Problem -Consider we have a Cosmos SDK module `foo` at a go module v1.x semantic version, -and in that go module there is some generated protobuf code in the protobuf -package `foo.v1` in that module’s `types` package that forms part of the public -API, ex: -```go -// foo/types/tx.pb.go +Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released it under +the go module `example.com/foo`: -type MsgDoSomething struct { - Sender string - Amount uint64 -} +```protobuf +package foo.v1; -type MsgServer interface { - DoSomething(context.Context, msg *MsgDoSomething) (*MsgDoSomethingResponse, error) +message MsgDoSomething { + string sender = 1; + uint64 amount = 2; } +service Msg { + DoSomething(MsgDoSomething) returns (MsgDoSomethingResponse); +} ``` -Now consider that we want to make an upgrade and release `foo/v2` and also -add a new optional field to `MsgDoSomething`. We might now end up with the -following generated code in `foo/v2/types` if we follow the SDK's current -approach to generated code: +Now consider that we make a revision to this module and add a new `condition` field to `MsgDoSomething` and also +add a new validation rule on `amount` requiring it to be non-zero, and that we follow go semantic versioning and +want to release the next state machine version of `foo` as `example.com/foo/v2`. -```go -// foo/v2/types/tx.pb.go -type MsgDoSomething struct { - Sender string - Amount uint64 - // if Condition is non-nil, then the condition must be checked before performing the action - Condition *anypb.Any -} +```protobuf +// Revision 1 +package foo.v1; -type MsgServer interface { - DoSomething(context.Context, msg *MsgDoSomething) (*MsgDoSomethingResponse, error) +message MsgDoSomething { + string sender = 1; + + // amount must be a non-zero integer. + uint64 amount = 2; + + // condition is an optional condition on doing the thing. + // + // Since: Revision 1 + Condition condition = 3; } ``` +Approaching this naively, we would generate the protobuf types for the initial +version of `foo` in `example.com/foo/types` and we would generate the protobuf +types for the second version in `example.com/foo/v2/types`. -Now consider that the developer wants to make a breaking change in `foo` that -*does not affect* the `Keeper` interface above at all. So now a new go module -`foo/v2` must be created to follow go semantic versioning. - -The most obvious choice is to move all the code to `foo/v2` including the keeper -so we now have: - - +Now let's say we have a module `bar` which talks to `foo` using this keeper +interface which `foo` provides: ```go -// foo/v2/keeper.go - -import v2types "foo/v2/types" - -type Keeper interface { - DoSomething(context.Context, *[]v2types.Coin) +type FooKeeper interface { + DoSomething(MsgDoSomething) error } ``` -Note that in this scenario `foo/v2/types` *still* refers to the protobuf package -`foo.v1`! - -Now consider, another go module `bar` with a state machine also at v1.x that -depends on `foo.Keeper`. Let’s say that `bar` doesn’t have any changes but an -app wants to use `foo/v2` together with `bar`. - -Now `bar` can’t be instantiated together with `foo/v2` because it requires the -`foo` v1.x keeper which depends on the generated code in `foo` v1. Even if the -`foo/v2` `Keeper` interface is basically identical to v1 interface, we must -refactor `bar` to work with the new `foo/v2` `Keeper`. And now consumers of -`bar` will also be forced to upgrade to `foo/v2` to get any `bar` updates. -That’s not really a good outcome because it could cause all sorts of downstream -compatibility problems - -To avoid this, we could consider an alternative where `foo/v2` imports `foo` v1 -and exposes the `foo` v1 keeper interface to be compatible. Then `foo/v2` will -need to import the `foo` v1 go module then we have these problems: -* there will be a protobuf namespace conflict because we have the protobuf -package `foo.v1` generated into both `foo/types` and `foo/v2/types` in the -same binary. The startup panic can be disabled with a build flag, but that is a -rather hacky solution. -* `foo/v2` will need to implement a wrapper which converts the `foo/types` -structs to `foo/v2/types` structs which is just unnecessary because they both -represent the *same* protobuf types in `foo.v1`. - -One alternative at this point is to simply tell people not to use go semantic -versioning at all and to keep their packages on `v0.x` forever. This solution, -however, would likely be highly unpopular. +### Scenario A: Backward Compatibility: Newer Foo, Older Bar + +Imagine we have a chain which uses both `foo` and `bar` and wants to upgrade to +`foo/v2`, but the `bar` module has not upgraded to `foo/v2`. + +In this case, the chain will not be able to upgrade to `foo/v2` until `bar` +has upgraded its references to `example.com/foo/types.MsgDoSomething` to +`example.com/foo/v2/types.MsgDoSomething`. + +Even if `bar`'s usage of `MsgDoSomething` has not changed at all, the upgrade +will be impossible without this change because `example.com/foo/types.MsgDoSomething` +and `example.com/foo/v2/types.MsgDoSomething` are fundamentally different +incompatible types in the go type system. + +### Scenario B: Forward Compatibility: Older Foo, Newer Bar + +Now let's consider the reverse scenario, where `bar` upgrades to `foo/v2` +by changing the `MsgDoSomething` reference to `example.com/foo/v2/types.MsgDoSomething` +and releases that as `bar/v2` with some other changes that a chain wants. +The chain, however, has decided that it thinks the changes in `foo/v2` are too +risky and that it'd prefer to stay on the initial version of `foo`. + +In this scenario, it is impossible to upgrade to `bar/v2` without upgrading +to `foo/v2` even if `bar/v2` would have worked 100% fine with `foo` other +than changing the import path to `MsgDoSomething` (meaning that `bar/v2` +doesn't actually use any new features of `foo/v2`). + +Now because of the way go semantic import versioning works, we are locked +into either using `foo` and `bar` OR `foo/v2` and `bar/v2`. We cannot have +`foo` + `bar/v2` OR `foo/v2` + `bar`. The go type system doesn't allow this +even if both versions of these modules are otherwise compatible with each other. + +### Naive Mitigation + +A naive approach at fixing this would be to not regenerate the protobuf types +in `example.com/foo/v2/types` but instead just update `example.com/foo/types` +to reflect the changes needed for `v2` (adding `condition` and requiring +`amount` to be non-zero). Then we could release a patch of `example.com/foo/types` +with this update and use that for `foo/v2`. But this change is state machine +breaking for `v1`. It requires changing the `ValidateBasic` method to reject +the case where `amount` is zero, and it adds the `condition` field which +should be rejected based on ADR 020 unknown field filtering. So adding these +changes as a patch on `v1` is actually an incorrect semantic versioning patch +to that release line. Chains that want to stay on `v1` of `foo` should not +be importing these changes because they are incorrect for `v1.` ### Solutions From 61a635dd166c084197094833c2b945ce0d74c607 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 11:28:28 -0500 Subject: [PATCH 08/24] updates --- .../adr-054-protobuf-semver-compat-codegen.md | 243 ++++++------------ 1 file changed, 76 insertions(+), 167 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index af450d46abb2..853464c2046a 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -128,17 +128,10 @@ accept non-breaking changes. This would then allow other modules to be compatible with either `foo` or `foo/v2` as long as the inter-module API only depends on the types in `foo/api`. -This approach introduces two complexities which need to be dealt with: -1. if `foo/api` includes any state machine breaking code then this situation is unworkable -because it means that changes to the state machine logic bleed across two go modules -in a hard to reason about manner. Currently, interfaces (such as `sdk.Msg` -or `authz.Authorization` are implemented directly on generated types and these -almost always include state machine breaking logic. -2. the version the protobuf files in `foo/api` at runtime may be different from -the version `foo` or `foo/v2` were built with which could introduce subtle bugs. -For instance, if a field is added to a message in `foo/api` for `foo/v2` but -the original `foo` module doesn't use it, then there may be important data in -that new field which silently gets ignored. +In order to differentiate this from the naive mitigation described above +we would need to do two things differently: +1. remove all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) +2. embed the correct file descriptors to be used for unknown field filtering in the binary. #### Migrate all interface methods on API types to handlers @@ -156,51 +149,31 @@ but more Cosmos-specific) to replace `ValidateBasic`. #### Pinning State Machine API Compatibility To solve 2), state machine modules must be able to specify what the version of -the protobuf files was that they were built against. The simplest way to -do this may be to embed the protobuf `FileDescriptor`s into the module itself -so that these `FileDescriptor`s are used at runtime rather than the ones that -are built into the `foo/api` which may be different. This would involve the -following steps: +the protobuf files was that they were built against. For instance if the API +module for `foo` upgrades to `foo/v2`, the original `foo` module still needs +a copy of the original protobuf files it was built with so that ADR 020 +unknown field filtering will reject `MsgDoSomething` when `condition` is +set. + +The simplest way to do this may be to embed the protobuf `FileDescriptor`s into +the module itself so that these `FileDescriptor`s are used at runtime rather +than the ones that are built into the `foo/api` which may be different. This +would involve the following steps: 1. a build step executed during `make proto-gen` that runs `buf build` to pack the `FileDescriptor`s into an image file 2. a go embed directive to embed the image file -One consequence of bundling protobuf types separate from state machine logic is how it affects API forwards -compatibility. By default, protobuf as we're using it is forwards compatible - meaning that newer clients can talk to -older state machines. This can cause problems, however, if fields are added to older messages and clients try to use -these new fields against older state machines. - -For example, say someone adds a field to a message to set an optional expiration time on some operation. If the newer -client sends a message an older state machine with this new expiration field set, the state machine will reject it -based on [ADR 020 Unknown Field Filtering](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). - -This will break down, however, if we package API types separately because an app developer may use an API version that's -newer that the state machine version and then clients can send a message with an expiration time, the state machine will -accept it but ignore it, which is a bug. This isn't a problem now because the protobuf types are codegen'ed directly -into the state machine code so there can be no discrepancy. - -If we migrate to an API module, we will need to pin the API compatibility version in the state machine. Here are two -potential ways to do this: - -##### "Since" Annotations - -In the [Protobuf package versioning discussion](https://github.com/cosmos/cosmos-sdk/discussions/10406) we agreed to -take [approach 2: annotations using "Since" comments](https://github.com/cosmos/cosmos-sdk/pull/10434) to help clients -deal with forwards compatibility gracefully by only enabling newer API features when they know they're talking to a -newer chain. We could use these same annotations in state machines and instruct unknown field filtering to reject -fields in newer API versions if they are present in protobuf generated code. - - -##### Embed raw proto files in state machines +#### Potential limitations to generated code -This would involve using [golang embed](https://pkg.go.dev/embed) to force state machines to embed the proto files they -intended to use in the binary and registering them with the `InterfaceRegistry` which will use them for unknown field -filtering. By using the `embed.FS` type we can force module developers to copy .proto files into the module path and -update them when they want to support newer APIs. A warning could be emitted if an older API verison is registered and -a newer one is available in generated code, alerting modular developers and/or apps to upgrade. +One challenge with this approach is that it places heavy restrictions on what +can go in API modules and how generated code can affect state machine logic. -This second approach is probably less fragile than the "Since" annotations because it could be easy to mess up API -versions with annotations. While these annotations are a good solution for clients like CosmJs which want to support -multiple chains, we need things to be a little stricter inside state machines. +For instance, we do code generation for the ORM that in the future could +potentially contain optimizations that are even state machine breaking. We +would either need to ensure very carefully that the optimizations aren't +state machine breaking in generated code or separate this generated code +out from the API module into the state machine module. Both of these mitigations +are potentially viable but the API module approach does require an extra level +of care to avoid these sorts of issues. ### B) Changes to Generated Code @@ -223,152 +196,88 @@ If we changed protobuf generated types to only expose interfaces and then implem some set of zero-copy memory buffers, then we could simply pass the memory buffers from one implementation of the types to another. -#### Proto File Versioning - -Versioning of proto files vs the state machine is complicated. The idea with the `api` module is that it stays -forever on `v1.x` and independent proto packages are versioned with package suffixes `v1beta1`, `v1`, `v2`. - -This introduces a bit of a complex versioning scenario where we have a `v1` go module with sub-packages marked alpha or -beta that could be changed or removed. We can deal with this by allowing an explicit exception for packages marked alpha -and beta where those can change independent of the go module version. - -Also it requires state machines to solidify a v1 in a beta or alpha package and then a migration of 1) all the proto -files to v1 and 2) all the state machine code to now reference v1 in two steps at the end of development. If we -call `api` v1 and we have a sub-package `foo/v1` then we really can't break `foo/v1` anymore even if the `foo/v1` state -machine isn't ready. - -**Essentially this makes state machine development more complicated because it prematurely leaks WIP designs to client -libraries.** - -#### Pinned proto images - -As is described in https://github.com/cosmos/cosmos-sdk/discussions/10582), we -would need to pin proto images for state machines in the codec registry -to ensure proper unknown field filtering. This isn't a deal breaker, but it is a bit complex for people to understand -and requires both: - -* an additional build step to configure which may be hard to understand -* fairly complex linting of pinned proto images vs runtime generated - code: https://github.com/cosmos/cosmos-sdk/blob/fdd3d07a28f662c2fabd6007a4a1f64be3a373b3/proto/cosmos/app/v1alpha1/module.proto#L48-L83 - -#### Complex refactoring of interfaces - -As described in https://github.com/cosmos/cosmos-sdk/discussions/10368, all -interface methods on generated code would need to be removed and refactored into -a handler approach. It is a complex refactoring especially of `ValidateBasic` -and alignment on an ideal replacement pattern hasn't been reached yet -(https://github.com/cosmos/cosmos-sdk/pull/11340). - -#### Potential limitations to generated code - -In doing benchmarking of ORM generated code several potential optimizations have emerged and obviously the most -performant optimization would be to generate as much code as possible. But because ORM table descriptors may evolve from -one version to the next with new indexes and fields being added, this makes generated code state machine breaking. -Recall that the API module paradigm requires no state machine breaking logic in generated code. - -## Decision - -To address these issues, we will adopt a hybrid approach which requires changes -to the https://github.com/cosmos/cosmos-proto code generator. - -For client facing code, the API module pattern is still useful given that -care is taken to only publish stable tags when packages are actually stable -and in production. - -For state machine code, the recommended solution is to generate protobuf -code used by the module in an `internal` package and modify the code generator -to *skip global registration* for generated code in internal packages. - -Because there are plenty of cases where we want one module to essentially -be a client of another module, either in `Keeper` method or as proposed in -[ADR 033](./adr-033-protobuf-inter-module-comm.md), modules will need -to use different generated code - for instance from an API module - than -the code used in the state machine itself. - -To address this, we will also modify the code generator to generate interfaces -which allow different concrete structs to be passed into keeper methods and -ADR 033 than those used internally by the module. - -For instance, for a struct `MsgSend`, getters like `GetAmount`, `GetFromAddress`, are already defined so codegen could -create an interface: - +For example, imagine this protobuf API with only getters and setters is exposed for `MsgSend`: ```go -type MsgSendI interface { - protoreflect.ProtoMessage - GetFromAddress() string - GetToAddress() string - GetAmount() []v1beta1.CoinI - - IsCosmosBankV1MsgSend() // this method distinguishes this interface from other proto types which may otherwise implement the same fields. +type MsgSend interface { + proto.Message + GetFromAddress() string + GetToAddress() string + GetAmount() []v1beta1.Coin + SetFromAddress(string) + SetToAddress(string) + SetAmount([]v1beta1.Coin) } -``` -The gRPC generated server and client could look like this, with the client having -a way to detect the server revision (as described -in https://github.com/cosmos/cosmos-sdk/blob/fdd3d07a28f662c2fabd6007a4a1f64be3a373b3/proto/cosmos/app/v1alpha1/module.proto#L55) -to see which features the server supports if the client is newer: +func NewMsgSend() MsgSend { ... } +``` +Under the hood, `MsgSend` could be implemented based on raw `[]byte` memory buffers, ex: ```go -type MsgServer interface { - Send(context.Context, MsgSendI) (MsgSendResponseI, error) +type msgSendImpl struct { + memoryBuffers []interface{} } -type MsgClient interface { - Send(ctx context.Context, in MsgSendI, opts …grpc.CallOption) (MsgSendResponseI, error) - // note that for MsgSendResponseI we would need to have a generated response wrapper type to deal with the case where - // the client is newer than the server +func (m *msgSendImpl) GetFromAddress() { + return m.memoryBuffers[0].(string) +} - GetServerRevision() uint64 +func (m *msgSendImpl) GetToAddress() { + return m.memoryBuffers[1].(string) } ``` -This would allow inter-module clients to use different generated code built against potentially different revisions of -the same protobuf package without doing marshaling/unmarshaling between different structs. +This approach would have the added benefits of allowing zero-copy message passing to modules written in other languages +such as Rust. It could also make unknown field filtering in inter-module communication simpler if we assume that all +new fields are added in sequential order. -The structs themselves and the ORM could also use these interfaces directly so that the there is no need to do copying -from interfaces to concrete types when dealing with different generated code, ex: +Also, we wouldn't have any issues with state machine breaking code on generated types because all the generated +code used in the state machine would actually live in the state machine module. Other modules using ADR 033 or +keeper methods could still use a public API module to reference other types. In fact, it may be best to combine +the API module approach with this approach - basically public keeper APIs would use public API module types whereas +internal logic would use internal generated types. This, however, may be a bit complex for module authors to manage. -```go -type MsgSend struct { - FromAddress string - ToAddress string - Amount []v1beta1.CoinI -} +Other big downsides of this approach are that it requires big changes to how people use protobuf types and would be a +substantial rewrite of the protobuf code generator. These types, however, could still be made compatible with +the `google.golang.org/protobuf/reflect/protoreflect` API in order to work with all standard golang protobuf tooling. -// for the ORM: -type BalanceTable interface { - Insert(ctx context.Context, balance BalanceI) error - ... -} -``` +It is possible that this second approach could be adopted later on as an optimization for multi-language message +on top of the first API module approach. + +## Decision + +We have decided based on the complexities of approach B) to adopt approach A) for the time-being. While the refactoring +from interface methods to handlers is somewhat tedious, it is relatively simpler than changing how we use generated +code everywhere. Also, embedded file descriptors is a rather simple way to deal with correct unknown field +filtering - it needs a small amount of boilerplate and a build step all of which could be part of a project template +and is basically set it and forget it. Regarding excluding state machine breaking changes from generated code (i.e. +API modules), this is something primarily for the SDK team to attend to and define best practices around. We may even +decide to recommend projects use [Buf Remote Generation](https://docs.buf.build/bsr/remote-generation/go) with a +Buf template which we provide to make this step mostly fool-proof for module developers. + +Maintaining both internal types + an API module might be confusing in an ongoing way to module developers, not to +mention the upfront costs of 1) getting the code generator right and 2) designing a new zero-copy encoding on top of +protobuf. It may be worth reconsidering B) in the future when we start supporting modules in other languages, but +for now A) is a simpler correct-enough approach. ## Consequences ### Backwards Compatibility -This approach is more backwards compatible with the existing state machine -code than before, but some changes will be necessitated - first migrating -to the new code generator and secondly modifying `Keeper` methods to use -interfaces rather than concrete structs. +TODO ### Positive -* no need for pinned proto images in state machines - the codegen would have the correct image -* interface methods can be defined on generated code -* codegen can include other state machine breaking logic, such ORM optimizations +TODO ### Negative -* file descriptors will need to be manually registered (which is already sort of the case with `RegisterInterfaces`) -* significant changes to the code generator will be required +TODO ### Neutral - ## Further Discussions -Further discussions can take place in https://github.com/cosmos/cosmos-sdk/discussions/10582 and within -the Cosmos SDK Framework Working Group. +TODO ## References From b1da61a0126ba47113446e91f6e0c129f4a7e5da Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 12:40:56 -0500 Subject: [PATCH 09/24] updates --- .../adr-054-protobuf-semver-compat-codegen.md | 51 +++++++++++++++---- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index 853464c2046a..42da4dc77e94 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -19,7 +19,7 @@ in the community for semantic versioning in the SDK. How this interacts with protobuf generated code is [more complex](https://github.com/cosmos/cosmos-sdk/discussions/10162#discussioncomment-1363034) than it seems at first glance. -### Problem +### Problem 1: Version Compatibility Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released it under the go module `example.com/foo`: @@ -70,7 +70,7 @@ type FooKeeper interface { } ``` -### Scenario A: Backward Compatibility: Newer Foo, Older Bar +#### Scenario A: Backward Compatibility: Newer Foo, Older Bar Imagine we have a chain which uses both `foo` and `bar` and wants to upgrade to `foo/v2`, but the `bar` module has not upgraded to `foo/v2`. @@ -84,7 +84,7 @@ will be impossible without this change because `example.com/foo/types.MsgDoSomet and `example.com/foo/v2/types.MsgDoSomething` are fundamentally different incompatible types in the go type system. -### Scenario B: Forward Compatibility: Older Foo, Newer Bar +#### Scenario B: Forward Compatibility: Older Foo, Newer Bar Now let's consider the reverse scenario, where `bar` upgrades to `foo/v2` by changing the `MsgDoSomething` reference to `example.com/foo/v2/types.MsgDoSomething` @@ -102,7 +102,7 @@ into either using `foo` and `bar` OR `foo/v2` and `bar/v2`. We cannot have `foo` + `bar/v2` OR `foo/v2` + `bar`. The go type system doesn't allow this even if both versions of these modules are otherwise compatible with each other. -### Naive Mitigation +#### Naive Mitigation A naive approach at fixing this would be to not regenerate the protobuf types in `example.com/foo/v2/types` but instead just update `example.com/foo/types` @@ -116,9 +116,18 @@ changes as a patch on `v1` is actually an incorrect semantic versioning patch to that release line. Chains that want to stay on `v1` of `foo` should not be importing these changes because they are incorrect for `v1.` +### Problem 2: Circular dependencies + +None of the above approaches allow `foo` and `bar` to be separate modules +if for some reason `foo` and `bar` depend on each other in different ways. +We have several cases of circular module dependencies in the SDK +(ex. staking, distribution and slashing) that are legitimate from a state machine +perspective but that would make it impossible to independently semantically +version these modules without some other mitigation. + ### Solutions -### A) API Module Approach +### Approach A) Separate API and State Machine Modules One solution (first proposed in https://github.com/cosmos/cosmos-sdk/discussions/10582) is to isolate all protobuf generated code into a separate module from the state machine module. This would mean that we could have state machine @@ -126,12 +135,16 @@ go modules `foo` and `foo/v2` which could use a types or API go module say `foo/api`. This `foo/api` go module would be perpetually on `v1.x` and only accept non-breaking changes. This would then allow other modules to be compatible with either `foo` or `foo/v2` as long as the inter-module API only -depends on the types in `foo/api`. +depends on the types in `foo/api`. It would also allow modules `foo` and `bar` +to depend on each other in that both of them could depend on `foo/api` and +`bar/api` without `foo` directly depending on `bar` and vice versa. -In order to differentiate this from the naive mitigation described above -we would need to do two things differently: -1. remove all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) -2. embed the correct file descriptors to be used for unknown field filtering in the binary. +This is similar to the naive mitigation described above except that it separates +the types into separate go modules which in and of itself could break circular +dependencies. Otherwise, it would have the same problems as that solution which +we could rectify by: +1. removing all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) +2. embedding the correct file descriptors to be used for unknown field filtering in the binary. #### Migrate all interface methods on API types to handlers @@ -175,7 +188,7 @@ out from the API module into the state machine module. Both of these mitigations are potentially viable but the API module approach does require an extra level of care to avoid these sorts of issues. -### B) Changes to Generated Code +### Approach B) Changes to Generated Code An alternate approach to solving the versioning problem with generated code is to change the generated code itself. Currently, we face two issues with how protobuf generated code works: @@ -243,6 +256,22 @@ the `google.golang.org/protobuf/reflect/protoreflect` API in order to work with It is possible that this second approach could be adopted later on as an optimization for multi-language message on top of the first API module approach. +### Approach C) Use 0.x based versioning and replace directives + +Some people have commented that go's semantic import versioning (i.e. changing the import path to `foo/v2`, `foo/v3`, +etc.) is too restrictive and that it should be optional. The golang maintainers disagree and only officially support +semantic import versioning, although we could take the contrary perspective and get more flexibility by using 0.x-based +versioning basically forever. + +Module version compatibility could then be achieved using go.mod replace directives to pin dependencies to specific +compatible 0.x versions. For instance if we knew `foo` 0.2 and 0.3 were both compatible with `bar` 0.3 and 0.4, we +could use replace directives in our go.mod to stick to the versions of `foo` and `bar` we want. This would work as +long as the authors of `foo` and `bar` avoid incompatible breaking changes between these modules. + +### Approach D) Use semantic versioning and don't address these issues + + + ## Decision We have decided based on the complexities of approach B) to adopt approach A) for the time-being. While the refactoring From 9a348dfb1ad28a58f7087aa7b858f3409faa5075 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 12:41:07 -0500 Subject: [PATCH 10/24] updates --- .../adr-054-protobuf-semver-compat-codegen.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md index 42da4dc77e94..b5e2ce9c32cc 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-protobuf-semver-compat-codegen.md @@ -274,19 +274,6 @@ long as the authors of `foo` and `bar` avoid incompatible breaking changes betwe ## Decision -We have decided based on the complexities of approach B) to adopt approach A) for the time-being. While the refactoring -from interface methods to handlers is somewhat tedious, it is relatively simpler than changing how we use generated -code everywhere. Also, embedded file descriptors is a rather simple way to deal with correct unknown field -filtering - it needs a small amount of boilerplate and a build step all of which could be part of a project template -and is basically set it and forget it. Regarding excluding state machine breaking changes from generated code (i.e. -API modules), this is something primarily for the SDK team to attend to and define best practices around. We may even -decide to recommend projects use [Buf Remote Generation](https://docs.buf.build/bsr/remote-generation/go) with a -Buf template which we provide to make this step mostly fool-proof for module developers. - -Maintaining both internal types + an API module might be confusing in an ongoing way to module developers, not to -mention the upfront costs of 1) getting the code generator right and 2) designing a new zero-copy encoding on top of -protobuf. It may be worth reconsidering B) in the future when we start supporting modules in other languages, but -for now A) is a simpler correct-enough approach. ## Consequences From 165af334afb3100cc46e7ec64afa5791e8c9e9c9 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 13:35:06 -0500 Subject: [PATCH 11/24] updates --- docs/architecture/README.md | 2 +- ...d => adr-054-semver-compatible-modules.md} | 88 ++++++++++++++----- 2 files changed, 65 insertions(+), 25 deletions(-) rename docs/architecture/{adr-054-protobuf-semver-compat-codegen.md => adr-054-semver-compatible-modules.md} (78%) diff --git a/docs/architecture/README.md b/docs/architecture/README.md index f7e46575058a..7606e19a15c7 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -80,7 +80,7 @@ When writing ADRs, follow the same best practices for writing RFCs. When writing * [ADR 039: Epoched Staking](./adr-039-epoched-staking.md) * [ADR 040: Storage and SMT State Commitments](./adr-040-storage-and-smt-state-commitments.md) * [ADR 046: Module Params](./adr-046-module-params.md) -* [ADR 054: Protobuf Semver Compatible Codegen](./adr-054-protobuf-semver-compat-codegen.md) +* [ADR 054: Semver Compatible SDK Modules](./adr-054-semver-compatible-modules.md) * [ADR 057: App Wiring](./adr-057-app-wiring.md) * [ADR 059: Test Scopes](./adr-059-test-scopes.md) diff --git a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md b/docs/architecture/adr-054-semver-compatible-modules.md similarity index 78% rename from docs/architecture/adr-054-protobuf-semver-compat-codegen.md rename to docs/architecture/adr-054-semver-compatible-modules.md index b5e2ce9c32cc..8af8319e910f 100644 --- a/docs/architecture/adr-054-protobuf-semver-compat-codegen.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -1,4 +1,4 @@ -# ADR 054: Protobuf Semver Compatible Codegen +# ADR 054: Semver Compatible SDK Modules ## Changelog @@ -10,16 +10,34 @@ PROPOSED ## Abstract -TODO +In order to move the Cosmos SDK to a system of decoupled semantically versioned +modules which can be composed in different combinations (ex. staking v3 with +bank v1 and distribution v2), we need to reassess how we organize the API surface +of modules to avoid problems with go semantic import versioning and +circular dependencies. This ADR explores various approaches we can take to +addressing these issues. ## Context There has been [a fair amount of desire](https://github.com/cosmos/cosmos-sdk/discussions/10162) -in the community for semantic versioning in the SDK. How this interacts -with protobuf generated code is [more complex](https://github.com/cosmos/cosmos-sdk/discussions/10162#discussioncomment-1363034) -than it seems at first glance. - -### Problem 1: Version Compatibility +in the community for semantic versioning in the SDK and there has been significant +movement to splitting out modules into [standalone go modules](https://github.com/cosmos/cosmos-sdk/issues/11899). +Both of these will ideally allow the ecosystem to move faster because we won't +be waiting for all major dependencies to update in sync. For instance, we could +have 3 versions of the core SDK compatible with the latest 2 releases of +CosmWasm, and 4 different versions of staking that are compatible with all +these releases of the SDK and CosmWasm. This sort of setup would allow +early adopters to aggressively integrate new versions, while also allowing +more conservative users to be more selective about which latest and greatest +versions they're ready for. + +In order to achieve this, we need to solve the following problems: +1. because of the way [go semantic import versioning](https://research.swtch.com/vgo-import) (SIV) +works, moving to SIV naively will actually make it harder to achieve these goals +2. circular dependencies between modules need to be broken to actually release +many modules in the SDK independently + +### Problem 1: Semantic Import Versioning Compatibility Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released it under the go module `example.com/foo`: @@ -140,9 +158,9 @@ to depend on each other in that both of them could depend on `foo/api` and `bar/api` without `foo` directly depending on `bar` and vice versa. This is similar to the naive mitigation described above except that it separates -the types into separate go modules which in and of itself could break circular -dependencies. Otherwise, it would have the same problems as that solution which -we could rectify by: +the types into separate go modules which in and of itself could be used to +break circular module dependencies. It has the same problems as the naive solution, +otherwise, which we could rectify by: 1. removing all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) 2. embedding the correct file descriptors to be used for unknown field filtering in the binary. @@ -151,7 +169,20 @@ we could rectify by: To solve 1), we need to remove all interface implementations from generated types and start using a handler approach which essentially means that given a type `X`, we have some sort of router which allows us to resolve some interface -implementation for that type (say `sdk.Msg` or `authz.Authorization`). +implementation for that type (say `sdk.Msg` or `authz.Authorization`). Ex: + +```go +func (k Keeper) DoSomething(msg MsgDoSomething) error { + var validateBasicHandler ValidateBasicHandler + err := k.resolver.Resolve(&validateBasic, msg) + if err != nil { + return err + } + + err = validateBasicHandler.ValidateBasic() + ... +} +``` In the case of some methods on `sdk.Msg`, we can replace them with declarative annotations. For instance, `GetSigners` can already be replaced by the protobuf @@ -159,7 +190,7 @@ annotation `cosmos.msg.v1.signer`. In the future, we may consider some sort of protobuf validation framework (like https://github.com/bufbuild/protoc-gen-validate but more Cosmos-specific) to replace `ValidateBasic`. -#### Pinning State Machine API Compatibility +#### Pinned FileDescriptor's To solve 2), state machine modules must be able to specify what the version of the protobuf files was that they were built against. For instance if the API @@ -170,10 +201,11 @@ set. The simplest way to do this may be to embed the protobuf `FileDescriptor`s into the module itself so that these `FileDescriptor`s are used at runtime rather -than the ones that are built into the `foo/api` which may be different. This -would involve the following steps: -1. a build step executed during `make proto-gen` that runs `buf build` to pack the `FileDescriptor`s into an image file -2. a go embed directive to embed the image file +than the ones that are built into the `foo/api` which may be different. Using +[buf build](https://docs.buf.build/build/usage#output-format), [go embed](https://pkg.go.dev/embed), +and a build script we can probably come up with a solution for embedding +`FileDescriptor`s into modules that is basically set it and forget it the +way that protobuf codegen is now. #### Potential limitations to generated code @@ -256,21 +288,29 @@ the `google.golang.org/protobuf/reflect/protoreflect` API in order to work with It is possible that this second approach could be adopted later on as an optimization for multi-language message on top of the first API module approach. -### Approach C) Use 0.x based versioning and replace directives +### Approach C) Don't address these issues + +We can also decide not to do anything explicit to: +* enable better module version compatibility, and +* break circular dependencies. + +In this case, when developers are confronted with the issues described above +they can require dependencies to update in sync (what we do now) or +attempt some ad hoc potentially hacky solution. -Some people have commented that go's semantic import versioning (i.e. changing the import path to `foo/v2`, `foo/v3`, -etc.) is too restrictive and that it should be optional. The golang maintainers disagree and only officially support -semantic import versioning, although we could take the contrary perspective and get more flexibility by using 0.x-based -versioning basically forever. +One approach is to ditch go semantic import versioning (SIV) altogether. Some people have commented that go's SIV +(i.e. changing the import path to `foo/v2`, `foo/v3`, etc.) is too restrictive and that it should be optional. The +golang maintainers disagree and only officially support semantic import versioning, although we could take the +contrary perspective and get more flexibility by using 0.x-based versioning basically forever. Module version compatibility could then be achieved using go.mod replace directives to pin dependencies to specific compatible 0.x versions. For instance if we knew `foo` 0.2 and 0.3 were both compatible with `bar` 0.3 and 0.4, we could use replace directives in our go.mod to stick to the versions of `foo` and `bar` we want. This would work as long as the authors of `foo` and `bar` avoid incompatible breaking changes between these modules. -### Approach D) Use semantic versioning and don't address these issues - - +Or, if developers choose to use semantic import versioning, they can attempt the naive solution described above +and would also need to use special tags and replace directives to make sure that modules are pinned to the correct +versions. ## Decision From 902c6af6ded63f17bf132f72e9c04ed1ee36d83e Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 16 Nov 2022 14:31:22 -0500 Subject: [PATCH 12/24] updates --- .../adr-054-semver-compatible-modules.md | 199 ++++++++++++------ 1 file changed, 132 insertions(+), 67 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 8af8319e910f..0d8be04a1d5e 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -21,26 +21,27 @@ addressing these issues. There has been [a fair amount of desire](https://github.com/cosmos/cosmos-sdk/discussions/10162) in the community for semantic versioning in the SDK and there has been significant -movement to splitting out modules into [standalone go modules](https://github.com/cosmos/cosmos-sdk/issues/11899). +movement to splitting SDK modules into [standalone go modules](https://github.com/cosmos/cosmos-sdk/issues/11899). Both of these will ideally allow the ecosystem to move faster because we won't -be waiting for all major dependencies to update in sync. For instance, we could +be waiting for all dependencies to update synchronously. For instance, we could have 3 versions of the core SDK compatible with the latest 2 releases of -CosmWasm, and 4 different versions of staking that are compatible with all -these releases of the SDK and CosmWasm. This sort of setup would allow -early adopters to aggressively integrate new versions, while also allowing -more conservative users to be more selective about which latest and greatest -versions they're ready for. +CosmWasm as well as 4 different versions of staking . This sort of setup would +allow early adopters to aggressively integrate new versions, while allowing +more conservative users to be selective about which versions they're ready for. In order to achieve this, we need to solve the following problems: 1. because of the way [go semantic import versioning](https://research.swtch.com/vgo-import) (SIV) works, moving to SIV naively will actually make it harder to achieve these goals 2. circular dependencies between modules need to be broken to actually release many modules in the SDK independently +3. pernicious minor version incompatibilities introduced through correctly +[evolving protobuf schemas](https://developers.google.com/protocol-buffers/docs/proto3#updating) +without correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) ### Problem 1: Semantic Import Versioning Compatibility -Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released it under -the go module `example.com/foo`: +Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released its state +machine in go module `example.com/foo`: ```protobuf package foo.v1; @@ -56,8 +57,8 @@ service Msg { ``` Now consider that we make a revision to this module and add a new `condition` field to `MsgDoSomething` and also -add a new validation rule on `amount` requiring it to be non-zero, and that we follow go semantic versioning and -want to release the next state machine version of `foo` as `example.com/foo/v2`. +add a new validation rule on `amount` requiring it to be non-zero, and that following go semantic versioning we +release the next state machine version of `foo` as `example.com/foo/v2`. ```protobuf // Revision 1 @@ -100,7 +101,7 @@ has upgraded its references to `example.com/foo/types.MsgDoSomething` to Even if `bar`'s usage of `MsgDoSomething` has not changed at all, the upgrade will be impossible without this change because `example.com/foo/types.MsgDoSomething` and `example.com/foo/v2/types.MsgDoSomething` are fundamentally different -incompatible types in the go type system. +incompatible structs in the go type system. #### Scenario B: Forward Compatibility: Older Foo, Newer Bar @@ -118,30 +119,50 @@ doesn't actually use any new features of `foo/v2`). Now because of the way go semantic import versioning works, we are locked into either using `foo` and `bar` OR `foo/v2` and `bar/v2`. We cannot have `foo` + `bar/v2` OR `foo/v2` + `bar`. The go type system doesn't allow this -even if both versions of these modules are otherwise compatible with each other. +even if both versions of these modules are otherwise compatible with each +other. #### Naive Mitigation -A naive approach at fixing this would be to not regenerate the protobuf types +A naive approach to fixing this would be to not regenerate the protobuf types in `example.com/foo/v2/types` but instead just update `example.com/foo/types` to reflect the changes needed for `v2` (adding `condition` and requiring `amount` to be non-zero). Then we could release a patch of `example.com/foo/types` with this update and use that for `foo/v2`. But this change is state machine breaking for `v1`. It requires changing the `ValidateBasic` method to reject the case where `amount` is zero, and it adds the `condition` field which -should be rejected based on ADR 020 unknown field filtering. So adding these -changes as a patch on `v1` is actually an incorrect semantic versioning patch -to that release line. Chains that want to stay on `v1` of `foo` should not +should be rejected based on [ADR 020 unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). +So adding these changes as a patch on `v1` is actually incorrect based on semantic +versioning. Chains that want to stay on `v1` of `foo` should not be importing these changes because they are incorrect for `v1.` ### Problem 2: Circular dependencies None of the above approaches allow `foo` and `bar` to be separate modules if for some reason `foo` and `bar` depend on each other in different ways. +For instance, we can't have `foo` import `bar/types` while `bar` imports +`foo/types`. + We have several cases of circular module dependencies in the SDK (ex. staking, distribution and slashing) that are legitimate from a state machine -perspective but that would make it impossible to independently semantically -version these modules without some other mitigation. +perspective. Without separating the API types out somehow, there would be +no way to independently semantically version these modules without some other +mitigation. + +### Problem 3: Handling Minor Version Incompatibilities + +Imagine that we solve the first two problems but now have a scenario where +`bar/v2` wants the option to use `MsgDoSomething.condition` which only `foo/v2` +supports. If `bar/v2` works with `foo` `v1` and sets `condition` to some non-nil +value, then `foo` will silently ignore this field resulting in a silent logic +possibly dangerous logic error. If `bar/v2` were able to check whether `foo` was +on `v1` or `v2` and dynamically, it could choose to only use `condition` when +`foo/v2` is available. Even if `bar/v2` were able to perform this check, however, +how do we know that it is always performing the check properly. Without +some sort of framework-level [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), +it is hard to know whether these pernicious hard to detect bugs are getting into +our app and a client-server layer such as [ADR 033: Inter-Module Communication](./adr-033-protobuf-inter-module-comm.md) +may be needed to do this. ### Solutions @@ -162,14 +183,15 @@ the types into separate go modules which in and of itself could be used to break circular module dependencies. It has the same problems as the naive solution, otherwise, which we could rectify by: 1. removing all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) -2. embedding the correct file descriptors to be used for unknown field filtering in the binary. +2. embedding the correct file descriptors for unknown field filtering in the binary #### Migrate all interface methods on API types to handlers To solve 1), we need to remove all interface implementations from generated -types and start using a handler approach which essentially means that given -a type `X`, we have some sort of router which allows us to resolve some interface -implementation for that type (say `sdk.Msg` or `authz.Authorization`). Ex: +types and instead use a handler approach which essentially means that given +a type `X`, we have some sort of resolver which allows us to resolve interface +implementations for that type (ex. `sdk.Msg` or `authz.Authorization`). For +example: ```go func (k Keeper) DoSomething(msg MsgDoSomething) error { @@ -184,7 +206,7 @@ func (k Keeper) DoSomething(msg MsgDoSomething) error { } ``` -In the case of some methods on `sdk.Msg`, we can replace them with declarative +In the case of some methods on `sdk.Msg`, we could replace them with declarative annotations. For instance, `GetSigners` can already be replaced by the protobuf annotation `cosmos.msg.v1.signer`. In the future, we may consider some sort of protobuf validation framework (like https://github.com/bufbuild/protoc-gen-validate @@ -204,42 +226,74 @@ the module itself so that these `FileDescriptor`s are used at runtime rather than the ones that are built into the `foo/api` which may be different. Using [buf build](https://docs.buf.build/build/usage#output-format), [go embed](https://pkg.go.dev/embed), and a build script we can probably come up with a solution for embedding -`FileDescriptor`s into modules that is basically set it and forget it the -way that protobuf codegen is now. +`FileDescriptor`s into modules that is fairly straightforward. #### Potential limitations to generated code One challenge with this approach is that it places heavy restrictions on what -can go in API modules and how generated code can affect state machine logic. +can go in API modules and requires that node of this is state machine breaking. +All or most of the code in the API module would be generated from protobuf +files, so we can probably control this with how code generation is done, but +it is a risk to be aware of. For instance, we do code generation for the ORM that in the future could -potentially contain optimizations that are even state machine breaking. We +contain optimizations that are state machine breaking. We would either need to ensure very carefully that the optimizations aren't -state machine breaking in generated code or separate this generated code +actually state machine breaking in generated code or separate this generated code out from the API module into the state machine module. Both of these mitigations are potentially viable but the API module approach does require an extra level of care to avoid these sorts of issues. -### Approach B) Changes to Generated Code +#### Minor Version Incompatibilities -An alternate approach to solving the versioning problem with generated code is to change the generated code itself. -Currently, we face two issues with how protobuf generated code works: -1. there can be only one generated type per protobuf type in the global registry (this can be overridden with special build flags) -2. if there are two generated types for one protobuf type, then they are not compatible +This approach in and of itself does little to address any potential minor +version incompatibilities and the requisite [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). +Likely some sort of client-server routing layer which does this check such as +[ADR 033: Inter-Module communication](./adr-033-protobuf-inter-module-comm.md) +is required to make sure that this is done properly. We could then allow +modules to perform a runtime check given a `MsgClient`, ex: -To solve the global registry problem, we can adapt the code generator to not registry protobuf types with the global -registry if the generated code is placed in an `internal/` package. This will require modules to register their types -with the app-level level protobuf registry manually. This is similar to what modules already do with registering types -with the amino codec and `InterfaceRegistry`. +```go +func (k Keeper) CallFoo() error { + if k.interModuleClient.MinorRevision(k.fooMsgClient) >= 2 { + k.fooMsgClient.DoSomething(&MsgDoSomething{Condition: ...}) + } else { + ... + } +} +``` -Dealing with incompatible types is more difficult. Imagine we have an ADR 033 module client which is using the type -`github.com/cosmos/cosmos-sdk/x/bank/types.MsgSend`, but the bank module itself is using -`github.com/cosmos/cosmos-sdk/x/bank/v2/internal/types.MsgSend` in its `MsgServer` implementation. It won't be possible -to directly convert one `MsgSend` to the other the way protobuf types are currently generated. +To do the unknown field filtering itself, the ADR 033 router would need to use +the [protoreflect API](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect) +to ensure that no fields unknown to the receiving module are set. This could +result in an undesirable performance hit depending on how complex this logic is. -If we changed protobuf generated types to only expose interfaces and then implemented the storage of the types using -some set of zero-copy memory buffers, then we could simply pass the memory buffers from one implementation of the -types to another. +### Approach B) Changes to Generated Code + +An alternate approach to solving the versioning problem is to change how protobuf code is generated and move modules +mostly or completely in the direction of inter-module communication as described in [ADR 033](./adr-033-protobuf-inter-module-comm.md). +In this paradigm, a module could generate all the types it needs internally - including the API types of other modules - +and talk to other modules via a client-server boundary. For instance, if `bar` needs to talk to `foo`, it could +generate its own version of `MsgDoSomething` as `bar/internal/foo/v1.MsgDoSomething` and just pass this to the +inter-module router which would somehow convert it to the version which foo needs (ex. `foo/internal.MsgDoSomething`). + +Currently, two generated structs for the same protobuf type cannot exist in the same go binary without special +build flags (see https://developers.google.com/protocol-buffers/docs/reference/go/faq#fix-namespace-conflict). +A relatively simple mitigation to this issue would be to set up the protobuf code to not register protobuf types +globally if they are generated in an `internal/` package. This will require modules to register their types manually +with the app-level level protobuf registry, this is similar to what modules already do with the `InterfaceRegistry` +and amino codec. + +If modules _only_ do ADR 033 message passing then a naive and non-performant solution for converting `bar/internal/foo/v1.MsgDoSomething` +to `foo/internal.MsgDoSomething` would be marshaling and unmarshaling in the ADR 033 router. This would break down if +we needed to expose protobuf types in `Keeper` interfaces because the whole point is to try to keep these types +`internal/` so that we don't end up with all the import version incompatibilities we've described above. However, +because of the issue with minor version incompatibilities and the need for [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), +sticking with the `Keeper` paradigm instead of ADR 033 may be unviable to begin with. + +A more performant solution (that could maybe be adapted to work with `Keeper` interfaces) would be to only expose +getters and setters for generated types and internally store data in memory buffers which could be passed from +one implementation to another in a zero-copy way. For example, imagine this protobuf API with only getters and setters is exposed for `MsgSend`: ```go @@ -253,10 +307,10 @@ type MsgSend interface { SetAmount([]v1beta1.Coin) } -func NewMsgSend() MsgSend { ... } +func NewMsgSend() MsgSend { return &msgSendImpl{memoryBuffers: ...} } ``` -Under the hood, `MsgSend` could be implemented based on raw `[]byte` memory buffers, ex: +Under the hood, `MsgSend` could be implemented based on some raw memory buffers, ex: ```go type msgSendImpl struct { memoryBuffers []interface{} @@ -272,36 +326,40 @@ func (m *msgSendImpl) GetToAddress() { ``` This approach would have the added benefits of allowing zero-copy message passing to modules written in other languages -such as Rust. It could also make unknown field filtering in inter-module communication simpler if we assume that all -new fields are added in sequential order. +such as Rust. It could also make unknown field filtering in inter-module communication simpler if we require that all +new fields are added in sequential order, ex. just checking that no field `> 5` is set. Also, we wouldn't have any issues with state machine breaking code on generated types because all the generated -code used in the state machine would actually live in the state machine module. Other modules using ADR 033 or -keeper methods could still use a public API module to reference other types. In fact, it may be best to combine -the API module approach with this approach - basically public keeper APIs would use public API module types whereas -internal logic would use internal generated types. This, however, may be a bit complex for module authors to manage. +code used in the state machine would actually live in the state machine module itself. Depending on how interface +types and protobuf `Any`s are used in other languages, however, it may still be desirable to take the handler +approach described in approach A. Either way, types implementing interfaces would still need to be registered +with an `InterfaceRegistry` as they are now because there would be no way to retrieve them via the global registry. -Other big downsides of this approach are that it requires big changes to how people use protobuf types and would be a -substantial rewrite of the protobuf code generator. These types, however, could still be made compatible with -the `google.golang.org/protobuf/reflect/protoreflect` API in order to work with all standard golang protobuf tooling. +In order to simplify access to other modules using ADR 033, a public API module (maybe even one +[remotely generated by Buf](https://docs.buf.build/bsr/remote-generation/go)) could be used by client modules instead +of requiring to generate all client types internally. -It is possible that this second approach could be adopted later on as an optimization for multi-language message -on top of the first API module approach. +The big downsides of this approach are that it requires big changes to how people use protobuf types and would be a +substantial rewrite of the protobuf code generator. This new generated code, however, could still be made compatible with +the [`google.golang.org/protobuf/reflect/protoreflect`](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect) +API in order to work with all standard golang protobuf tooling. + +It is possible that the naive approach of marshaling/unmarshaling in the ADR 033 router is an acceptable intermediate +solution if the changes to the code generator are seen as too complex. However, since all modules would likely need +to migrate to ADR 033 anyway with this approach, it might be better to do this all at once. ### Approach C) Don't address these issues -We can also decide not to do anything explicit to: -* enable better module version compatibility, and -* break circular dependencies. +If the above solutions are seen as too complex, we can also decide not to do anything explicit to enable better module +version compatibility, and break circular dependencies. -In this case, when developers are confronted with the issues described above -they can require dependencies to update in sync (what we do now) or -attempt some ad hoc potentially hacky solution. +In this case, when developers are confronted with the issues described above they can require dependencies to update in +sync (what we do now) or attempt some ad-hoc potentially hacky solution. One approach is to ditch go semantic import versioning (SIV) altogether. Some people have commented that go's SIV (i.e. changing the import path to `foo/v2`, `foo/v3`, etc.) is too restrictive and that it should be optional. The -golang maintainers disagree and only officially support semantic import versioning, although we could take the -contrary perspective and get more flexibility by using 0.x-based versioning basically forever. +golang maintainers disagree and only officially support semantic import versioning. We could, however, take the +contrarian perspective and get more flexibility by using 0.x-based versioning basically forever. Module version compatibility could then be achieved using go.mod replace directives to pin dependencies to specific compatible 0.x versions. For instance if we knew `foo` 0.2 and 0.3 were both compatible with `bar` 0.3 and 0.4, we @@ -312,8 +370,13 @@ Or, if developers choose to use semantic import versioning, they can attempt the and would also need to use special tags and replace directives to make sure that modules are pinned to the correct versions. +Note, however, that all of these ad-hoc approaches, would be vulnerable to the minor version compatibility issues +described above unless [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) +is properly addressed. + ## Decision +More discussion is needed to make a clear and decisive decision. ## Consequences @@ -340,4 +403,6 @@ TODO * https://github.com/cosmos/cosmos-sdk/discussions/10162 * https://github.com/cosmos/cosmos-sdk/discussions/10582 * https://github.com/cosmos/cosmos-sdk/discussions/10368 -* https://github.com/cosmos/cosmos-sdk/pull/11340 \ No newline at end of file +* https://github.com/cosmos/cosmos-sdk/pull/11340 +* https://github.com/cosmos/cosmos-sdk/issues/11899 +* [ADR 020](./adr-020-protobuf-transaction-encoding.md) \ No newline at end of file From ee4748cf5cdc2a32e877e56cad11723d2a883366 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 21 Nov 2022 11:27:53 -0500 Subject: [PATCH 13/24] add draft decision --- .../adr-054-semver-compatible-modules.md | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 0d8be04a1d5e..70e060bdb2cb 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -376,13 +376,32 @@ is properly addressed. ## Decision -More discussion is needed to make a clear and decisive decision. +Based on discussions within the team, the current draft consensus is the following: +1. we are alignment on adopting [ADR 033](./adr-033-protobuf-inter-module-comm.md) not just as an addition to the +framework, but as a core replacement to the keeper paradigm entirely. +2. the ADR 033 inter-module router will accommodate any variation of approach (A) or (B) given the following rules: + a. if the client type is the same as the server type then pass it directly through, + b. if both client and server use the zero-copy generated code wrappers (which still need to be defined), then pass +the memory buffers from one wrapper to the other, or + c. marshal/unmarshal types between client and server. + +This approach will allow for both maximal correctness and enable a clear path to enabling modules within in other +languages, possibly executed within a WASM VM. + +The inter-module router will need to provide a capability for clients to introspect the minor API revision of the +server. + +We will also need to define how interface methods are defined on types that are serialized as `google.protobuf.Any`'s. +In light of the desire to support modules in other languages, we may want to think of solutions that will accommodate +other languages such as plugins described briefly in [ADR 033](./adr-033-protobuf-inter-module-comm.md#internal-methods). ## Consequences ### Backwards Compatibility -TODO +Modules which migrate fully to ADR 033 will not be compatible with existing modules which use the keeper paradigm. +As a temporary workaround we may create some wrapper types that emulate the current keeper interface to minimize +the migration overhead. ### Positive @@ -405,4 +424,5 @@ TODO * https://github.com/cosmos/cosmos-sdk/discussions/10368 * https://github.com/cosmos/cosmos-sdk/pull/11340 * https://github.com/cosmos/cosmos-sdk/issues/11899 -* [ADR 020](./adr-020-protobuf-transaction-encoding.md) \ No newline at end of file +* [ADR 020](./adr-020-protobuf-transaction-encoding.md) +* [ADR 033](./adr-033-protobuf-inter-module-comm.md) From 9a1460ea072ace48268ecc24af505ebf3c8dfb97 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 21 Nov 2022 11:35:07 -0500 Subject: [PATCH 14/24] pros and cons --- .../adr-054-semver-compatible-modules.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 70e060bdb2cb..03c1f58ac3a6 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -389,7 +389,7 @@ This approach will allow for both maximal correctness and enable a clear path to languages, possibly executed within a WASM VM. The inter-module router will need to provide a capability for clients to introspect the minor API revision of the -server. +server, and it will need to perform the correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). We will also need to define how interface methods are defined on types that are serialized as `google.protobuf.Any`'s. In light of the desire to support modules in other languages, we may want to think of solutions that will accommodate @@ -405,17 +405,26 @@ the migration overhead. ### Positive -TODO +* we will be able to deliver interoperable semantically versioned modules which should dramatically increase the +ability of the Cosmos SDK ecosystem to iterate on new features +* it will be possible to write Cosmos SDK modules in other languages in the near future ### Negative -TODO +* all modules will need to be refactored somewhat dramatically ### Neutral ## Further Discussions -TODO +The decision described above is considered in draft mode and is pending final buy-in from the team and key stakeholders. +Key outstanding discussions if we do adopt that direction are: +* how do module clients introspect dependency module API revisions +* how do modules determine a minor dependency module API revision requirement +* how do modules appropriately test compatibility with different dependency versions +* how to register and resolve interface implementations +* how do modules register their protobuf file descriptors depending on the approach they take to generated code (the +API module approach may still be viable as a supported strategy and would need pinned file descriptors) ## References From fd8cca347423553645d3408aed0f5a03430cf2c2 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 10:44:03 -0500 Subject: [PATCH 15/24] context on proto vs module versioning --- .../adr-054-semver-compatible-modules.md | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 03c1f58ac3a6..0c9538ee3346 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -38,6 +38,15 @@ many modules in the SDK independently [evolving protobuf schemas](https://developers.google.com/protocol-buffers/docs/proto3#updating) without correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) +Note that all the following discussion assumes that the proto file versioning and state machine versioning of a module +are distinct in that: +* proto files are maintained in a non-breaking way (using something like [buf breaking](https://docs.buf.build/breaking/overview) + to ensure all changes are backwards compatible) +* proto file versions get bumped much less frequently, i.e. we might maintain `cosmos.bank.v1` through many versions + of the bank module state machine +* state machine breaking changes are more common and ideally this is what we'd want to semantically version with +go modules, ex. `x/bank/v2`, `x/bank/v3`, etc. + ### Problem 1: Semantic Import Versioning Compatibility Consider we have a module `foo` which defines the following `MsgDoSomething` and that we've released its state @@ -388,13 +397,60 @@ the memory buffers from one wrapper to the other, or This approach will allow for both maximal correctness and enable a clear path to enabling modules within in other languages, possibly executed within a WASM VM. -The inter-module router will need to provide a capability for clients to introspect the minor API revision of the -server, and it will need to perform the correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). +### Minor API Revisions + +In order for modules to introspect the minor API revision of peer modules, we propose adding the following method +to `cosmossdk.io/core/intermodule.Client`: + +```go +ServiceRevision(ctx context.Context, serviceName string) uint64 +``` + +Modules could all this using the service name statically generated by the go grpc code generator: + +```go +intermoduleClient.ServiceRevision(ctx, bankv1beta1.Msg_ServiceDesc.ServiceName) +``` + +In the future, we may decide to extend the code generator used for protobuf services to add a field +to client types which does this check more concisely, ex: + +```go +package bankv1beta1 + +type MsgClient interface { + Send(context.Context, MsgSend) (MsgSendResponse, error) + ServiceRevision(context.Context) uint64 +} +``` + +### Unknown Field Filtering + +To correctly perform [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), +the inter-module router can do one of the following: +* use the `protoreflect` API for messages which support that +* for gogo proto messages, marshal and use the existing `codec/unknownproto` code +* for zero-copy messages, do a simple check on the highest set field number (assuming we can require that fields are +adding consecutively in increasing order) + +### Dependency Declaration + +### Interface Registration We will also need to define how interface methods are defined on types that are serialized as `google.protobuf.Any`'s. In light of the desire to support modules in other languages, we may want to think of solutions that will accommodate other languages such as plugins described briefly in [ADR 033](./adr-033-protobuf-inter-module-comm.md#internal-methods). +### `FileDescriptor` Registration + +### Testing + +#### Unit Testing + +#### Integration Testing + +### Proto File Versioning + ## Consequences ### Backwards Compatibility From f43d5caef73944c88fe237ac2fd5d9f6261e9f20 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 13:08:17 -0500 Subject: [PATCH 16/24] Update docs/architecture/adr-054-semver-compatible-modules.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-054-semver-compatible-modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 0c9538ee3346..2d1a245d7ea4 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -240,7 +240,7 @@ and a build script we can probably come up with a solution for embedding #### Potential limitations to generated code One challenge with this approach is that it places heavy restrictions on what -can go in API modules and requires that node of this is state machine breaking. +can go in API modules and requires that most of this is state machine breaking. All or most of the code in the API module would be generated from protobuf files, so we can probably control this with how code generation is done, but it is a risk to be aware of. From 8148e10e128d846df1a09d69b8dc45f560102513 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 13:34:09 -0500 Subject: [PATCH 17/24] Update docs/architecture/adr-054-semver-compatible-modules.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-054-semver-compatible-modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 2d1a245d7ea4..9ced2313a59e 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -173,7 +173,7 @@ it is hard to know whether these pernicious hard to detect bugs are getting into our app and a client-server layer such as [ADR 033: Inter-Module Communication](./adr-033-protobuf-inter-module-comm.md) may be needed to do this. -### Solutions +## Solutions ### Approach A) Separate API and State Machine Modules From b2764c8a813846aa967c988e94119aec4d6820fc Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 13:34:32 -0500 Subject: [PATCH 18/24] Update docs/architecture/adr-054-semver-compatible-modules.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-054-semver-compatible-modules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 9ced2313a59e..bb7355f52b27 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -208,7 +208,7 @@ func (k Keeper) DoSomething(msg MsgDoSomething) error { err := k.resolver.Resolve(&validateBasic, msg) if err != nil { return err - } + } err = validateBasicHandler.ValidateBasic() ... From f75d1d926f8ca63c03f758246bd237667810ea9c Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 14:43:59 -0500 Subject: [PATCH 19/24] updates --- .../adr-054-semver-compatible-modules.md | 106 +++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 0c9538ee3346..3fe3203cacf9 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -445,11 +445,106 @@ other languages such as plugins described briefly in [ADR 033](./adr-033-protobu ### Testing +In order to ensure that modules are indeed with multiple versions of their dependencies, we plan to provide specialized +unit and integration testing infrastructure that automatically tests multiple versions of dependencies. + #### Unit Testing +Unit tests should be conducted inside SDK modules by mocking their dependencies. In a full ADR 033 scenario, +this means that all interaction with other modules is done via the inter-module router, so mocking of dependencies +means mocking their msg and query server implementations. We will provide both a test runner and fixture to make this +streamlined. The test fixture will be an interface like the following: + +```go +package moduletesting + +import ( + "context" + "testing" + + "cosmossdk.io/core/intermodule" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" +) + +type TestFixture interface { + context.Context + intermodule.Client // for making calls to the module we're testing + BeginBlock() + EndBlock() +} + +type UnitTestFixture interface { + TestFixture + grpc.ServiceRegistrar // for registering mock service implementations +} + +type UnitTestConfig struct { + ModuleConfig proto.Message +} + +func (cfg UnitTestConfig) Run(t *testing.T, f func(t *testing.T, f UnitTestFixture)) { + // ... +} +``` + +```go +func TestBar(t *testing.T) { + UnitTestConfig + moduletesting.RunUnitTests(t, &foomodulev1.Module{}, func(t *testing.T, f moduletesting.UnitTestFixture) { + ctrl := gomock.NewController(t) + mockFooMsgServer := footestutil.NewMockMsgServer() + foov1.RegisterMsgServer(f, mockFooMsgServer) + barMsgClient := barv1.NewMsgClient(f) + mockFooMsgServer.EXPECT().DoSomething(gomock.Any(), gomock.Any()).Return(&foov1.MsgDoSomething.Response{}, nil) + res, err := barMsgClient.CallFoo(f, &MsgCallFoo{}) + ... + }) +} +``` + #### Integration Testing -### Proto File Versioning + +```go +type IntegrationTestFixture interface { + TestFixture +} + +type IntegrationTestConfig struct { + ModuleConfig proto.Message + DependencyMatrix map[string][]proto.Message +} + +func (cfg IntegationTestConfig) Run(t *testing.T, f func(t *testing.T, f IntegrationTestFixture)) { + // ... +} +``` + +```go +func TestBarIntegration(t *testing.T) { + IntegrationTestConfig{ + ModuleConfig: &barmodulev1.Module{}, + DependencyMatrix: map[string][]proto.Message{ + "runtime": []proto.Message{ + &runtimev1.Module{}, + &runtimev2.Module{}, + }, + "foo": []proto.Message{ + &foomodulev1.Module{}, + &foomodulev2.Module{}, + &foomodulev3.Module{}, + } + } + }.Run(t, func(t *testing.T, f moduletesting.IntegrationTestFixture) { + barMsgClient := barv1.NewMsgClient(f) + res, err := barMsgClient.CallFoo(f, &MsgCallFoo{}) + ... + }) +} +``` + +### Proto File and Module Versioning ## Consequences @@ -471,6 +566,15 @@ ability of the Cosmos SDK ecosystem to iterate on new features ### Neutral +* the `cosmossdk.io/core/appconfig` framework will play a more central role in terms of how modules are defined, this +is likely generally a good thing but does mean additional changes for users wanting to stick to the pre-depinject way +of wiring up modules +* `depinject` is somewhat less needed or maybe even obviated because of the full ADR 033 approach. If we adopt the +core API proposed in https://github.com/cosmos/cosmos-sdk/pull/12239, then a module would probably always instantiate +itself with a method `ProvideModule(appmodule.Service) (appmodule.AppModule, error)`. There is no complex wiring of +keeper dependencies in this scenario and dependency injection may not have as much of (or any) use case. + + ## Further Discussions The decision described above is considered in draft mode and is pending final buy-in from the team and key stakeholders. From 18063339e78f8e0c4e8f8cfd42e8f206371ac65e Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 22 Nov 2022 16:25:52 -0500 Subject: [PATCH 20/24] updates --- .../adr-054-semver-compatible-modules.md | 228 +++++++++++++----- proto/cosmos/app/v1alpha1/module.proto | 2 +- 2 files changed, 165 insertions(+), 65 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 3fe3203cacf9..2b1a12c2226b 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -26,26 +26,29 @@ Both of these will ideally allow the ecosystem to move faster because we won't be waiting for all dependencies to update synchronously. For instance, we could have 3 versions of the core SDK compatible with the latest 2 releases of CosmWasm as well as 4 different versions of staking . This sort of setup would -allow early adopters to aggressively integrate new versions, while allowing +allow early adopters to aggressively integrate new versions, while allowing more conservative users to be selective about which versions they're ready for. In order to achieve this, we need to solve the following problems: + 1. because of the way [go semantic import versioning](https://research.swtch.com/vgo-import) (SIV) -works, moving to SIV naively will actually make it harder to achieve these goals + works, moving to SIV naively will actually make it harder to achieve these goals 2. circular dependencies between modules need to be broken to actually release -many modules in the SDK independently + many modules in the SDK independently 3. pernicious minor version incompatibilities introduced through correctly -[evolving protobuf schemas](https://developers.google.com/protocol-buffers/docs/proto3#updating) -without correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) + [evolving protobuf schemas](https://developers.google.com/protocol-buffers/docs/proto3#updating) + without correct [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) Note that all the following discussion assumes that the proto file versioning and state machine versioning of a module are distinct in that: -* proto files are maintained in a non-breaking way (using something like [buf breaking](https://docs.buf.build/breaking/overview) + +* proto files are maintained in a non-breaking way (using something + like [buf breaking](https://docs.buf.build/breaking/overview) to ensure all changes are backwards compatible) * proto file versions get bumped much less frequently, i.e. we might maintain `cosmos.bank.v1` through many versions of the bank module state machine * state machine breaking changes are more common and ideally this is what we'd want to semantically version with -go modules, ex. `x/bank/v2`, `x/bank/v3`, etc. + go modules, ex. `x/bank/v2`, `x/bank/v3`, etc. ### Problem 1: Semantic Import Versioning Compatibility @@ -92,6 +95,7 @@ types for the second version in `example.com/foo/v2/types`. Now let's say we have a module `bar` which talks to `foo` using this keeper interface which `foo` provides: + ```go type FooKeeper interface { DoSomething(MsgDoSomething) error @@ -103,8 +107,8 @@ type FooKeeper interface { Imagine we have a chain which uses both `foo` and `bar` and wants to upgrade to `foo/v2`, but the `bar` module has not upgraded to `foo/v2`. -In this case, the chain will not be able to upgrade to `foo/v2` until `bar` -has upgraded its references to `example.com/foo/types.MsgDoSomething` to +In this case, the chain will not be able to upgrade to `foo/v2` until `bar` +has upgraded its references to `example.com/foo/types.MsgDoSomething` to `example.com/foo/v2/types.MsgDoSomething`. Even if `bar`'s usage of `MsgDoSomething` has not changed at all, the upgrade @@ -140,7 +144,8 @@ to reflect the changes needed for `v2` (adding `condition` and requiring with this update and use that for `foo/v2`. But this change is state machine breaking for `v1`. It requires changing the `ValidateBasic` method to reject the case where `amount` is zero, and it adds the `condition` field which -should be rejected based on [ADR 020 unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). +should be rejected based +on [ADR 020 unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). So adding these changes as a patch on `v1` is actually incorrect based on semantic versioning. Chains that want to stay on `v1` of `foo` should not be importing these changes because they are incorrect for `v1.` @@ -168,7 +173,8 @@ possibly dangerous logic error. If `bar/v2` were able to check whether `foo` was on `v1` or `v2` and dynamically, it could choose to only use `condition` when `foo/v2` is available. Even if `bar/v2` were able to perform this check, however, how do we know that it is always performing the check properly. Without -some sort of framework-level [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), +some sort of +framework-level [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), it is hard to know whether these pernicious hard to detect bugs are getting into our app and a client-server layer such as [ADR 033: Inter-Module Communication](./adr-033-protobuf-inter-module-comm.md) may be needed to do this. @@ -177,7 +183,8 @@ may be needed to do this. ### Approach A) Separate API and State Machine Modules -One solution (first proposed in https://github.com/cosmos/cosmos-sdk/discussions/10582) is to isolate all protobuf generated code into a separate module +One solution (first proposed in https://github.com/cosmos/cosmos-sdk/discussions/10582) is to isolate all protobuf +generated code into a separate module from the state machine module. This would mean that we could have state machine go modules `foo` and `foo/v2` which could use a types or API go module say `foo/api`. This `foo/api` go module would be perpetually on `v1.x` and only @@ -191,10 +198,11 @@ This is similar to the naive mitigation described above except that it separates the types into separate go modules which in and of itself could be used to break circular module dependencies. It has the same problems as the naive solution, otherwise, which we could rectify by: + 1. removing all state machine breaking code from the API module (ex. `ValidateBasic` and any other interface methods) 2. embedding the correct file descriptors for unknown field filtering in the binary -#### Migrate all interface methods on API types to handlers +#### Migrate all interface methods on API types to handlers To solve 1), we need to remove all interface implementations from generated types and instead use a handler approach which essentially means that given @@ -231,7 +239,7 @@ unknown field filtering will reject `MsgDoSomething` when `condition` is set. The simplest way to do this may be to embed the protobuf `FileDescriptor`s into -the module itself so that these `FileDescriptor`s are used at runtime rather +the module itself so that these `FileDescriptor`s are used at runtime rather than the ones that are built into the `foo/api` which may be different. Using [buf build](https://docs.buf.build/build/usage#output-format), [go embed](https://pkg.go.dev/embed), and a build script we can probably come up with a solution for embedding @@ -256,7 +264,8 @@ of care to avoid these sorts of issues. #### Minor Version Incompatibilities This approach in and of itself does little to address any potential minor -version incompatibilities and the requisite [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). +version incompatibilities and the +requisite [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering). Likely some sort of client-server routing layer which does this check such as [ADR 033: Inter-Module communication](./adr-033-protobuf-inter-module-comm.md) is required to make sure that this is done properly. We could then allow @@ -280,7 +289,8 @@ result in an undesirable performance hit depending on how complex this logic is. ### Approach B) Changes to Generated Code An alternate approach to solving the versioning problem is to change how protobuf code is generated and move modules -mostly or completely in the direction of inter-module communication as described in [ADR 033](./adr-033-protobuf-inter-module-comm.md). +mostly or completely in the direction of inter-module communication as described +in [ADR 033](./adr-033-protobuf-inter-module-comm.md). In this paradigm, a module could generate all the types it needs internally - including the API types of other modules - and talk to other modules via a client-server boundary. For instance, if `bar` needs to talk to `foo`, it could generate its own version of `MsgDoSomething` as `bar/internal/foo/v1.MsgDoSomething` and just pass this to the @@ -293,11 +303,13 @@ globally if they are generated in an `internal/` package. This will require modu with the app-level level protobuf registry, this is similar to what modules already do with the `InterfaceRegistry` and amino codec. -If modules _only_ do ADR 033 message passing then a naive and non-performant solution for converting `bar/internal/foo/v1.MsgDoSomething` +If modules _only_ do ADR 033 message passing then a naive and non-performant solution for +converting `bar/internal/foo/v1.MsgDoSomething` to `foo/internal.MsgDoSomething` would be marshaling and unmarshaling in the ADR 033 router. This would break down if we needed to expose protobuf types in `Keeper` interfaces because the whole point is to try to keep these types `internal/` so that we don't end up with all the import version incompatibilities we've described above. However, -because of the issue with minor version incompatibilities and the need for [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), +because of the issue with minor version incompatibilities and the need +for [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), sticking with the `Keeper` paradigm instead of ADR 033 may be unviable to begin with. A more performant solution (that could maybe be adapted to work with `Keeper` interfaces) would be to only expose @@ -305,6 +317,7 @@ getters and setters for generated types and internally store data in memory buff one implementation to another in a zero-copy way. For example, imagine this protobuf API with only getters and setters is exposed for `MsgSend`: + ```go type MsgSend interface { proto.Message @@ -349,7 +362,8 @@ In order to simplify access to other modules using ADR 033, a public API module of requiring to generate all client types internally. The big downsides of this approach are that it requires big changes to how people use protobuf types and would be a -substantial rewrite of the protobuf code generator. This new generated code, however, could still be made compatible with +substantial rewrite of the protobuf code generator. This new generated code, however, could still be made compatible +with the [`google.golang.org/protobuf/reflect/protoreflect`](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect) API in order to work with all standard golang protobuf tooling. @@ -368,7 +382,7 @@ sync (what we do now) or attempt some ad-hoc potentially hacky solution. One approach is to ditch go semantic import versioning (SIV) altogether. Some people have commented that go's SIV (i.e. changing the import path to `foo/v2`, `foo/v3`, etc.) is too restrictive and that it should be optional. The golang maintainers disagree and only officially support semantic import versioning. We could, however, take the -contrarian perspective and get more flexibility by using 0.x-based versioning basically forever. +contrarian perspective and get more flexibility by using 0.x-based versioning basically forever. Module version compatibility could then be achieved using go.mod replace directives to pin dependencies to specific compatible 0.x versions. For instance if we knew `foo` 0.2 and 0.3 were both compatible with `bar` 0.3 and 0.4, we @@ -386,19 +400,37 @@ is properly addressed. ## Decision Based on discussions within the team, the current draft consensus is the following: + 1. we are alignment on adopting [ADR 033](./adr-033-protobuf-inter-module-comm.md) not just as an addition to the -framework, but as a core replacement to the keeper paradigm entirely. + framework, but as a core replacement to the keeper paradigm entirely. 2. the ADR 033 inter-module router will accommodate any variation of approach (A) or (B) given the following rules: - a. if the client type is the same as the server type then pass it directly through, - b. if both client and server use the zero-copy generated code wrappers (which still need to be defined), then pass -the memory buffers from one wrapper to the other, or - c. marshal/unmarshal types between client and server. + a. if the client type is the same as the server type then pass it directly through, + b. if both client and server use the zero-copy generated code wrappers (which still need to be defined), then pass + the memory buffers from one wrapper to the other, or + c. marshal/unmarshal types between client and server. This approach will allow for both maximal correctness and enable a clear path to enabling modules within in other languages, possibly executed within a WASM VM. ### Minor API Revisions +To declare minor API revisions of proto files, we propose the following guidelines (which were already documented +in [cosmos.app.v1alpha module options](../proto/cosmos/app/v1alpha1/module.proto)): +* proto packages which are revised from their initial version (considered revision `0`) should include a `package` +* comment in some .proto file containing the test `Revision N` at the start of a comment line where `N` is the current +revision number. +* all fields, messages, etc. added in a version beyond the initial revision should add a comment at the start of a +comment line of the form `Since: Revision N` where `N` is the non-zero revision it was added. + +It is advised that there is a 1:1 correspondence between a state machine module and versioned set of proto files +which are versioned either as a buf module a go API module or both. If the buf schema registry is used, the version of +this buf module should always be `1.N` where `N` corresponds to the package revision. Patch releases should be used when +only documentation comments are updated. It is okay to include proto packages named `v2`, `v3`, etc. in this same +`1.N` versioned buf module (ex. `cosmos.bank.v2`) as long as all these proto packages consist of a single API intended +to be served by a single SDK module. + +### Introspecting Minor API Revisions + In order for modules to introspect the minor API revision of peer modules, we propose adding the following method to `cosmossdk.io/core/intermodule.Client`: @@ -428,12 +460,51 @@ type MsgClient interface { To correctly perform [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering), the inter-module router can do one of the following: + * use the `protoreflect` API for messages which support that * for gogo proto messages, marshal and use the existing `codec/unknownproto` code -* for zero-copy messages, do a simple check on the highest set field number (assuming we can require that fields are -adding consecutively in increasing order) +* for zero-copy messages, do a simple check on the highest set field number (assuming we can require that fields are + adding consecutively in increasing order) + +### `FileDescriptor` Registration + +Because a single go binary may contain different versions of the same generated protobuf code, we cannot rely on the +global protobuf registry to contain the correct `FileDescriptor`s. Because `appconfig` module configuration is itself +written in protobuf, we would like to load the `FileDescriptor`s for a module before loading a module itself. So we +will provide ways to register `FileDescriptor`s at module registration time before instantiation. We propose the +following `cosmossdk.io/core/appmodule.Option` constructors for the various cases of how `FileDescriptor`s may be +packaged: + +```go +package appmodule + +// this can be used when we are using google.golang.org/protobuf compatible generated code +// Ex: +// ProtoFiles(bankv1beta1.File_cosmos_bank_v1beta1_module_proto) +func ProtoFiles(file []protoreflect.FileDescriptor) Option {} + +// this can be used when we are using gogo proto generated code. +func GzippedProtoFiles(file [][]byte) Option {} -### Dependency Declaration +// this can be used when we are using buf build to generated a pinned file descriptor +func ProtoImage(protoImage []byte) Option {} +``` + +This approach allows us to support several ways protobuf files might be generated: +* proto files generated internally to a module (use `ProtoFiles`) +* the API module approach with pinned file descriptors (use `ProtoImage`) +* gogo proto (use `GzippedProtoFiles`) + +### Module Dependency Declaration + +One risk of ADR 033 is that dependencies are called at runtime which are not present in the loaded set of SDK modules. +Also we want modules to have a way to define a minimum dependency API revision that they require. Therefore, all +modules should declare their set of dependencies upfront. These dependencies could be defined when a module is +instantiated, but ideally we know what the dependencies are before instantiation and can statically look at an app +config and determine whether the set of modules. For example, if `bar` requires `foo` revision `>= 1`, then we +should be able to know this when creating an app config with two versions of `bar` and `foo`. + +We propose defining these dependencies in the proto options of the module config object itself. ### Interface Registration @@ -441,19 +512,22 @@ We will also need to define how interface methods are defined on types that are In light of the desire to support modules in other languages, we may want to think of solutions that will accommodate other languages such as plugins described briefly in [ADR 033](./adr-033-protobuf-inter-module-comm.md#internal-methods). -### `FileDescriptor` Registration - ### Testing In order to ensure that modules are indeed with multiple versions of their dependencies, we plan to provide specialized -unit and integration testing infrastructure that automatically tests multiple versions of dependencies. +unit and integration testing infrastructure that automatically tests multiple versions of dependencies. #### Unit Testing Unit tests should be conducted inside SDK modules by mocking their dependencies. In a full ADR 033 scenario, this means that all interaction with other modules is done via the inter-module router, so mocking of dependencies means mocking their msg and query server implementations. We will provide both a test runner and fixture to make this -streamlined. The test fixture will be an interface like the following: +streamlined. The key thing that the test runner should do to test compatibility is to test all combinations of +dependency API revisions. This can be done by taking the file descriptors for the dependencies, parsing their comments +to determine the revisions various elements were added, and then created synthetic file descriptors for each revision +by subtracting elements that were added later. + +Here is a proposed API for the unit test runner and fixture: ```go package moduletesting @@ -463,14 +537,16 @@ import ( "testing" "cosmossdk.io/core/intermodule" + "cosmossdk.io/depinject" "google.golang.org/grpc" "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protodesc" ) type TestFixture interface { context.Context - intermodule.Client // for making calls to the module we're testing - BeginBlock() + intermodule.Client // for making calls to the module we're testing + BeginBlock() EndBlock() } @@ -480,63 +556,83 @@ type UnitTestFixture interface { } type UnitTestConfig struct { - ModuleConfig proto.Message + ModuleConfig proto.Message // the module's config object + DepinjectConfig depinject.Config // optional additional depinject config options + DependencyFileDescriptors []protodesc.FileDescriptorProto // optional dependency file descriptors to use instead of the global registry } +// Run runs the test function for all combinations of dependency API revisions. func (cfg UnitTestConfig) Run(t *testing.T, f func(t *testing.T, f UnitTestFixture)) { // ... } ``` +Here is an example for testing bar calling foo which takes advantage of conditional service revisions in the expected +mock arguments: + ```go func TestBar(t *testing.T) { - UnitTestConfig - moduletesting.RunUnitTests(t, &foomodulev1.Module{}, func(t *testing.T, f moduletesting.UnitTestFixture) { + UnitTestConfig{ModuleConfig: &foomodulev1.Module{}}.Run(t, func (t *testing.T, f moduletesting.UnitTestFixture) { ctrl := gomock.NewController(t) mockFooMsgServer := footestutil.NewMockMsgServer() foov1.RegisterMsgServer(f, mockFooMsgServer) - barMsgClient := barv1.NewMsgClient(f) - mockFooMsgServer.EXPECT().DoSomething(gomock.Any(), gomock.Any()).Return(&foov1.MsgDoSomething.Response{}, nil) - res, err := barMsgClient.CallFoo(f, &MsgCallFoo{}) - ... + barMsgClient := barv1.NewMsgClient(f) + if f.ServiceRevision(foov1.Msg_ServiceDesc.ServiceName) >= 1 { + mockFooMsgServer.EXPECT().DoSomething(gomock.Any(), &foov1.MsgDoSomething{ + ..., + Condition: ..., // condition is expected in revision >= 1 + }).Return(&foov1.MsgDoSomethingResponse{}, nil) + } else { + mockFooMsgServer.EXPECT().DoSomething(gomock.Any(), &foov1.MsgDoSomething{...}).Return(&foov1.MsgDoSomethingResponse{}, nil) + } + res, err := barMsgClient.CallFoo(f, &MsgCallFoo{}) + ... }) } ``` +The unit test runner would make sure that no dependency mocks return arguments which are invalid for the service +revision being tested to ensure that modules don't incorrectly depend on functionality not present in a given revision. + #### Integration Testing +An integration test runner and fixture would also be provided which instead of using mocks would test actual module +dependencies in various combinations. Here is the proposed API: ```go type IntegrationTestFixture interface { - TestFixture + TestFixture } type IntegrationTestConfig struct { - ModuleConfig proto.Message - DependencyMatrix map[string][]proto.Message + ModuleConfig proto.Message // the module's config object + DependencyMatrix map[string][]proto.Message // all the dependent module configs } -func (cfg IntegationTestConfig) Run(t *testing.T, f func(t *testing.T, f IntegrationTestFixture)) { +// Run runs the test function for all combinations of dependency modules. +func (cfg IntegationTestConfig) Run(t *testing.T, f func (t *testing.T, f IntegrationTestFixture)) { // ... } ``` +And here is an example with foo and bar: + ```go func TestBarIntegration(t *testing.T) { - IntegrationTestConfig{ - ModuleConfig: &barmodulev1.Module{}, - DependencyMatrix: map[string][]proto.Message{ - "runtime": []proto.Message{ + IntegrationTestConfig{ + ModuleConfig: &barmodulev1.Module{}, + DependencyMatrix: map[string][]proto.Message{ + "runtime": []proto.Message{ // test against two versions of runtime &runtimev1.Module{}, - &runtimev2.Module{}, + &runtimev2.Module{}, }, - "foo": []proto.Message{ - &foomodulev1.Module{}, + "foo": []proto.Message{ // test against three versions of foo + &foomodulev1.Module{}, &foomodulev2.Module{}, &foomodulev3.Module{}, - } + } } - }.Run(t, func(t *testing.T, f moduletesting.IntegrationTestFixture) { + }.Run(t, func (t *testing.T, f moduletesting.IntegrationTestFixture) { barMsgClient := barv1.NewMsgClient(f) res, err := barMsgClient.CallFoo(f, &MsgCallFoo{}) ... @@ -544,7 +640,11 @@ func TestBarIntegration(t *testing.T) { } ``` -### Proto File and Module Versioning +Unlike unit tests, integration tests actually pull in other module dependencies. So that modules can be written +without direct dependencies on other modules and because golang has no concept of development dependencies, integration +tests should be written in separate go modules, ex. `example.com/bar/v2/test`. Because this paradigm uses go semantic +versioning, it is possible to build a single go module which imports 3 versions of bar and 2 versions of runtime and +can test these all together in the six various combinations of dependencies. ## Consequences @@ -557,7 +657,7 @@ the migration overhead. ### Positive * we will be able to deliver interoperable semantically versioned modules which should dramatically increase the -ability of the Cosmos SDK ecosystem to iterate on new features + ability of the Cosmos SDK ecosystem to iterate on new features * it will be possible to write Cosmos SDK modules in other languages in the near future ### Negative @@ -567,24 +667,24 @@ ability of the Cosmos SDK ecosystem to iterate on new features ### Neutral * the `cosmossdk.io/core/appconfig` framework will play a more central role in terms of how modules are defined, this -is likely generally a good thing but does mean additional changes for users wanting to stick to the pre-depinject way -of wiring up modules + is likely generally a good thing but does mean additional changes for users wanting to stick to the pre-depinject way + of wiring up modules * `depinject` is somewhat less needed or maybe even obviated because of the full ADR 033 approach. If we adopt the -core API proposed in https://github.com/cosmos/cosmos-sdk/pull/12239, then a module would probably always instantiate -itself with a method `ProvideModule(appmodule.Service) (appmodule.AppModule, error)`. There is no complex wiring of -keeper dependencies in this scenario and dependency injection may not have as much of (or any) use case. - + core API proposed in https://github.com/cosmos/cosmos-sdk/pull/12239, then a module would probably always instantiate + itself with a method `ProvideModule(appmodule.Service) (appmodule.AppModule, error)`. There is no complex wiring of + keeper dependencies in this scenario and dependency injection may not have as much of (or any) use case. ## Further Discussions The decision described above is considered in draft mode and is pending final buy-in from the team and key stakeholders. Key outstanding discussions if we do adopt that direction are: + * how do module clients introspect dependency module API revisions * how do modules determine a minor dependency module API revision requirement -* how do modules appropriately test compatibility with different dependency versions +* how do modules appropriately test compatibility with different dependency versions * how to register and resolve interface implementations * how do modules register their protobuf file descriptors depending on the approach they take to generated code (the -API module approach may still be viable as a supported strategy and would need pinned file descriptors) + API module approach may still be viable as a supported strategy and would need pinned file descriptors) ## References diff --git a/proto/cosmos/app/v1alpha1/module.proto b/proto/cosmos/app/v1alpha1/module.proto index 990857172ec5..e5413786509e 100644 --- a/proto/cosmos/app/v1alpha1/module.proto +++ b/proto/cosmos/app/v1alpha1/module.proto @@ -57,7 +57,7 @@ message PackageReference { // // When a new version of a module is released and items are added to existing // .proto files, these definitions should contain comments of the form - // "Since Revision N" where N is an integer revision. + // "Since: Revision N" where N is an integer revision. // // When the module runtime starts up, it will check the pinned proto // image and panic if there are runtime protobuf definitions that are not From 145d73eca5674960f18f81e28d480a9155db7814 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Mon, 28 Nov 2022 16:42:37 -0500 Subject: [PATCH 21/24] update zero-copy section --- .../adr-054-semver-compatible-modules.md | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 0c9538ee3346..aac0381ee494 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -319,24 +319,13 @@ type MsgSend interface { func NewMsgSend() MsgSend { return &msgSendImpl{memoryBuffers: ...} } ``` -Under the hood, `MsgSend` could be implemented based on some raw memory buffers, ex: -```go -type msgSendImpl struct { - memoryBuffers []interface{} -} - -func (m *msgSendImpl) GetFromAddress() { - return m.memoryBuffers[0].(string) -} - -func (m *msgSendImpl) GetToAddress() { - return m.memoryBuffers[1].(string) -} -``` - -This approach would have the added benefits of allowing zero-copy message passing to modules written in other languages -such as Rust. It could also make unknown field filtering in inter-module communication simpler if we require that all -new fields are added in sequential order, ex. just checking that no field `> 5` is set. +Under the hood, `MsgSend` could be implemented based on some raw memory buffer in the same way +that [Cap'n Proto](https://capnproto.org) +and [FlatBuffers](https://google.github.io/flatbuffers/) so that we could convert between one version of `MsgSend` +and another without serialization (i.e. zero-copy). This approach would have the added benefits of allowing zero-copy +message passing to modules written in other languages such as Rust and accessed through a VM or FFI. It could also make +unknown field filtering in inter-module communication simpler if we require that all new fields are added in sequential +order, ex. just checking that no field `> 5` is set. Also, we wouldn't have any issues with state machine breaking code on generated types because all the generated code used in the state machine would actually live in the state machine module itself. Depending on how interface From fcf0388f622769cf8ebba57ba2e1b497a5ddf0aa Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Tue, 29 Nov 2022 13:07:22 -0500 Subject: [PATCH 22/24] add approach D --- .../adr-054-semver-compatible-modules.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index 2aa3a704dbda..a22db4432a3b 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -372,6 +372,48 @@ Note, however, that all of these ad-hoc approaches, would be vulnerable to the m described above unless [unknown field filtering](./adr-020-protobuf-transaction-encoding.md#unknown-field-filtering) is properly addressed. +### Approach D) Avoid protobuf generated code in public APIs + +An alternative approach would be to avoid protobuf generated code in public module APIs. This would help avoid the +discrepancy between state machine versions and client API versions at the module to module boundaries. It would mean +that we wouldn't do inter-module message passing based on ADR 033, but rather stick to the existing keeper approach +and take it one step further by avoiding any protobuf generated code in the keeper interface methods. + +Using this approach, our `foo.Keeper.DoSomething` method wouldn't have the generated `MsgDoSomething` struct (which +comes from the protobuf API), but instead positional parameters. Then in order for `foo/v2` to support the `foo/v1` +keeper it would simply need to implement both the v1 and v2 keeper APIs. The `DoSomething` method in v2 could have the +additional `condition` parameter, but this wouldn't be present in v1 at all so there would be no danger of a client +accidentally setting this when it isn't available. + +So this approach would avoid the challenge around minor version incompatibilities because the existing module keeper +API would not get new fields when they are added to protobuf files. + +Taking this approach, however, would likely require making all protobuf generated code internal in order to prevent +it from leaking into the keeper API. This means we would still need to modify the protobuf code generator to not +register `internal/` code with the global registry, and we would still need to manually register protobuf +`FileDescriptor`s (this is probably true in all scenarios). It may, however, be possible to avoid needing to refactor +interface methods on generated types to handlers. + +Also, this approach doesn't address what would be done in scenarios where modules still want to use the message router. +Either way, we probably still want a way to pass messages from one module to another router safely even if it's just for +use cases like `x/gov`, `x/authz`, CosmWasm, etc. That would still require most of the things outlined in approach (B), +although we could advise modules to prefer keepers for communicating with other modules. + +The biggest downside of this approach is probably that it requires a strict refactoring of keeper interfaces to avoid +generated code leaking into the API. This may result in cases where we need to duplicate types that are already defined +in proto files and then write methods for converting between the golang and protobuf version. This may end up in a lot +of unnecessary boilerplate and that may discourage modules from actually adopting it and achieving effective version +compatibility. Approaches (A) and (B), although heavy handed initially, aim to provide a system which once adopted +more or less gives the developer version compatibility for free with minimal boilerplate. Approach (D) may not be able +to provide such a straightforward system since it requires a golang API to be defined alongside a protobuf API in a +way that requires duplication and differing sets of design principles (protobuf APIs encourage additive changes +while golang APIs would forbid it). + +Other downsides to this approach are: +* no clear roadmap to supporting modules in other languages like Rust +* doesn't get us any closer to proper object capability security (one of the goals of ADR 033) +* ADR 033 needs to be done properly anyway for the set of use cases which do need it + ## Decision Based on discussions within the team, the current draft consensus is the following: From da3fbacb8cd96763504f47783dcd55747a02ffad Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 11 Jan 2023 15:16:36 -0500 Subject: [PATCH 23/24] revert --- baseapp/abci.go | 153 ++- baseapp/abci_test.go | 1509 ++++++++++++++++++++++++++-- baseapp/baseapp.go | 204 ++-- baseapp/baseapp_test.go | 630 +++++++++++- baseapp/block_gas_test.go | 16 +- baseapp/grpcrouter.go | 2 +- baseapp/grpcrouter_test.go | 2 +- baseapp/grpcserver.go | 2 +- baseapp/msg_service_router.go | 2 +- baseapp/msg_service_router_test.go | 4 +- baseapp/options.go | 50 +- baseapp/recovery.go | 3 +- baseapp/state.go | 5 +- baseapp/utils_test.go | 392 ++++++++ 14 files changed, 2676 insertions(+), 298 deletions(-) create mode 100644 baseapp/utils_test.go diff --git a/baseapp/abci.go b/baseapp/abci.go index 707f55f4cbba..71e1582ee419 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -17,7 +17,8 @@ import ( grpcstatus "google.golang.org/grpc/status" "github.com/cosmos/cosmos-sdk/codec" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + snapshottypes "github.com/cosmos/cosmos-sdk/store/snapshots/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -52,10 +53,10 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } // initialize states with a correct header - app.setDeliverState(initHeader) - app.setCheckState(initHeader) - app.setPrepareProposalState(initHeader) - app.setProcessProposalState(initHeader) + app.setState(runTxModeDeliver, initHeader) + app.setState(runTxModeCheck, initHeader) + app.setState(runTxPrepareProposal, initHeader) + app.setState(runTxProcessProposal, initHeader) // Store the consensus params in the BaseApp's paramstore. Note, this must be // done after the deliver state and context have been set as it's persisted @@ -69,7 +70,7 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } // add block gas meter for any genesis transactions (allow infinite gas) - app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(sdk.NewInfiniteGasMeter()) + app.deliverState.ctx = app.deliverState.ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) res = app.initChainer(app.deliverState.ctx, req) @@ -149,7 +150,7 @@ func (app *BaseApp) FilterPeerByID(info string) abci.ResponseQuery { // BeginBlock implements the ABCI application interface. func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeginBlock) { if app.cms.TracingEnabled() { - app.cms.SetTracingContext(sdk.TraceContext( + app.cms.SetTracingContext(storetypes.TraceContext( map[string]interface{}{"blockHeight": req.Header.Height}, )) } @@ -162,7 +163,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // already be initialized in InitChain. Otherwise app.deliverState will be // nil, since it is reset on Commit. if app.deliverState == nil { - app.setDeliverState(req.Header) + app.setState(runTxModeDeliver, req.Header) } else { // In the first block, app.deliverState.ctx will already be initialized // by InitChain. Context is now updated with Header information. @@ -172,11 +173,11 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg } // add block gas meter - var gasMeter sdk.GasMeter - if maxGas := app.getMaximumBlockGas(app.deliverState.ctx); maxGas > 0 { - gasMeter = sdk.NewGasMeter(maxGas) + var gasMeter storetypes.GasMeter + if maxGas := app.GetMaximumBlockGas(app.deliverState.ctx); maxGas > 0 { + gasMeter = storetypes.NewGasMeter(maxGas) } else { - gasMeter = sdk.NewInfiniteGasMeter() + gasMeter = storetypes.NewInfiniteGasMeter() } // NOTE: header hash is not set in NewContext, so we manually set it here @@ -201,11 +202,8 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // call the hooks with the BeginBlock messages for _, streamingListener := range app.abciListeners { - - goCtx := sdk.WrapSDKContext(app.deliverState.ctx) - - if err := streamingListener.ListenBeginBlock(goCtx, req, res); err != nil { - app.logger.Error("BeginBlock listening hook failed", "height", req.Header.Height, "err", err) + if err := streamingListener.ListenBeginBlock(app.deliverState.ctx, req, res); err != nil { + panic(fmt.Errorf("BeginBlock listening hook failed, height: %d, err: %w", req.Header.Height, err)) } } @@ -215,7 +213,7 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) (res abci.ResponseBeg // EndBlock implements the ABCI interface. func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBlock) { if app.deliverState.ms.TracingEnabled() { - app.deliverState.ms = app.deliverState.ms.SetTracingContext(nil).(sdk.CacheMultiStore) + app.deliverState.ms = app.deliverState.ms.SetTracingContext(nil).(storetypes.CacheMultiStore) } if app.endBlocker != nil { @@ -229,10 +227,8 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // call the streaming service hooks with the EndBlock messages for _, streamingListener := range app.abciListeners { - goCtx := sdk.WrapSDKContext(app.deliverState.ctx) - - if err := streamingListener.ListenEndBlock(goCtx, req, res); err != nil { - app.logger.Error("EndBlock listening hook failed", "height", req.Height, "err", err) + if err := streamingListener.ListenEndBlock(app.deliverState.ctx, req, res); err != nil { + panic(fmt.Errorf("EndBlock listening hook failed, height: %d, err: %w", req.Height, err)) } } @@ -252,12 +248,39 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc // // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/tendermint/tendermint/blob/main/spec/abci/abci%2B%2B_basic_concepts.md -func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { - ctx := app.getContextForTx(runTxPrepareProposal, []byte{}) +func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) (resp abci.ResponsePrepareProposal) { if app.prepareProposal == nil { panic("PrepareProposal method not set") } - return app.prepareProposal(ctx, req) + + // Tendermint must never call PrepareProposal with a height of 0. + // Ref: https://github.com/tendermint/tendermint/blob/059798a4f5b0c9f52aa8655fa619054a0154088c/spec/core/state.md?plain=1#L37-L38 + if req.Height < 1 { + panic("PrepareProposal called with invalid height") + } + + ctx := app.getContextForProposal(app.prepareProposalState.ctx, req.Height) + + ctx = ctx.WithVoteInfos(app.voteInfos). + WithBlockHeight(req.Height). + WithBlockTime(req.Time). + WithProposer(req.ProposerAddress). + WithConsensusParams(app.GetConsensusParams(ctx)) + + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in PrepareProposal", + "height", req.Height, + "time", req.Time, + "panic", err, + ) + resp = abci.ResponsePrepareProposal{Txs: req.Txs} + } + }() + + resp = app.prepareProposal(ctx, req) + return resp } // ProcessProposal implements the ProcessProposal ABCI method and returns a @@ -268,24 +291,43 @@ func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) abci.Respon // that all transactions are valid. If all transactions are valid, then we inform // Tendermint that the Status is ACCEPT. However, the application is also able // to implement optimizations such as executing the entire proposed block -// immediately. It may even execute the block in parallel. +// immediately. +// +// If a panic is detected during execution of an application's ProcessProposal +// handler, it will be recovered and we will reject the proposal. // // Ref: https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-060-abci-1.0.md // Ref: https://github.com/tendermint/tendermint/blob/main/spec/abci/abci%2B%2B_basic_concepts.md -func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { +func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) (resp abci.ResponseProcessProposal) { if app.processProposal == nil { panic("app.ProcessProposal is not set") } - ctx := app.processProposalState.ctx. + ctx := app.getContextForProposal(app.processProposalState.ctx, req.Height) + + ctx = ctx. WithVoteInfos(app.voteInfos). WithBlockHeight(req.Height). WithBlockTime(req.Time). WithHeaderHash(req.Hash). WithProposer(req.ProposerAddress). - WithConsensusParams(app.GetConsensusParams(app.processProposalState.ctx)) + WithConsensusParams(app.GetConsensusParams(ctx)) + + defer func() { + if err := recover(); err != nil { + app.logger.Error( + "panic recovered in ProcessProposal", + "height", req.Height, + "time", req.Time, + "hash", fmt.Sprintf("%X", req.Hash), + "panic", err, + ) + resp = abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT} + } + }() - return app.processProposal(ctx, req) + resp = app.processProposal(ctx, req) + return resp } // CheckTx implements the ABCI interface and executes a tx in CheckTx mode. In @@ -334,10 +376,8 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv defer func() { for _, streamingListener := range app.abciListeners { - goCtx := sdk.WrapSDKContext(app.deliverState.ctx) - - if err := streamingListener.ListenDeliverTx(goCtx, req, res); err != nil { - app.logger.Error("DeliverTx listening hook failed", "err", err) + if err := streamingListener.ListenDeliverTx(app.deliverState.ctx, req, res); err != nil { + panic(fmt.Errorf("DeliverTx listening hook failed: %w", err)) } } }() @@ -371,7 +411,7 @@ func (app *BaseApp) DeliverTx(req abci.RequestDeliverTx) (res abci.ResponseDeliv // defined in config, Commit will execute a deferred function call to check // against that height and gracefully halt if it matches the latest committed // height. -func (app *BaseApp) Commit() (res abci.ResponseCommit) { +func (app *BaseApp) Commit() abci.ResponseCommit { header := app.deliverState.ctx.BlockHeader() retainHeight := app.GetBlockRetentionHeight(header.Height) @@ -380,15 +420,28 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { // MultiStore (app.cms) so when Commit() is called is persists those values. app.deliverState.ms.Write() commitID := app.cms.Commit() + + res := abci.ResponseCommit{ + Data: commitID.Hash, + RetainHeight: retainHeight, + } + + // call the hooks with the Commit message + for _, streamingListener := range app.abciListeners { + if err := streamingListener.ListenCommit(app.deliverState.ctx, res); err != nil { + panic(fmt.Errorf("Commit listening hook failed, height: %d, err: %w", header.Height, err)) + } + } + app.logger.Info("commit synced", "commit", fmt.Sprintf("%X", commitID)) // Reset the Check state to the latest committed. // // NOTE: This is safe because Tendermint holds a lock on the mempool for // Commit. Use the header from this latest block. - app.setCheckState(header) - app.setPrepareProposalState(header) - app.setProcessProposalState(header) + app.setState(runTxModeCheck, header) + app.setState(runTxPrepareProposal, header) + app.setState(runTxProcessProposal, header) // empty/reset the deliver state app.deliverState = nil @@ -413,10 +466,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) { go app.snapshotManager.SnapshotIfApplicable(header.Height) - return abci.ResponseCommit{ - Data: commitID.Hash, - RetainHeight: retainHeight, - } + return res } // halt attempts to gracefully shutdown the node via SIGINT and SIGTERM falling @@ -612,7 +662,7 @@ func (app *BaseApp) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci. } func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery { - ctx, err := app.createQueryContext(req.Height, req.Prove) + ctx, err := app.CreateQueryContext(req.Height, req.Prove) if err != nil { return sdkerrors.QueryResult(err, app.trace) } @@ -660,7 +710,7 @@ func checkNegativeHeight(height int64) error { // createQueryContext creates a new sdk.Context for a query, taking as args // the block height and whether the query needs a proof or not. -func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) { +func (app *BaseApp) CreateQueryContext(height int64, prove bool) (sdk.Context, error) { if err := checkNegativeHeight(height); err != nil { return sdk.Context{}, err } @@ -668,7 +718,7 @@ func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, e // use custom query multistore if provided qms := app.qms if qms == nil { - qms = app.cms.(sdk.MultiStore) + qms = app.cms.(storetypes.MultiStore) } lastBlockHeight := qms.LatestVersion() @@ -831,7 +881,7 @@ func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.Res func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { // "/store" prefix for store queries - queryable, ok := app.cms.(sdk.Queryable) + queryable, ok := app.cms.(storetypes.Queryable) if !ok { return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "multistore doesn't support queries"), app.trace) } @@ -894,3 +944,14 @@ func SplitABCIQueryPath(requestPath string) (path []string) { return path } + +// getContextForProposal returns the right context for PrepareProposal and +// ProcessProposal. We use deliverState on the first block to be able to access +// any state changes made in InitChain. +func (app *BaseApp) getContextForProposal(ctx sdk.Context, height int64) sdk.Context { + if height == 1 { + ctx, _ = app.deliverState.ctx.CacheContext() + return ctx + } + return ctx +} diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index c1e2934c7779..bd81ea41e1af 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -1,29 +1,1207 @@ -package baseapp +package baseapp_test import ( - "encoding/json" + "bytes" "errors" - "os" + "fmt" + "strings" "testing" + dbm "github.com/cosmos/cosmos-db" + + "github.com/cosmos/gogoproto/jsonpb" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" - "github.com/cosmos/cosmos-sdk/snapshots" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" + "github.com/cosmos/cosmos-sdk/baseapp" + baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types" + "github.com/cosmos/cosmos-sdk/store/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/store/snapshots/types" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/mempool" + "github.com/cosmos/cosmos-sdk/x/auth/signing" ) -func defaultLogger() log.Logger { - return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app") +func TestABCI_Info(t *testing.T) { + suite := NewBaseAppSuite(t) + + reqInfo := abci.RequestInfo{} + res := suite.baseApp.Info(reqInfo) + + require.Equal(t, "", res.Version) + require.Equal(t, t.Name(), res.GetData()) + require.Equal(t, int64(0), res.LastBlockHeight) + require.Equal(t, []uint8(nil), res.LastBlockAppHash) + require.Equal(t, suite.baseApp.AppVersion(), res.AppVersion) } -func TestGetBlockRentionHeight(t *testing.T) { +func TestABCI_InitChain(t *testing.T) { + name := t.Name() + db := dbm.NewMemDB() + logger := defaultLogger() + app := baseapp.NewBaseApp(name, logger, db, nil) + + capKey := storetypes.NewKVStoreKey("main") + capKey2 := storetypes.NewKVStoreKey("key2") + app.MountStores(capKey, capKey2) + + // set a value in the store on init chain + key, value := []byte("hello"), []byte("goodbye") + var initChainer sdk.InitChainer = func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + store := ctx.KVStore(capKey) + store.Set(key, value) + return abci.ResponseInitChain{} + } + + query := abci.RequestQuery{ + Path: "/store/main/key", + Data: key, + } + + // initChain is nil - nothing happens + app.InitChain(abci.RequestInitChain{}) + res := app.Query(query) + require.Equal(t, 0, len(res.Value)) + + // set initChainer and try again - should see the value + app.SetInitChainer(initChainer) + + // stores are mounted and private members are set - sealing baseapp + err := app.LoadLatestVersion() // needed to make stores non-nil + require.Nil(t, err) + require.Equal(t, int64(0), app.LastBlockHeight()) + + initChainRes := app.InitChain(abci.RequestInitChain{AppStateBytes: []byte("{}"), ChainId: "test-chain-id"}) // must have valid JSON genesis file, even if empty + + // The AppHash returned by a new chain is the sha256 hash of "". + // $ echo -n '' | sha256sum + // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + require.Equal( + t, + []byte{0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + initChainRes.AppHash, + ) + + // assert that chainID is set correctly in InitChain + chainID := getDeliverStateCtx(app).ChainID() + require.Equal(t, "test-chain-id", chainID, "ChainID in deliverState not set correctly in InitChain") + + chainID = getCheckStateCtx(app).ChainID() + require.Equal(t, "test-chain-id", chainID, "ChainID in checkState not set correctly in InitChain") + + app.Commit() + res = app.Query(query) + require.Equal(t, int64(1), app.LastBlockHeight()) + require.Equal(t, value, res.Value) + + // reload app + app = baseapp.NewBaseApp(name, logger, db, nil) + app.SetInitChainer(initChainer) + app.MountStores(capKey, capKey2) + err = app.LoadLatestVersion() // needed to make stores non-nil + require.Nil(t, err) + require.Equal(t, int64(1), app.LastBlockHeight()) + + // ensure we can still query after reloading + res = app.Query(query) + require.Equal(t, value, res.Value) + + // commit and ensure we can still query + header := tmproto.Header{Height: app.LastBlockHeight() + 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + app.Commit() + + res = app.Query(query) + require.Equal(t, value, res.Value) +} + +func TestABCI_InitChain_WithInitialHeight(t *testing.T) { + name := t.Name() + db := dbm.NewMemDB() + logger := defaultLogger() + app := baseapp.NewBaseApp(name, logger, db, nil) + + app.InitChain( + abci.RequestInitChain{ + InitialHeight: 3, + }, + ) + app.Commit() + + require.Equal(t, int64(3), app.LastBlockHeight()) +} + +func TestABCI_BeginBlock_WithInitialHeight(t *testing.T) { + name := t.Name() + db := dbm.NewMemDB() + logger := defaultLogger() + app := baseapp.NewBaseApp(name, logger, db, nil) + + app.InitChain( + abci.RequestInitChain{ + InitialHeight: 3, + }, + ) + + require.PanicsWithError(t, "invalid height: 4; expected: 3", func() { + app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: 4, + }, + }) + }) + + app.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{ + Height: 3, + }, + }) + app.Commit() + + require.Equal(t, int64(3), app.LastBlockHeight()) +} + +func TestABCI_GRPCQuery(t *testing.T) { + grpcQueryOpt := func(bapp *baseapp.BaseApp) { + testdata.RegisterQueryServer( + bapp.GRPCQueryRouter(), + testdata.QueryImpl{}, + ) + } + + suite := NewBaseAppSuite(t, grpcQueryOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + suite.baseApp.Commit() + + req := testdata.SayHelloRequest{Name: "foo"} + reqBz, err := req.Marshal() + require.NoError(t, err) + + reqQuery := abci.RequestQuery{ + Data: reqBz, + Path: "/testdata.Query/SayHello", + } + + resQuery := suite.baseApp.Query(reqQuery) + require.Equal(t, abci.CodeTypeOK, resQuery.Code, resQuery) + + var res testdata.SayHelloResponse + require.NoError(t, res.Unmarshal(resQuery.Value)) + require.Equal(t, "Hello foo!", res.Greeting) +} + +func TestABCI_P2PQuery(t *testing.T) { + addrPeerFilterOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAddrPeerFilter(func(addrport string) abci.ResponseQuery { + require.Equal(t, "1.1.1.1:8000", addrport) + return abci.ResponseQuery{Code: uint32(3)} + }) + } + + idPeerFilterOpt := func(bapp *baseapp.BaseApp) { + bapp.SetIDPeerFilter(func(id string) abci.ResponseQuery { + require.Equal(t, "testid", id) + return abci.ResponseQuery{Code: uint32(4)} + }) + } + + suite := NewBaseAppSuite(t, addrPeerFilterOpt, idPeerFilterOpt) + + addrQuery := abci.RequestQuery{ + Path: "/p2p/filter/addr/1.1.1.1:8000", + } + res := suite.baseApp.Query(addrQuery) + require.Equal(t, uint32(3), res.Code) + + idQuery := abci.RequestQuery{ + Path: "/p2p/filter/id/testid", + } + res = suite.baseApp.Query(idQuery) + require.Equal(t, uint32(4), res.Code) +} + +func TestABCI_ListSnapshots(t *testing.T) { + ssCfg := SnapshotsConfig{ + blocks: 5, + blockTxs: 4, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + } + + suite := NewBaseAppSuiteWithSnapshots(t, ssCfg) + + resp := suite.baseApp.ListSnapshots(abci.RequestListSnapshots{}) + for _, s := range resp.Snapshots { + require.NotEmpty(t, s.Hash) + require.NotEmpty(t, s.Metadata) + + s.Hash = nil + s.Metadata = nil + } + + require.Equal(t, abci.ResponseListSnapshots{Snapshots: []*abci.Snapshot{ + {Height: 4, Format: snapshottypes.CurrentFormat, Chunks: 2}, + {Height: 2, Format: snapshottypes.CurrentFormat, Chunks: 1}, + }}, resp) +} + +func TestABCI_SnapshotWithPruning(t *testing.T) { + testCases := map[string]struct { + ssCfg SnapshotsConfig + expectedSnapshots []*abci.Snapshot + }{ + "prune nothing with snapshot": { + ssCfg: SnapshotsConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5}, + }, + }, + "prune everything with snapshot": { + ssCfg: SnapshotsConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningEverything), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5}, + }, + }, + "default pruning with snapshot": { + ssCfg: SnapshotsConfig{ + blocks: 20, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 1, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningDefault), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5}, + }, + }, + "custom": { + ssCfg: SnapshotsConfig{ + blocks: 25, + blockTxs: 2, + snapshotInterval: 5, + snapshotKeepRecent: 2, + pruningOpts: pruningtypes.NewCustomPruningOptions(12, 12), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 25, Format: snapshottypes.CurrentFormat, Chunks: 6}, + {Height: 20, Format: snapshottypes.CurrentFormat, Chunks: 5}, + }, + }, + "no snapshots": { + ssCfg: SnapshotsConfig{ + blocks: 10, + blockTxs: 2, + snapshotInterval: 0, // 0 implies disable snapshots + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{}, + }, + "keep all snapshots": { + ssCfg: SnapshotsConfig{ + blocks: 10, + blockTxs: 2, + snapshotInterval: 3, + snapshotKeepRecent: 0, // 0 implies keep all snapshots + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + }, + expectedSnapshots: []*abci.Snapshot{ + {Height: 9, Format: snapshottypes.CurrentFormat, Chunks: 2}, + {Height: 6, Format: snapshottypes.CurrentFormat, Chunks: 2}, + {Height: 3, Format: snapshottypes.CurrentFormat, Chunks: 1}, + }, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + suite := NewBaseAppSuiteWithSnapshots(t, tc.ssCfg) + + resp := suite.baseApp.ListSnapshots(abci.RequestListSnapshots{}) + for _, s := range resp.Snapshots { + require.NotEmpty(t, s.Hash) + require.NotEmpty(t, s.Metadata) + + s.Hash = nil + s.Metadata = nil + } + + require.Equal(t, abci.ResponseListSnapshots{Snapshots: tc.expectedSnapshots}, resp) + + // Validate that heights were pruned correctly by querying the state at the last height that should be present relative to latest + // and the first height that should be pruned. + // + // Exceptions: + // * Prune nothing: should be able to query all heights (we only test first and latest) + // * Prune default: should be able to query all heights (we only test first and latest) + // * The reason for default behaving this way is that we only commit 20 heights but default has 100_000 keep-recent + var lastExistingHeight int64 + if tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault { + lastExistingHeight = 1 + } else { + // Integer division rounds down so by multiplying back we get the last height at which we pruned + lastExistingHeight = int64((tc.ssCfg.blocks/tc.ssCfg.pruningOpts.Interval)*tc.ssCfg.pruningOpts.Interval - tc.ssCfg.pruningOpts.KeepRecent) + } + + // Query 1 + res := suite.baseApp.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight}) + require.NotNil(t, res, "height: %d", lastExistingHeight) + require.NotNil(t, res.Value, "height: %d", lastExistingHeight) + + // Query 2 + res = suite.baseApp.Query(abci.RequestQuery{Path: fmt.Sprintf("/store/%s/key", capKey2.Name()), Data: []byte("0"), Height: lastExistingHeight - 1}) + require.NotNil(t, res, "height: %d", lastExistingHeight-1) + + if tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningNothing || tc.ssCfg.pruningOpts.GetPruningStrategy() == pruningtypes.PruningDefault { + // With prune nothing or default, we query height 0 which translates to the latest height. + require.NotNil(t, res.Value, "height: %d", lastExistingHeight-1) + } + }) + } +} + +func TestABCI_LoadSnapshotChunk(t *testing.T) { + ssCfg := SnapshotsConfig{ + blocks: 2, + blockTxs: 5, + snapshotInterval: 2, + snapshotKeepRecent: snapshottypes.CurrentFormat, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + } + suite := NewBaseAppSuiteWithSnapshots(t, ssCfg) + + testCases := map[string]struct { + height uint64 + format uint32 + chunk uint32 + expectEmpty bool + }{ + "Existing snapshot": {2, snapshottypes.CurrentFormat, 1, false}, + "Missing height": {100, snapshottypes.CurrentFormat, 1, true}, + "Missing format": {2, snapshottypes.CurrentFormat + 1, 1, true}, + "Missing chunk": {2, snapshottypes.CurrentFormat, 9, true}, + "Zero height": {0, snapshottypes.CurrentFormat, 1, true}, + "Zero format": {2, 0, 1, true}, + "Zero chunk": {2, snapshottypes.CurrentFormat, 0, false}, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + resp := suite.baseApp.LoadSnapshotChunk(abci.RequestLoadSnapshotChunk{ + Height: tc.height, + Format: tc.format, + Chunk: tc.chunk, + }) + if tc.expectEmpty { + require.Equal(t, abci.ResponseLoadSnapshotChunk{}, resp) + return + } + + require.NotEmpty(t, resp.Chunk) + }) + } +} + +func TestABCI_OfferSnapshot_Errors(t *testing.T) { + ssCfg := SnapshotsConfig{ + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + } + suite := NewBaseAppSuiteWithSnapshots(t, ssCfg) + + m := snapshottypes.Metadata{ChunkHashes: [][]byte{{1}, {2}, {3}}} + metadata, err := m.Marshal() + require.NoError(t, err) + + hash := []byte{1, 2, 3} + + testCases := map[string]struct { + snapshot *abci.Snapshot + result abci.ResponseOfferSnapshot_Result + }{ + "nil snapshot": {nil, abci.ResponseOfferSnapshot_REJECT}, + "invalid format": {&abci.Snapshot{ + Height: 1, Format: 9, Chunks: 3, Hash: hash, Metadata: metadata, + }, abci.ResponseOfferSnapshot_REJECT_FORMAT}, + "incorrect chunk count": {&abci.Snapshot{ + Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 2, Hash: hash, Metadata: metadata, + }, abci.ResponseOfferSnapshot_REJECT}, + "no chunks": {&abci.Snapshot{ + Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: metadata, + }, abci.ResponseOfferSnapshot_REJECT}, + "invalid metadata serialization": {&abci.Snapshot{ + Height: 1, Format: snapshottypes.CurrentFormat, Chunks: 0, Hash: hash, Metadata: []byte{3, 1, 4}, + }, abci.ResponseOfferSnapshot_REJECT}, + } + for name, tc := range testCases { + tc := tc + t.Run(name, func(t *testing.T) { + resp := suite.baseApp.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: tc.snapshot}) + require.Equal(t, tc.result, resp.Result) + }) + } + + // Offering a snapshot after one has been accepted should error + resp := suite.baseApp.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{ + Height: 1, + Format: snapshottypes.CurrentFormat, + Chunks: 3, + Hash: []byte{1, 2, 3}, + Metadata: metadata, + }}) + require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, resp) + + resp = suite.baseApp.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: &abci.Snapshot{ + Height: 2, + Format: snapshottypes.CurrentFormat, + Chunks: 3, + Hash: []byte{1, 2, 3}, + Metadata: metadata, + }}) + require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ABORT}, resp) +} + +func TestABCI_ApplySnapshotChunk(t *testing.T) { + srcCfg := SnapshotsConfig{ + blocks: 4, + blockTxs: 10, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + } + srcSuite := NewBaseAppSuiteWithSnapshots(t, srcCfg) + + targetCfg := SnapshotsConfig{ + blocks: 0, + blockTxs: 0, + snapshotInterval: 2, + snapshotKeepRecent: 2, + pruningOpts: pruningtypes.NewPruningOptions(pruningtypes.PruningNothing), + } + targetSuite := NewBaseAppSuiteWithSnapshots(t, targetCfg) + + // fetch latest snapshot to restore + respList := srcSuite.baseApp.ListSnapshots(abci.RequestListSnapshots{}) + require.NotEmpty(t, respList.Snapshots) + snapshot := respList.Snapshots[0] + + // make sure the snapshot has at least 3 chunks + require.GreaterOrEqual(t, snapshot.Chunks, uint32(3), "Not enough snapshot chunks") + + // begin a snapshot restoration in the target + respOffer := targetSuite.baseApp.OfferSnapshot(abci.RequestOfferSnapshot{Snapshot: snapshot}) + require.Equal(t, abci.ResponseOfferSnapshot{Result: abci.ResponseOfferSnapshot_ACCEPT}, respOffer) + + // We should be able to pass an invalid chunk and get a verify failure, before + // reapplying it. + respApply := targetSuite.baseApp.ApplySnapshotChunk(abci.RequestApplySnapshotChunk{ + Index: 0, + Chunk: []byte{9}, + Sender: "sender", + }) + require.Equal(t, abci.ResponseApplySnapshotChunk{ + Result: abci.ResponseApplySnapshotChunk_RETRY, + RefetchChunks: []uint32{0}, + RejectSenders: []string{"sender"}, + }, respApply) + + // fetch each chunk from the source and apply it to the target + for index := uint32(0); index < snapshot.Chunks; index++ { + respChunk := srcSuite.baseApp.LoadSnapshotChunk(abci.RequestLoadSnapshotChunk{ + Height: snapshot.Height, + Format: snapshot.Format, + Chunk: index, + }) + require.NotNil(t, respChunk.Chunk) + + respApply := targetSuite.baseApp.ApplySnapshotChunk(abci.RequestApplySnapshotChunk{ + Index: index, + Chunk: respChunk.Chunk, + }) + require.Equal(t, abci.ResponseApplySnapshotChunk{ + Result: abci.ResponseApplySnapshotChunk_ACCEPT, + }, respApply) + } + + // the target should now have the same hash as the source + require.Equal(t, srcSuite.baseApp.LastCommitID(), targetSuite.baseApp.LastCommitID()) +} + +func TestABCI_EndBlock(t *testing.T) { + db := dbm.NewMemDB() + name := t.Name() + logger := defaultLogger() + + cp := &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ + MaxGas: 5000000, + }, + } + + app := baseapp.NewBaseApp(name, logger, db, nil) + app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) + app.InitChain(abci.RequestInitChain{ + ConsensusParams: cp, + }) + + app.SetEndBlocker(func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { + return abci.ResponseEndBlock{ + ValidatorUpdates: []abci.ValidatorUpdate{ + {Power: 100}, + }, + } + }) + app.Seal() + + res := app.EndBlock(abci.RequestEndBlock{}) + require.Len(t, res.GetValidatorUpdates(), 1) + require.Equal(t, int64(100), res.GetValidatorUpdates()[0].Power) + require.Equal(t, cp.Block.MaxGas, res.ConsensusParamUpdates.Block.MaxGas) +} + +func TestABCI_CheckTx(t *testing.T) { + // This ante handler reads the key and checks that the value matches the + // current counter. This ensures changes to the KVStore persist across + // successive CheckTx runs. + counterKey := []byte("counter-key") + anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, counterKey)) } + suite := NewBaseAppSuite(t, anteOpt) + + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, counterKey}) + + nTxs := int64(5) + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + for i := int64(0); i < nTxs; i++ { + tx := newTxCounter(t, suite.txConfig, i, 0) // no messages + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + r := suite.baseApp.CheckTx(abci.RequestCheckTx{Tx: txBytes}) + require.True(t, r.IsOK(), fmt.Sprintf("%v", r)) + require.Equal(t, testTxPriority, r.Priority) + require.Empty(t, r.GetEvents()) + } + + checkStateStore := getCheckStateCtx(suite.baseApp).KVStore(capKey1) + storedCounter := getIntFromStore(t, checkStateStore, counterKey) + + // ensure AnteHandler ran + require.Equal(t, nTxs, storedCounter) + + // if a block is committed, CheckTx state should be reset + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header, Hash: []byte("hash")}) + + require.NotNil(t, getCheckStateCtx(suite.baseApp).BlockGasMeter(), "block gas meter should have been set to checkState") + require.NotEmpty(t, getCheckStateCtx(suite.baseApp).HeaderHash()) + + suite.baseApp.EndBlock(abci.RequestEndBlock{}) + suite.baseApp.Commit() + + checkStateStore = getCheckStateCtx(suite.baseApp).KVStore(capKey1) + storedBytes := checkStateStore.Get(counterKey) + require.Nil(t, storedBytes) +} + +func TestABCI_DeliverTx(t *testing.T) { + anteKey := []byte("ante-key") + anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } + suite := NewBaseAppSuite(t, anteOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + deliverKey := []byte("deliver-key") + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, deliverKey}) + + nBlocks := 3 + txPerHeight := 5 + + for blockN := 0; blockN < nBlocks; blockN++ { + header := tmproto.Header{Height: int64(blockN) + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + for i := 0; i < txPerHeight; i++ { + counter := int64(blockN*txPerHeight + i) + tx := newTxCounter(t, suite.txConfig, counter, counter) + + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + + events := res.GetEvents() + require.Len(t, events, 3, "should contain ante handler, message type and counter events respectively") + require.Equal(t, sdk.MarkEventsToIndex(counterEvent("ante_handler", counter).ToABCIEvents(), map[string]struct{}{})[0], events[0], "ante handler event") + require.Equal(t, sdk.MarkEventsToIndex(counterEvent(sdk.EventTypeMessage, counter).ToABCIEvents(), map[string]struct{}{})[0], events[2], "msg handler update counter event") + } + + suite.baseApp.EndBlock(abci.RequestEndBlock{}) + suite.baseApp.Commit() + } +} + +func TestABCI_DeliverTx_MultiMsg(t *testing.T) { + anteKey := []byte("ante-key") + anteOpt := func(bapp *baseapp.BaseApp) { bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) } + suite := NewBaseAppSuite(t, anteOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + deliverKey := []byte("deliver-key") + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, deliverKey}) + + deliverKey2 := []byte("deliver-key2") + baseapptestutil.RegisterCounter2Server(suite.baseApp.MsgServiceRouter(), Counter2ServerImpl{t, capKey1, deliverKey2}) + + // run a multi-msg tx + // with all msgs the same route + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + tx := newTxCounter(t, suite.txConfig, 0, 0, 1, 2) + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + + store := getDeliverStateCtx(suite.baseApp).KVStore(capKey1) + + // tx counter only incremented once + txCounter := getIntFromStore(t, store, anteKey) + require.Equal(t, int64(1), txCounter) + + // msg counter incremented three times + msgCounter := getIntFromStore(t, store, deliverKey) + require.Equal(t, int64(3), msgCounter) + + // replace the second message with a Counter2 + tx = newTxCounter(t, suite.txConfig, 1, 3) + + builder := suite.txConfig.NewTxBuilder() + msgs := tx.GetMsgs() + msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 0}) + msgs = append(msgs, &baseapptestutil.MsgCounter2{Counter: 1}) + + builder.SetMsgs(msgs...) + builder.SetMemo(tx.GetMemo()) + setTxSignature(t, builder, 0) + + txBytes, err = suite.txConfig.TxEncoder()(builder.GetTx()) + require.NoError(t, err) + + res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + + store = getDeliverStateCtx(suite.baseApp).KVStore(capKey1) + + // tx counter only incremented once + txCounter = getIntFromStore(t, store, anteKey) + require.Equal(t, int64(2), txCounter) + + // original counter increments by one + // new counter increments by two + msgCounter = getIntFromStore(t, store, deliverKey) + require.Equal(t, int64(4), msgCounter) + + msgCounter2 := getIntFromStore(t, store, deliverKey2) + require.Equal(t, int64(2), msgCounter2) +} + +func TestABCI_Query_SimulateTx(t *testing.T) { + gasConsumed := uint64(5) + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasConsumed)) + return + }) + } + suite := NewBaseAppSuite(t, anteOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{gasConsumed}) + + nBlocks := 3 + for blockN := 0; blockN < nBlocks; blockN++ { + count := int64(blockN + 1) + header := tmproto.Header{Height: count} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + tx := newTxCounter(t, suite.txConfig, count, count) + + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.Nil(t, err) + + // simulate a message, check gas reported + gInfo, result, err := suite.baseApp.Simulate(txBytes) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) + + // simulate again, same result + gInfo, result, err = suite.baseApp.Simulate(txBytes) + require.NoError(t, err) + require.NotNil(t, result) + require.Equal(t, gasConsumed, gInfo.GasUsed) + + // simulate by calling Query with encoded tx + query := abci.RequestQuery{ + Path: "/app/simulate", + Data: txBytes, + } + queryResult := suite.baseApp.Query(query) + require.True(t, queryResult.IsOK(), queryResult.Log) + + var simRes sdk.SimulationResponse + require.NoError(t, jsonpb.Unmarshal(strings.NewReader(string(queryResult.Value)), &simRes)) + + require.Equal(t, gInfo, simRes.GasInfo) + require.Equal(t, result.Log, simRes.Result.Log) + require.Equal(t, result.Events, simRes.Result.Events) + require.True(t, bytes.Equal(result.Data, simRes.Result.Data)) + + suite.baseApp.EndBlock(abci.RequestEndBlock{}) + suite.baseApp.Commit() + } +} + +func TestABCI_InvalidTransaction(t *testing.T) { + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + return + }) + } + + suite := NewBaseAppSuite(t, anteOpt) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + // transaction with no messages + { + emptyTx := suite.txConfig.NewTxBuilder().GetTx() + _, result, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), emptyTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidRequest.ABCICode(), code, err) + } + + // transaction where ValidateBasic fails + { + testCases := []struct { + tx signing.Tx + fail bool + }{ + {newTxCounter(t, suite.txConfig, 0, 0), false}, + {newTxCounter(t, suite.txConfig, -1, 0), false}, + {newTxCounter(t, suite.txConfig, 100, 100), false}, + {newTxCounter(t, suite.txConfig, 100, 5, 4, 3, 2, 1), false}, + + {newTxCounter(t, suite.txConfig, 0, -1), true}, + {newTxCounter(t, suite.txConfig, 0, 1, -2), true}, + {newTxCounter(t, suite.txConfig, 0, 1, 2, -10, 5), true}, + } + + for _, testCase := range testCases { + tx := testCase.tx + _, result, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx) + + if testCase.fail { + require.Error(t, err) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrInvalidSequence.ABCICode(), code, err) + } else { + require.NotNil(t, result) + } + } + } + + // transaction with no known route + { + txBuilder := suite.txConfig.NewTxBuilder() + txBuilder.SetMsgs(&baseapptestutil.MsgCounter2{}) + setTxSignature(t, txBuilder, 0) + unknownRouteTx := txBuilder.GetTx() + + _, result, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) + + txBuilder = suite.txConfig.NewTxBuilder() + txBuilder.SetMsgs(&baseapptestutil.MsgCounter{}, &baseapptestutil.MsgCounter2{}) + setTxSignature(t, txBuilder, 0) + unknownRouteTx = txBuilder.GetTx() + + _, result, err = suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), unknownRouteTx) + require.Error(t, err) + require.Nil(t, result) + + space, code, _ = sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrUnknownRequest.ABCICode(), code, err) + } + + // Transaction with an unregistered message + { + txBuilder := suite.txConfig.NewTxBuilder() + txBuilder.SetMsgs(&testdata.MsgCreateDog{}) + tx := txBuilder.GetTx() + + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.EqualValues(t, sdkerrors.ErrTxDecode.ABCICode(), res.Code) + require.EqualValues(t, sdkerrors.ErrTxDecode.Codespace(), res.Codespace) + } +} + +func TestABCI_TxGasLimits(t *testing.T) { + gasGranted := uint64(10) + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasGranted)) + + // AnteHandlers must have their own defer/recover in order for the BaseApp + // to know how much gas was used! This is because the GasMeter is created in + // the AnteHandler, but if it panics the context won't be set properly in + // runTx's recover call. + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + case storetypes.ErrorOutOfGas: + err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) + default: + panic(r) + } + } + }() + + count, _ := parseTxMemo(t, tx) + newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") + + return newCtx, nil + }) + } + + suite := NewBaseAppSuite(t, anteOpt) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + testCases := []struct { + tx signing.Tx + gasUsed uint64 + fail bool + }{ + {newTxCounter(t, suite.txConfig, 0, 0), 0, false}, + {newTxCounter(t, suite.txConfig, 1, 1), 2, false}, + {newTxCounter(t, suite.txConfig, 9, 1), 10, false}, + {newTxCounter(t, suite.txConfig, 1, 9), 10, false}, + {newTxCounter(t, suite.txConfig, 10, 0), 10, false}, + {newTxCounter(t, suite.txConfig, 0, 10), 10, false}, + {newTxCounter(t, suite.txConfig, 0, 8, 2), 10, false}, + {newTxCounter(t, suite.txConfig, 0, 5, 1, 1, 1, 1, 1), 10, false}, + {newTxCounter(t, suite.txConfig, 0, 5, 1, 1, 1, 1), 9, false}, + + {newTxCounter(t, suite.txConfig, 9, 2), 11, true}, + {newTxCounter(t, suite.txConfig, 2, 9), 11, true}, + {newTxCounter(t, suite.txConfig, 9, 1, 1), 11, true}, + {newTxCounter(t, suite.txConfig, 1, 8, 1, 1), 11, true}, + {newTxCounter(t, suite.txConfig, 11, 0), 11, true}, + {newTxCounter(t, suite.txConfig, 0, 11), 11, true}, + {newTxCounter(t, suite.txConfig, 0, 5, 11), 16, true}, + } + + for i, tc := range testCases { + tx := tc.tx + gInfo, result, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx) + + // check gas used and wanted + require.Equal(t, tc.gasUsed, gInfo.GasUsed, fmt.Sprintf("tc #%d; gas: %v, result: %v, err: %s", i, gInfo, result, err)) + + // check for out of gas + if !tc.fail { + require.NotNil(t, result, fmt.Sprintf("%d: %v, %v", i, tc, err)) + } else { + require.Error(t, err) + require.Nil(t, result) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) + } + } +} + +func TestABCI_MaxBlockGasLimits(t *testing.T) { + gasGranted := uint64(10) + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasGranted)) + + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + case storetypes.ErrorOutOfGas: + err = sdkerrors.Wrapf(sdkerrors.ErrOutOfGas, "out of gas in location: %v", rType.Descriptor) + default: + panic(r) + } + } + }() + + count, _ := parseTxMemo(t, tx) + newCtx.GasMeter().ConsumeGas(uint64(count), "counter-ante") + + return + }) + } + + suite := NewBaseAppSuite(t, anteOpt) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ + MaxGas: 100, + }, + }, + }) + + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + testCases := []struct { + tx signing.Tx + numDelivers int + gasUsedPerDeliver uint64 + fail bool + failAfterDeliver int + }{ + {newTxCounter(t, suite.txConfig, 0, 0), 0, 0, false, 0}, + {newTxCounter(t, suite.txConfig, 9, 1), 2, 10, false, 0}, + {newTxCounter(t, suite.txConfig, 10, 0), 3, 10, false, 0}, + {newTxCounter(t, suite.txConfig, 10, 0), 10, 10, false, 0}, + {newTxCounter(t, suite.txConfig, 2, 7), 11, 9, false, 0}, + {newTxCounter(t, suite.txConfig, 10, 0), 10, 10, false, 0}, // hit the limit but pass + + {newTxCounter(t, suite.txConfig, 10, 0), 11, 10, true, 10}, + {newTxCounter(t, suite.txConfig, 10, 0), 15, 10, true, 10}, + {newTxCounter(t, suite.txConfig, 9, 0), 12, 9, true, 11}, // fly past the limit + } + + for i, tc := range testCases { + tx := tc.tx + + // reset the block gas + header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + // execute the transaction multiple times + for j := 0; j < tc.numDelivers; j++ { + _, result, err := suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx) + + ctx := getDeliverStateCtx(suite.baseApp) + + // check for failed transactions + if tc.fail && (j+1) > tc.failAfterDeliver { + require.Error(t, err, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + require.Nil(t, result, fmt.Sprintf("tc #%d; result: %v, err: %s", i, result, err)) + + space, code, _ := sdkerrors.ABCIInfo(err, false) + require.EqualValues(t, sdkerrors.ErrOutOfGas.Codespace(), space, err) + require.EqualValues(t, sdkerrors.ErrOutOfGas.ABCICode(), code, err) + require.True(t, ctx.BlockGasMeter().IsOutOfGas()) + } else { + // check gas used and wanted + blockGasUsed := ctx.BlockGasMeter().GasConsumed() + expBlockGasUsed := tc.gasUsedPerDeliver * uint64(j+1) + require.Equal( + t, expBlockGasUsed, blockGasUsed, + fmt.Sprintf("%d,%d: %v, %v, %v, %v", i, j, tc, expBlockGasUsed, blockGasUsed, result), + ) + + require.NotNil(t, result, fmt.Sprintf("tc #%d; currDeliver: %d, result: %v, err: %s", i, j, result, err)) + require.False(t, ctx.BlockGasMeter().IsPastLimit()) + } + } + } +} + +func TestABCI_GasConsumptionBadTx(t *testing.T) { + gasWanted := uint64(5) + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + newCtx = ctx.WithGasMeter(storetypes.NewGasMeter(gasWanted)) + + defer func() { + if r := recover(); r != nil { + switch rType := r.(type) { + case storetypes.ErrorOutOfGas: + log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor) + err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log) + default: + panic(r) + } + } + }() + + counter, failOnAnte := parseTxMemo(t, tx) + newCtx.GasMeter().ConsumeGas(uint64(counter), "counter-ante") + if failOnAnte { + return newCtx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") + } + + return + }) + } + + suite := NewBaseAppSuite(t, anteOpt) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ + MaxGas: 9, + }, + }, + }) + + header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + tx := newTxCounter(t, suite.txConfig, 5, 0) + tx = setFailOnAnte(t, suite.txConfig, tx, true) + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) + + // require next tx to fail due to black gas limit + tx = newTxCounter(t, suite.txConfig, 5, 0) + txBytes, err = suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) +} + +func TestABCI_Query(t *testing.T) { + key, value := []byte("hello"), []byte("goodbye") + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + store := ctx.KVStore(capKey1) + store.Set(key, value) + return + }) + } + + suite := NewBaseAppSuite(t, anteOpt) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImplGasMeterOnly{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + // NOTE: "/store/key1" tells us KVStore + // and the final "/key" says to use the data as the + // key in the given KVStore ... + query := abci.RequestQuery{ + Path: "/store/key1/key", + Data: key, + } + tx := newTxCounter(t, suite.txConfig, 0, 0) + + // query is empty before we do anything + res := suite.baseApp.Query(query) + require.Equal(t, 0, len(res.Value)) + + // query is still empty after a CheckTx + _, resTx, err := suite.baseApp.SimCheck(suite.txConfig.TxEncoder(), tx) + require.NoError(t, err) + require.NotNil(t, resTx) + + res = suite.baseApp.Query(query) + require.Equal(t, 0, len(res.Value)) + + // query is still empty after a DeliverTx before we commit + header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + _, resTx, err = suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx) + require.NoError(t, err) + require.NotNil(t, resTx) + + res = suite.baseApp.Query(query) + require.Equal(t, 0, len(res.Value)) + + // query returns correct value after Commit + suite.baseApp.Commit() + + res = suite.baseApp.Query(query) + require.Equal(t, value, res.Value) +} + +func TestABCI_GetBlockRetentionHeight(t *testing.T) { logger := defaultLogger() db := dbm.NewMemDB() name := t.Name() @@ -32,81 +1210,81 @@ func TestGetBlockRentionHeight(t *testing.T) { require.NoError(t, err) testCases := map[string]struct { - bapp *BaseApp + bapp *baseapp.BaseApp maxAgeBlocks int64 commitHeight int64 expected int64 }{ "defaults": { - bapp: NewBaseApp(name, logger, db, nil), + bapp: baseapp.NewBaseApp(name, logger, db, nil), maxAgeBlocks: 0, commitHeight: 499000, expected: 0, }, "pruning unbonding time only": { - bapp: NewBaseApp(name, logger, db, nil, SetMinRetainBlocks(1)), + bapp: baseapp.NewBaseApp(name, logger, db, nil, baseapp.SetMinRetainBlocks(1)), maxAgeBlocks: 362880, commitHeight: 499000, expected: 136120, }, "pruning iavl snapshot only": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)), - SetMinRetainBlocks(1), - SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(10000, 1)), + baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)), + baseapp.SetMinRetainBlocks(1), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(10000, 1)), ), maxAgeBlocks: 0, commitHeight: 499000, expected: 489000, }, "pruning state sync snapshot only": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), - SetMinRetainBlocks(1), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), + baseapp.SetMinRetainBlocks(1), ), maxAgeBlocks: 0, commitHeight: 499000, expected: 349000, }, "pruning min retention only": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetMinRetainBlocks(400000), + baseapp.SetMinRetainBlocks(400000), ), maxAgeBlocks: 0, commitHeight: 499000, expected: 99000, }, "pruning all conditions": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), - SetMinRetainBlocks(400000), - SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), + baseapp.SetMinRetainBlocks(400000), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, expected: 99000, }, "no pruning due to no persisted state": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), - SetMinRetainBlocks(400000), - SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), + baseapp.SetMinRetainBlocks(400000), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 10000, expected: 0, }, "disable pruning": { - bapp: NewBaseApp( + bapp: baseapp.NewBaseApp( name, logger, db, nil, - SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), - SetMinRetainBlocks(0), - SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), + baseapp.SetPruning(pruningtypes.NewCustomPruningOptions(0, 0)), + baseapp.SetMinRetainBlocks(0), + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(50000, 3)), ), maxAgeBlocks: 362880, commitHeight: 499000, @@ -132,87 +1310,238 @@ func TestGetBlockRentionHeight(t *testing.T) { } } -// Test and ensure that invalid block heights always cause errors. -// See issues: -// - https://github.com/cosmos/cosmos-sdk/issues/11220 -// - https://github.com/cosmos/cosmos-sdk/issues/7662 -func TestBaseAppCreateQueryContext(t *testing.T) { - t.Parallel() +func TestABCI_Proposal_HappyPath(t *testing.T) { + anteKey := []byte("ante-key") + pool := mempool.NewSenderNonceMempool() + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } - logger := defaultLogger() - db := dbm.NewMemDB() - name := t.Name() - app := NewBaseApp(name, logger, db, nil) + suite := NewBaseAppSuite(t, anteOpt, baseapp.SetMempool(pool)) + baseapptestutil.RegisterKeyValueServer(suite.baseApp.MsgServiceRouter(), MsgKeyValueImpl{}) + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), NoopCounterServerImpl{}) - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}}) - app.Commit() + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) - app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) - app.Commit() + tx := newTxCounter(t, suite.txConfig, 0, 1) + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) - testCases := []struct { - name string - height int64 - prove bool - expErr bool - }{ - {"valid height", 2, true, false}, - {"future height", 10, true, true}, - {"negative height, prove=true", -1, true, true}, - {"negative height, prove=false", -1, false, true}, + reqCheckTx := abci.RequestCheckTx{ + Tx: txBytes, + Type: abci.CheckTxType_New, } + suite.baseApp.CheckTx(reqCheckTx) - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - _, err := app.createQueryContext(tc.height, tc.prove) - if tc.expErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - }) + tx2 := newTxCounter(t, suite.txConfig, 1, 1) + + tx2Bytes, err := suite.txConfig.TxEncoder()(tx2) + require.NoError(t, err) + + err = pool.Insert(sdk.Context{}, tx2) + require.NoError(t, err) + + reqPrepareProposal := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, } + resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) + require.Equal(t, 2, len(resPrepareProposal.Txs)) + + reqProposalTxBytes := [2][]byte{ + txBytes, + tx2Bytes, + } + reqProcessProposal := abci.RequestProcessProposal{ + Txs: reqProposalTxBytes[:], + } + + resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) + require.Equal(t, abci.ResponseProcessProposal_ACCEPT, resProcessProposal.Status) + + suite.baseApp.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, + }) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.Equal(t, 1, pool.CountTx()) + + require.NotEmpty(t, res.Events) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) } -type paramStore struct { - db *dbm.MemDB +func TestABCI_Proposal_Read_State_PrepareProposal(t *testing.T) { + someKey := []byte("some-key") + + setInitChainerOpt := func(bapp *baseapp.BaseApp) { + bapp.SetInitChainer(func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { + ctx.KVStore(capKey1).Set(someKey, []byte("foo")) + return abci.ResponseInitChain{} + }) + } + + prepareOpt := func(bapp *baseapp.BaseApp) { + bapp.SetPrepareProposal(func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + value := ctx.KVStore(capKey1).Get(someKey) + // We should be able to access any state written in InitChain + require.Equal(t, "foo", string(value)) + return abci.ResponsePrepareProposal{Txs: req.Txs} + }) + } + + suite := NewBaseAppSuite(t, setInitChainerOpt, prepareOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + reqPrepareProposal := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, // this value can't be 0 + } + resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) + require.Equal(t, 0, len(resPrepareProposal.Txs)) + + reqProposalTxBytes := [][]byte{} + reqProcessProposal := abci.RequestProcessProposal{ + Txs: reqProposalTxBytes, + } + + resProcessProposal := suite.baseApp.ProcessProposal(reqProcessProposal) + require.Equal(t, abci.ResponseProcessProposal_ACCEPT, resProcessProposal.Status) + + suite.baseApp.BeginBlock(abci.RequestBeginBlock{ + Header: tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1}, + }) } -var ParamstoreKey = []byte("paramstore") +func TestABCI_PrepareProposal_ReachedMaxBytes(t *testing.T) { + anteKey := []byte("ante-key") + pool := mempool.NewSenderNonceMempool() + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } + suite := NewBaseAppSuite(t, anteOpt, baseapp.SetMempool(pool)) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) -func (ps *paramStore) Set(_ sdk.Context, value *tmproto.ConsensusParams) { - bz, err := json.Marshal(value) - if err != nil { - panic(err) + for i := 0; i < 100; i++ { + tx2 := newTxCounter(t, suite.txConfig, int64(i), int64(i)) + err := pool.Insert(sdk.Context{}, tx2) + require.NoError(t, err) } - ps.db.Set(ParamstoreKey, bz) + reqPrepareProposal := abci.RequestPrepareProposal{ + MaxTxBytes: 1500, + Height: 1, + } + resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) + require.Equal(t, 10, len(resPrepareProposal.Txs)) } -func (ps *paramStore) Has(_ sdk.Context) bool { - ok, err := ps.db.Has(ParamstoreKey) - if err != nil { - panic(err) +func TestABCI_PrepareProposal_BadEncoding(t *testing.T) { + anteKey := []byte("ante-key") + pool := mempool.NewSenderNonceMempool() + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } + suite := NewBaseAppSuite(t, anteOpt, baseapp.SetMempool(pool)) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + tx := newTxCounter(t, suite.txConfig, 0, 0) + err := pool.Insert(sdk.Context{}, tx) + require.NoError(t, err) + + reqPrepareProposal := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, + } + resPrepareProposal := suite.baseApp.PrepareProposal(reqPrepareProposal) + require.Equal(t, 1, len(resPrepareProposal.Txs)) +} + +func TestABCI_PrepareProposal_Failures(t *testing.T) { + anteKey := []byte("ante-key") + pool := mempool.NewSenderNonceMempool() + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } + suite := NewBaseAppSuite(t, anteOpt, baseapp.SetMempool(pool)) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + tx := newTxCounter(t, suite.txConfig, 0, 0) + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + reqCheckTx := abci.RequestCheckTx{ + Tx: txBytes, + Type: abci.CheckTxType_New, } + checkTxRes := suite.baseApp.CheckTx(reqCheckTx) + require.True(t, checkTxRes.IsOK()) + + failTx := newTxCounter(t, suite.txConfig, 1, 1) + failTx = setFailOnAnte(t, suite.txConfig, failTx, true) + + err = pool.Insert(sdk.Context{}, failTx) + require.NoError(t, err) + require.Equal(t, 2, pool.CountTx()) - return ok + req := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, + } + res := suite.baseApp.PrepareProposal(req) + require.Equal(t, 1, len(res.Txs)) } -func (ps paramStore) Get(_ sdk.Context) (*tmproto.ConsensusParams, error) { - bz, err := ps.db.Get(ParamstoreKey) - if err != nil { - return nil, err +func TestABCI_PrepareProposal_PanicRecovery(t *testing.T) { + prepareOpt := func(app *baseapp.BaseApp) { + app.SetPrepareProposal(func(ctx sdk.Context, rpp abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + panic(errors.New("test")) + }) } + suite := NewBaseAppSuite(t, prepareOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) - if len(bz) == 0 { - return nil, errors.New("no consensus params") + req := abci.RequestPrepareProposal{ + MaxTxBytes: 1000, + Height: 1, } - var params tmproto.ConsensusParams + require.NotPanics(t, func() { + res := suite.baseApp.PrepareProposal(req) + require.Equal(t, req.Txs, res.Txs) + }) +} - if err := json.Unmarshal(bz, ¶ms); err != nil { - panic(err) +func TestABCI_ProcessProposal_PanicRecovery(t *testing.T) { + processOpt := func(app *baseapp.BaseApp) { + app.SetProcessProposal(func(ctx sdk.Context, rpp abci.RequestProcessProposal) abci.ResponseProcessProposal { + panic(errors.New("test")) + }) } + suite := NewBaseAppSuite(t, processOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) - return ¶ms, nil + require.NotPanics(t, func() { + res := suite.baseApp.ProcessProposal(abci.RequestProcessProposal{}) + require.Equal(t, res.Status, abci.ResponseProcessProposal_REJECT) + }) } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 2f227f8b4bde..d8a6feef91e3 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -6,18 +6,18 @@ import ( "sort" "strings" + dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/gogoproto/proto" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/crypto/tmhash" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" "golang.org/x/exp/maps" codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/snapshots" "github.com/cosmos/cosmos-sdk/store" - "github.com/cosmos/cosmos-sdk/store/rootmulti" + storemetrics "github.com/cosmos/cosmos-sdk/store/metrics" + "github.com/cosmos/cosmos-sdk/store/snapshots" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -43,20 +43,20 @@ type ( // from disk. This is useful for state migration, when loading a datastore written with // an older version of the software. In particular, if a module changed the substore key name // (or removed a substore) between two versions of the software. - StoreLoader func(ms sdk.CommitMultiStore) error + StoreLoader func(ms storetypes.CommitMultiStore) error ) // BaseApp reflects the ABCI application implementation. type BaseApp struct { //nolint: maligned // initialized on creation logger log.Logger - name string // application name from abci.Info - db dbm.DB // common DB backend - cms sdk.CommitMultiStore // Main (uncached) state - qms sdk.MultiStore // Optional alternative multistore for querying only. - storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader() - grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls - msgServiceRouter *MsgServiceRouter // router for redirecting Msg service messages + name string // application name from abci.Info + db dbm.DB // common DB backend + cms storetypes.CommitMultiStore // Main (uncached) state + qms storetypes.MultiStore // Optional alternative multistore for querying only. + storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader() + grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls + msgServiceRouter *MsgServiceRouter // router for redirecting Msg service messages interfaceRegistry codectypes.InterfaceRegistry txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx txEncoder sdk.TxEncoder // marshal sdk.Tx into []byte @@ -86,7 +86,7 @@ type BaseApp struct { //nolint: maligned prepareProposalState *state // for PrepareProposal // an inter-block write-through cache provided to the context during deliverState - interBlockCache sdk.MultiStorePersistentCache + interBlockCache storetypes.MultiStorePersistentCache // absent validators from begin block voteInfos []abci.VoteInfo @@ -142,7 +142,7 @@ type BaseApp struct { //nolint: maligned // abciListeners for hooking into the ABCI message processing of the BaseApp // and exposing the requests and responses to external consumers - abciListeners []ABCIListener + abciListeners []storetypes.ABCIListener } // NewBaseApp returns a reference to an initialized BaseApp. It accepts a @@ -157,7 +157,7 @@ func NewBaseApp( logger: logger, name: name, db: db, - cms: store.NewCommitMultiStore(db), + cms: store.NewCommitMultiStore(db, logger, storemetrics.NewNoOpMetrics()), // by default we use a no-op metric gather in store storeLoader: DefaultStoreLoader, grpcQueryRouter: NewGRPCQueryRouter(), msgServiceRouter: NewMsgServiceRouter(), @@ -170,7 +170,7 @@ func NewBaseApp( } if app.mempool == nil { - app.SetMempool(mempool.NewSenderNonceMempool()) + app.SetMempool(mempool.NoOpMempool{}) } if app.processProposal == nil { @@ -300,14 +300,14 @@ func (app *BaseApp) LoadLatestVersion() error { } // DefaultStoreLoader will be used by default and loads the latest version -func DefaultStoreLoader(ms sdk.CommitMultiStore) error { +func DefaultStoreLoader(ms storetypes.CommitMultiStore) error { return ms.LoadLatestVersion() } // CommitMultiStore returns the root multi-store. // App constructor can use this to access the `cms`. // UNSAFE: must not be used during the abci life cycle. -func (app *BaseApp) CommitMultiStore() sdk.CommitMultiStore { +func (app *BaseApp) CommitMultiStore() storetypes.CommitMultiStore { return app.cms } @@ -351,18 +351,18 @@ func (app *BaseApp) Init() error { emptyHeader := tmproto.Header{} // needed for the export command which inits from store but never calls initchain - app.setCheckState(emptyHeader) + app.setState(runTxModeCheck, emptyHeader) // needed for ABCI Replay Blocks mode which calls Prepare/Process proposal (InitChain is not called) - app.setPrepareProposalState(emptyHeader) - app.setProcessProposalState(emptyHeader) + app.setState(runTxPrepareProposal, emptyHeader) + app.setState(runTxProcessProposal, emptyHeader) app.Seal() - rms, ok := app.cms.(*rootmulti.Store) - if !ok { - return fmt.Errorf("invalid commit multi-store; expected %T, got: %T", &rootmulti.Store{}, app.cms) + if app.cms == nil { + return errors.New("commit multi-store must not be nil") } - return rms.GetPruning().Validate() + + return app.cms.GetPruning().Validate() } func (app *BaseApp) setMinGasPrices(gasPrices sdk.DecCoins) { @@ -381,7 +381,7 @@ func (app *BaseApp) setMinRetainBlocks(minRetainBlocks uint64) { app.minRetainBlocks = minRetainBlocks } -func (app *BaseApp) setInterBlockCache(cache sdk.MultiStorePersistentCache) { +func (app *BaseApp) setInterBlockCache(cache storetypes.MultiStorePersistentCache) { app.interBlockCache = cache } @@ -403,49 +403,32 @@ func (app *BaseApp) Seal() { app.sealed = true } // IsSealed returns true if the BaseApp is sealed and false otherwise. func (app *BaseApp) IsSealed() bool { return app.sealed } -// setCheckState sets the BaseApp's checkState with a branched multi-store -// (i.e. a CacheMultiStore) and a new Context with the same multi-store branch, -// provided header, and minimum gas prices set. It is set on InitChain and reset -// on Commit. -func (app *BaseApp) setCheckState(header tmproto.Header) { - ms := app.cms.CacheMultiStore() - app.checkState = &state{ - ms: ms, - ctx: sdk.NewContext(ms, header, true, app.logger).WithMinGasPrices(app.minGasPrices), - } -} - -// setDeliverState sets the BaseApp's deliverState with a branched multi-store -// (i.e. a CacheMultiStore) and a new Context with the same multi-store branch, -// and provided header. It is set on InitChain and BeginBlock and set to nil on -// Commit. -func (app *BaseApp) setDeliverState(header tmproto.Header) { +// setState sets the BaseApp's state for the corresponding mode with a branched +// multi-store (i.e. a CacheMultiStore) and a new Context with the same +// multi-store branch, and provided header. +func (app *BaseApp) setState(mode runTxMode, header tmproto.Header) { ms := app.cms.CacheMultiStore() - app.deliverState = &state{ + baseState := &state{ ms: ms, ctx: sdk.NewContext(ms, header, false, app.logger), } -} -// setPrepareProposalState sets the BaseApp's prepareProposalState with a -// branched multi-store (i.e. a CacheMultiStore) and a new Context with the -// same multi-store branch, and provided header. It is set on InitChain and Commit. -func (app *BaseApp) setPrepareProposalState(header tmproto.Header) { - ms := app.cms.CacheMultiStore() - app.prepareProposalState = &state{ - ms: ms, - ctx: sdk.NewContext(ms, header, false, app.logger), - } -} - -// setProcessProposalState sets the BaseApp's processProposalState with a -// branched multi-store (i.e. a CacheMultiStore) and a new Context with the -// same multi-store branch, and provided header. It is set on InitChain and Commit. -func (app *BaseApp) setProcessProposalState(header tmproto.Header) { - ms := app.cms.CacheMultiStore() - app.processProposalState = &state{ - ms: ms, - ctx: sdk.NewContext(ms, header, false, app.logger), + switch mode { + case runTxModeCheck: + // Minimum gas prices are also set. It is set on InitChain and reset on Commit. + baseState.ctx = baseState.ctx.WithIsCheckTx(true).WithMinGasPrices(app.minGasPrices) + app.checkState = baseState + case runTxModeDeliver: + // It is set on InitChain and BeginBlock and set to nil on Commit. + app.deliverState = baseState + case runTxPrepareProposal: + // It is set on InitChain and Commit. + app.prepareProposalState = baseState + case runTxProcessProposal: + // It is set on InitChain and Commit. + app.processProposalState = baseState + default: + panic(fmt.Sprintf("invalid runTxMode for setState: %d", mode)) } } @@ -486,10 +469,10 @@ func (app *BaseApp) AddRunTxRecoveryHandler(handlers ...RecoveryHandler) { } } -// getMaximumBlockGas gets the maximum gas from the consensus params. It panics +// GetMaximumBlockGas gets the maximum gas from the consensus params. It panics // if maximum block gas is less than negative one and returns zero if negative // one. -func (app *BaseApp) getMaximumBlockGas(ctx sdk.Context) uint64 { +func (app *BaseApp) GetMaximumBlockGas(ctx sdk.Context) uint64 { cp := app.GetConsensusParams(ctx) if cp == nil || cp.Block == nil { return 0 @@ -553,7 +536,8 @@ func validateBasicTxMsgs(msgs []sdk.Msg) error { } // Returns the application's deliverState if app is in runTxModeDeliver, -// otherwise it returns the application's checkstate. +// prepareProposalState if app is in runTxPrepareProposal, processProposalState +// if app is in runTxProcessProposal, and checkState otherwise. func (app *BaseApp) getState(mode runTxMode) *state { switch mode { case runTxModeDeliver: @@ -592,18 +576,18 @@ func (app *BaseApp) getContextForTx(mode runTxMode, txBytes []byte) sdk.Context // cacheTxContext returns a new context based off of the provided context with // a branched multi-store. -func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, sdk.CacheMultiStore) { +func (app *BaseApp) cacheTxContext(ctx sdk.Context, txBytes []byte) (sdk.Context, storetypes.CacheMultiStore) { ms := ctx.MultiStore() // TODO: https://github.com/cosmos/cosmos-sdk/issues/2824 msCache := ms.CacheMultiStore() if msCache.TracingEnabled() { msCache = msCache.SetTracingContext( - sdk.TraceContext( + storetypes.TraceContext( map[string]interface{}{ "txHash": fmt.Sprintf("%X", tmhash.Sum(txBytes)), }, ), - ).(sdk.CacheMultiStore) + ).(storetypes.CacheMultiStore) } return ctx.WithMultiStore(msCache), msCache @@ -673,7 +657,7 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re if app.anteHandler != nil { var ( anteCtx sdk.Context - msCache sdk.CacheMultiStore + msCache storetypes.CacheMultiStore ) // Branch context before AnteHandler call in case it aborts. @@ -739,9 +723,14 @@ func (app *BaseApp) runTx(mode runTxMode, txBytes []byte) (gInfo sdk.GasInfo, re // // Note: If the postHandler fails, we also revert the runMsgs state. if app.postHandler != nil { - newCtx, err := app.postHandler(runMsgCtx, tx, mode == runTxModeSimulate) + // The runMsgCtx context currently contains events emitted by the ante handler. + // We clear this to correctly order events without duplicates. + // Note that the state is still preserved. + postCtx := runMsgCtx.WithEventManager(sdk.NewEventManager()) + + newCtx, err := app.postHandler(postCtx, tx, mode == runTxModeSimulate) if err != nil { - return gInfo, nil, nil, priority, err + return gInfo, nil, anteEvents, priority, err } result.Events = append(result.Events, newCtx.EventManager().ABCIEvents()...) @@ -792,7 +781,7 @@ func (app *BaseApp) runMsgs(ctx sdk.Context, msgs []sdk.Msg, mode runTxMode) (*s } // create message events - msgEvents := createEvents(msg).AppendEvents(msgResult.GetEvents()) + msgEvents := createEvents(msgResult.GetEvents(), msg) // append message events, data and logs // @@ -834,7 +823,7 @@ func makeABCIData(msgResponses []*codectypes.Any) ([]byte, error) { return proto.Marshal(&sdk.TxMsgData{MsgResponses: msgResponses}) } -func createEvents(msg sdk.Msg) sdk.Events { +func createEvents(events sdk.Events, msg sdk.Msg) sdk.Events { eventMsgName := sdk.MsgTypeURL(msg) msgEvent := sdk.NewEvent(sdk.EventTypeMessage, sdk.NewAttribute(sdk.AttributeKeyAction, eventMsgName)) @@ -843,28 +832,48 @@ func createEvents(msg sdk.Msg) sdk.Events { msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeySender, msg.GetSigners()[0].String())) } - // here we assume that routes module name is the second element of the route - // e.g. "cosmos.bank.v1beta1.MsgSend" => "bank" - moduleName := strings.Split(eventMsgName, ".") - if len(moduleName) > 1 { - msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeyModule, moduleName[1])) + // verify that events have no module attribute set + if _, found := events.GetAttributes(sdk.AttributeKeyModule); !found { + // here we assume that routes module name is the second element of the route + // e.g. "cosmos.bank.v1beta1.MsgSend" => "bank" + moduleName := strings.Split(eventMsgName, ".") + if len(moduleName) > 1 { + msgEvent = msgEvent.AppendAttributes(sdk.NewAttribute(sdk.AttributeKeyModule, moduleName[1])) + } } - return sdk.Events{msgEvent} + return sdk.Events{msgEvent}.AppendEvents(events) } -// DefaultPrepareProposal returns the default implementation for processing an ABCI proposal. The application's -// mempool is enumerated and all valid transactions are added to the proposal. Transactions are valid if they: +// DefaultPrepareProposal returns the default implementation for processing an +// ABCI proposal. The application's mempool is enumerated and all valid +// transactions are added to the proposal. Transactions are valid if they: // // 1) Successfully encode to bytes. -// 2) Are valid (i.e. pass runTx, AnteHandler only) +// 2) Are valid (i.e. pass runTx, AnteHandler only). +// +// Enumeration is halted once RequestPrepareProposal.MaxBytes of transactions is +// reached or the mempool is exhausted. // -// Enumeration is halted once RequestPrepareProposal.MaxBytes of transactions is reached or the mempool is exhausted. -// Note that step (2) is identical to the validation step performed in DefaultProcessProposal. It is very important -// that the same validation logic is used in both steps, and applications must ensure that this is the case in +// Note: +// +// - Step (2) is identical to the validation step performed in +// DefaultProcessProposal. It is very important that the same validation logic +// is used in both steps, and applications must ensure that this is the case in // non-default handlers. +// +// - If no mempool is set or if the mempool is a no-op mempool, the transactions +// requested from Tendermint will simply be returned, which, by default, are in +// FIFO order. func (app *BaseApp) DefaultPrepareProposal() sdk.PrepareProposalHandler { return func(ctx sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + // If the mempool is nil or a no-op mempool, we simply return the transactions + // requested from Tendermint, which, by default, should be in FIFO order. + _, isNoOp := app.mempool.(mempool.NoOpMempool) + if app.mempool == nil || isNoOp { + return abci.ResponsePrepareProposal{Txs: req.Txs} + } + var ( txsBytes [][]byte byteCount int64 @@ -881,14 +890,16 @@ func (app *BaseApp) DefaultPrepareProposal() sdk.PrepareProposalHandler { txSize := int64(len(bz)) - // NOTE: runTx was already run in CheckTx which calls mempool.Insert so ideally everything in the pool - // should be valid. But some mempool implementations may insert invalid txs, so we check again. + // NOTE: Since runTx was already executed in CheckTx, which calls + // mempool.Insert, ideally everything in the pool should be valid. But + // some mempool implementations may insert invalid txs, so we check again. _, _, _, _, err = app.runTx(runTxPrepareProposal, bz) if err != nil { err := app.mempool.Remove(memTx) if err != nil && !errors.Is(err, mempool.ErrTxNotFound) { panic(err) } + iterator = iterator.Next() continue } else if byteCount += txSize; byteCount <= req.MaxTxBytes { @@ -899,6 +910,7 @@ func (app *BaseApp) DefaultPrepareProposal() sdk.PrepareProposalHandler { iterator = iterator.Next() } + return abci.ResponsePrepareProposal{Txs: txsBytes} } } @@ -928,3 +940,19 @@ func (app *BaseApp) DefaultProcessProposal() sdk.ProcessProposalHandler { return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} } } + +// NoOpPrepareProposal defines a no-op PrepareProposal handler. It will always +// return the transactions sent by the client's request. +func NoOpPrepareProposal() sdk.PrepareProposalHandler { + return func(_ sdk.Context, req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + return abci.ResponsePrepareProposal{Txs: req.Txs} + } +} + +// NoOpProcessProposal defines a no-op ProcessProposal Handler. It will always +// return ACCEPT. +func NoOpProcessProposal() sdk.ProcessProposalHandler { + return func(_ sdk.Context, _ abci.RequestProcessProposal) abci.ResponseProcessProposal { + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} + } +} diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index 42579f79c06d..9e93a81422ef 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -1,58 +1,619 @@ -package baseapp +package baseapp_test import ( + "fmt" + "math/rand" "testing" + "time" + dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" + "github.com/cosmos/cosmos-sdk/baseapp" + baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store/metrics" pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types" + "github.com/cosmos/cosmos-sdk/store/rootmulti" + "github.com/cosmos/cosmos-sdk/store/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/store/snapshots/types" storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" ) var ( - capKey1 = sdk.NewKVStoreKey("key1") - capKey2 = sdk.NewKVStoreKey("key2") + capKey1 = storetypes.NewKVStoreKey("key1") + capKey2 = storetypes.NewKVStoreKey("key2") + + // testTxPriority is the CheckTx priority that we set in the test + // AnteHandler. + testTxPriority = int64(42) +) + +type ( + BaseAppSuite struct { + baseApp *baseapp.BaseApp + cdc *codec.ProtoCodec + txConfig client.TxConfig + } + + SnapshotsConfig struct { + blocks uint64 + blockTxs int + snapshotInterval uint64 + snapshotKeepRecent uint32 + pruningOpts pruningtypes.PruningOptions + } ) +func NewBaseAppSuite(t *testing.T, opts ...func(*baseapp.BaseApp)) *BaseAppSuite { + cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) + + txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) + logger := defaultLogger() + db := dbm.NewMemDB() + + app := baseapp.NewBaseApp(t.Name(), logger, db, txConfig.TxDecoder(), opts...) + require.Equal(t, t.Name(), app.Name()) + + app.SetInterfaceRegistry(cdc.InterfaceRegistry()) + app.MsgServiceRouter().SetInterfaceRegistry(cdc.InterfaceRegistry()) + app.MountStores(capKey1, capKey2) + app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) + app.SetTxDecoder(txConfig.TxDecoder()) + app.SetTxEncoder(txConfig.TxEncoder()) + + // mount stores and seal + require.Nil(t, app.LoadLatestVersion()) + + return &BaseAppSuite{ + baseApp: app, + cdc: cdc, + txConfig: txConfig, + } +} + +func NewBaseAppSuiteWithSnapshots(t *testing.T, cfg SnapshotsConfig, opts ...func(*baseapp.BaseApp)) *BaseAppSuite { + snapshotTimeout := 1 * time.Minute + snapshotStore, err := snapshots.NewStore(dbm.NewMemDB(), testutil.GetTempDir(t)) + require.NoError(t, err) + + suite := NewBaseAppSuite( + t, + append( + opts, + baseapp.SetSnapshot(snapshotStore, snapshottypes.NewSnapshotOptions(cfg.snapshotInterval, cfg.snapshotKeepRecent)), + baseapp.SetPruning(cfg.pruningOpts), + )..., + ) + + baseapptestutil.RegisterKeyValueServer(suite.baseApp.MsgServiceRouter(), MsgKeyValueImpl{}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + r := rand.New(rand.NewSource(3920758213583)) + keyCounter := 0 + + for height := int64(1); height <= int64(cfg.blocks); height++ { + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: height}}) + + for txNum := 0; txNum < cfg.blockTxs; txNum++ { + msgs := []sdk.Msg{} + for msgNum := 0; msgNum < 100; msgNum++ { + key := []byte(fmt.Sprintf("%v", keyCounter)) + value := make([]byte, 10000) + + _, err := r.Read(value) + require.NoError(t, err) + + msgs = append(msgs, &baseapptestutil.MsgKeyValue{Key: key, Value: value}) + keyCounter++ + } + + builder := suite.txConfig.NewTxBuilder() + builder.SetMsgs(msgs...) + setTxSignature(t, builder, 0) + + txBytes, err := suite.txConfig.TxEncoder()(builder.GetTx()) + require.NoError(t, err) + + resp := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.True(t, resp.IsOK(), "%v", resp.String()) + } + + suite.baseApp.EndBlock(abci.RequestEndBlock{Height: height}) + suite.baseApp.Commit() + + // wait for snapshot to be taken, since it happens asynchronously + if cfg.snapshotInterval > 0 && uint64(height)%cfg.snapshotInterval == 0 { + start := time.Now() + for { + if time.Since(start) > snapshotTimeout { + t.Errorf("timed out waiting for snapshot after %v", snapshotTimeout) + } + + snapshot, err := snapshotStore.Get(uint64(height), snapshottypes.CurrentFormat) + require.NoError(t, err) + + if snapshot != nil { + break + } + + time.Sleep(100 * time.Millisecond) + } + } + } + + return suite +} + +func TestLoadVersion(t *testing.T) { + logger := defaultLogger() + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + + // make a cap key and mount the store + err := app.LoadLatestVersion() // needed to make stores non-nil + require.Nil(t, err) + + emptyCommitID := storetypes.CommitID{} + + // fresh store has zero/empty last commit + lastHeight := app.LastBlockHeight() + lastID := app.LastCommitID() + require.Equal(t, int64(0), lastHeight) + require.Equal(t, emptyCommitID, lastID) + + // execute a block, collect commit ID + header := tmproto.Header{Height: 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res := app.Commit() + commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} + + // execute a block, collect commit ID + header = tmproto.Header{Height: 2} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res = app.Commit() + commitID2 := storetypes.CommitID{Version: 2, Hash: res.Data} + + // reload with LoadLatestVersion + app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + app.MountStores() + + err = app.LoadLatestVersion() + require.Nil(t, err) + + testLoadVersionHelper(t, app, int64(2), commitID2) + + // Reload with LoadVersion, see if you can commit the same block and get + // the same result. + app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + err = app.LoadVersion(1) + require.Nil(t, err) + + testLoadVersionHelper(t, app, int64(1), commitID1) + + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + app.Commit() + + testLoadVersionHelper(t, app, int64(2), commitID2) +} + +func TestSetLoader(t *testing.T) { + useDefaultLoader := func(app *baseapp.BaseApp) { + app.SetStoreLoader(baseapp.DefaultStoreLoader) + } + + initStore := func(t *testing.T, db dbm.DB, storeKey string, k, v []byte) { + rs := rootmulti.NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) + + key := storetypes.NewKVStoreKey(storeKey) + rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) + + err := rs.LoadLatestVersion() + require.Nil(t, err) + require.Equal(t, int64(0), rs.LastCommitID().Version) + + // write some data in substore + kv, _ := rs.GetStore(key).(storetypes.KVStore) + require.NotNil(t, kv) + kv.Set(k, v) + + commitID := rs.Commit() + require.Equal(t, int64(1), commitID.Version) + } + + checkStore := func(t *testing.T, db dbm.DB, ver int64, storeKey string, k, v []byte) { + rs := rootmulti.NewStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + rs.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)) + + key := storetypes.NewKVStoreKey(storeKey) + rs.MountStoreWithDB(key, storetypes.StoreTypeIAVL, nil) + + err := rs.LoadLatestVersion() + require.Nil(t, err) + require.Equal(t, ver, rs.LastCommitID().Version) + + // query data in substore + kv, _ := rs.GetStore(key).(storetypes.KVStore) + require.NotNil(t, kv) + require.Equal(t, v, kv.Get(k)) + } + + testCases := map[string]struct { + setLoader func(*baseapp.BaseApp) + origStoreKey string + loadStoreKey string + }{ + "don't set loader": { + origStoreKey: "foo", + loadStoreKey: "foo", + }, + "default loader": { + setLoader: useDefaultLoader, + origStoreKey: "foo", + loadStoreKey: "foo", + }, + } + + k := []byte("key") + v := []byte("value") + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + // prepare a db with some data + db := dbm.NewMemDB() + initStore(t, db, tc.origStoreKey, k, v) + + // load the app with the existing db + opts := []func(*baseapp.BaseApp){baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing))} + if tc.setLoader != nil { + opts = append(opts, tc.setLoader) + } + app := baseapp.NewBaseApp(t.Name(), defaultLogger(), db, nil, opts...) + app.MountStores(storetypes.NewKVStoreKey(tc.loadStoreKey)) + err := app.LoadLatestVersion() + require.Nil(t, err) + + // "execute" one block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) + res := app.Commit() + require.NotNil(t, res.Data) + + // check db is properly updated + checkStore(t, db, 2, tc.loadStoreKey, k, v) + checkStore(t, db, 2, tc.loadStoreKey, []byte("foo"), nil) + }) + } +} + +func TestVersionSetterGetter(t *testing.T) { + logger := defaultLogger() + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningDefault)) + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + + require.Equal(t, "", app.Version()) + res := app.Query(abci.RequestQuery{Path: "app/version"}) + require.True(t, res.IsOK()) + require.Equal(t, "", string(res.Value)) + + versionString := "1.0.0" + app.SetVersion(versionString) + require.Equal(t, versionString, app.Version()) + + res = app.Query(abci.RequestQuery{Path: "app/version"}) + require.True(t, res.IsOK()) + require.Equal(t, versionString, string(res.Value)) +} + +func TestLoadVersionInvalid(t *testing.T) { + logger := log.NewNopLogger() + pruningOpt := baseapp.SetPruning(pruningtypes.NewPruningOptions(pruningtypes.PruningNothing)) + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + + err := app.LoadLatestVersion() + require.Nil(t, err) + + // require error when loading an invalid version + err = app.LoadVersion(-1) + require.Error(t, err) + + header := tmproto.Header{Height: 1} + app.BeginBlock(abci.RequestBeginBlock{Header: header}) + res := app.Commit() + commitID1 := storetypes.CommitID{Version: 1, Hash: res.Data} + + // create a new app with the stores mounted under the same cap key + app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) + + // require we can load the latest version + err = app.LoadVersion(1) + require.Nil(t, err) + testLoadVersionHelper(t, app, int64(1), commitID1) + + // require error when loading an invalid version + err = app.LoadVersion(2) + require.Error(t, err) +} + +func TestOptionFunction(t *testing.T) { + testChangeNameHelper := func(name string) func(*baseapp.BaseApp) { + return func(bap *baseapp.BaseApp) { + bap.SetName(name) + } + } + + logger := defaultLogger() + db := dbm.NewMemDB() + bap := baseapp.NewBaseApp("starting name", logger, db, nil, testChangeNameHelper("new name")) + require.Equal(t, bap.Name(), "new name", "BaseApp should have had name changed via option function") +} + +func TestBaseAppOptionSeal(t *testing.T) { + suite := NewBaseAppSuite(t) + + require.Panics(t, func() { + suite.baseApp.SetName("") + }) + require.Panics(t, func() { + suite.baseApp.SetVersion("") + }) + require.Panics(t, func() { + suite.baseApp.SetDB(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetCMS(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetInitChainer(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetBeginBlocker(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetEndBlocker(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetAnteHandler(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetAddrPeerFilter(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetIDPeerFilter(nil) + }) + require.Panics(t, func() { + suite.baseApp.SetFauxMerkleMode() + }) +} + +func TestTxDecoder(t *testing.T) { + cdc := codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + baseapptestutil.RegisterInterfaces(cdc.InterfaceRegistry()) + + // patch in TxConfig instead of using an output from x/auth/tx + txConfig := authtx.NewTxConfig(cdc, authtx.DefaultSignModes) + + tx := newTxCounter(t, txConfig, 1, 0) + txBytes, err := txConfig.TxEncoder()(tx) + require.NoError(t, err) + + dTx, err := txConfig.TxDecoder()(txBytes) + require.NoError(t, err) + + counter, _ := parseTxMemo(t, tx) + dTxCounter, _ := parseTxMemo(t, dTx) + require.Equal(t, counter, dTxCounter) +} + +func TestCustomRunTxPanicHandler(t *testing.T) { + customPanicMsg := "test panic" + anteErr := sdkerrors.Register("fakeModule", 100500, "fakeError") + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(func(ctx sdk.Context, tx sdk.Tx, simulate bool) (newCtx sdk.Context, err error) { + panic(sdkerrors.Wrap(anteErr, "anteHandler")) + }) + } + suite := NewBaseAppSuite(t, anteOpt) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + header := tmproto.Header{Height: 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + suite.baseApp.AddRunTxRecoveryHandler(func(recoveryObj interface{}) error { + err, ok := recoveryObj.(error) + if !ok { + return nil + } + + if anteErr.Is(err) { + panic(customPanicMsg) + } else { + return nil + } + }) + + // transaction should panic with custom handler above + { + tx := newTxCounter(t, suite.txConfig, 0, 0) + + require.PanicsWithValue(t, customPanicMsg, func() { + suite.baseApp.SimDeliver(suite.txConfig.TxEncoder(), tx) + }) + } +} + +func TestBaseAppAnteHandler(t *testing.T) { + anteKey := []byte("ante-key") + anteOpt := func(bapp *baseapp.BaseApp) { + bapp.SetAnteHandler(anteHandlerTxTest(t, capKey1, anteKey)) + } + suite := NewBaseAppSuite(t, anteOpt) + + deliverKey := []byte("deliver-key") + baseapptestutil.RegisterCounterServer(suite.baseApp.MsgServiceRouter(), CounterServerImpl{t, capKey1, deliverKey}) + + suite.baseApp.InitChain(abci.RequestInitChain{ + ConsensusParams: &tmproto.ConsensusParams{}, + }) + + header := tmproto.Header{Height: suite.baseApp.LastBlockHeight() + 1} + suite.baseApp.BeginBlock(abci.RequestBeginBlock{Header: header}) + + // execute a tx that will fail ante handler execution + // + // NOTE: State should not be mutated here. This will be implicitly checked by + // the next txs ante handler execution (anteHandlerTxTest). + tx := newTxCounter(t, suite.txConfig, 0, 0) + tx = setFailOnAnte(t, suite.txConfig, tx, true) + + txBytes, err := suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res := suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.Empty(t, res.Events) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx := getDeliverStateCtx(suite.baseApp) + store := ctx.KVStore(capKey1) + require.Equal(t, int64(0), getIntFromStore(t, store, anteKey)) + + // execute at tx that will pass the ante handler (the checkTx state should + // mutate) but will fail the message handler + tx = newTxCounter(t, suite.txConfig, 0, 0) + tx = setFailOnHandler(suite.txConfig, tx, true) + + txBytes, err = suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.NotEmpty(t, res.Events) + require.False(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx = getDeliverStateCtx(suite.baseApp) + store = ctx.KVStore(capKey1) + require.Equal(t, int64(1), getIntFromStore(t, store, anteKey)) + require.Equal(t, int64(0), getIntFromStore(t, store, deliverKey)) + + // Execute a successful ante handler and message execution where state is + // implicitly checked by previous tx executions. + tx = newTxCounter(t, suite.txConfig, 1, 0) + + txBytes, err = suite.txConfig.TxEncoder()(tx) + require.NoError(t, err) + + res = suite.baseApp.DeliverTx(abci.RequestDeliverTx{Tx: txBytes}) + require.NotEmpty(t, res.Events) + require.True(t, res.IsOK(), fmt.Sprintf("%v", res)) + + ctx = getDeliverStateCtx(suite.baseApp) + store = ctx.KVStore(capKey1) + require.Equal(t, int64(2), getIntFromStore(t, store, anteKey)) + require.Equal(t, int64(1), getIntFromStore(t, store, deliverKey)) + + suite.baseApp.EndBlock(abci.RequestEndBlock{}) + suite.baseApp.Commit() +} + +// Test and ensure that invalid block heights always cause errors. +// See issues: +// - https://github.com/cosmos/cosmos-sdk/issues/11220 +// - https://github.com/cosmos/cosmos-sdk/issues/7662 +func TestABCI_CreateQueryContext(t *testing.T) { + t.Parallel() + + logger := defaultLogger() + db := dbm.NewMemDB() + name := t.Name() + app := baseapp.NewBaseApp(name, logger, db, nil) + + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 1}}) + app.Commit() + + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: 2}}) + app.Commit() + + testCases := []struct { + name string + height int64 + prove bool + expErr bool + }{ + {"valid height", 2, true, false}, + {"future height", 10, true, true}, + {"negative height, prove=true", -1, true, true}, + {"negative height, prove=false", -1, false, true}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + _, err := app.CreateQueryContext(tc.height, tc.prove) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + func TestSetMinGasPrices(t *testing.T) { minGasPrices := sdk.DecCoins{sdk.NewInt64DecCoin("stake", 5000)} - app := setupBaseApp(t, SetMinGasPrices(minGasPrices.String())) - require.Equal(t, minGasPrices, app.minGasPrices) + suite := NewBaseAppSuite(t, baseapp.SetMinGasPrices(minGasPrices.String())) + + ctx := getCheckStateCtx(suite.baseApp) + require.Equal(t, minGasPrices, ctx.MinGasPrices()) } func TestGetMaximumBlockGas(t *testing.T) { - app := setupBaseApp(t) - app.InitChain(abci.RequestInitChain{}) - ctx := app.NewContext(true, tmproto.Header{}) + suite := NewBaseAppSuite(t) + suite.baseApp.InitChain(abci.RequestInitChain{}) + ctx := suite.baseApp.NewContext(true, tmproto.Header{}) - app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 0}}) - require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx)) + suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 0}}) + require.Equal(t, uint64(0), suite.baseApp.GetMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -1}}) - require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx)) + suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -1}}) + require.Equal(t, uint64(0), suite.baseApp.GetMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 5000000}}) - require.Equal(t, uint64(5000000), app.getMaximumBlockGas(ctx)) + suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 5000000}}) + require.Equal(t, uint64(5000000), suite.baseApp.GetMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -5000000}}) - require.Panics(t, func() { app.getMaximumBlockGas(ctx) }) + suite.baseApp.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -5000000}}) + require.Panics(t, func() { suite.baseApp.GetMaximumBlockGas(ctx) }) } func TestLoadVersionPruning(t *testing.T) { logger := log.NewNopLogger() pruningOptions := pruningtypes.NewCustomPruningOptions(10, 15) - pruningOpt := SetPruning(pruningOptions) + pruningOpt := baseapp.SetPruning(pruningOptions) db := dbm.NewMemDB() name := t.Name() - app := NewBaseApp(name, logger, db, nil, pruningOpt) + app := baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) // make a cap key and mount the store - capKey := sdk.NewKVStoreKey("key1") + capKey := storetypes.NewKVStoreKey("key1") app.MountStores(capKey) err := app.LoadLatestVersion() // needed to make stores non-nil @@ -77,43 +638,20 @@ func TestLoadVersionPruning(t *testing.T) { } for _, v := range []int64{1, 2, 4} { - _, err = app.cms.CacheMultiStoreWithVersion(v) + _, err = app.CommitMultiStore().CacheMultiStoreWithVersion(v) require.NoError(t, err) } for _, v := range []int64{3, 5, 6, 7} { - _, err = app.cms.CacheMultiStoreWithVersion(v) + _, err = app.CommitMultiStore().CacheMultiStoreWithVersion(v) require.NoError(t, err) } // reload with LoadLatestVersion, check it loads last version - app = NewBaseApp(name, logger, db, nil, pruningOpt) + app = baseapp.NewBaseApp(name, logger, db, nil, pruningOpt) app.MountStores(capKey) err = app.LoadLatestVersion() require.Nil(t, err) testLoadVersionHelper(t, app, int64(7), lastCommitID) } - -// simple one store baseapp -func setupBaseApp(t *testing.T, options ...func(*BaseApp)) *BaseApp { - logger := defaultLogger() - db := dbm.NewMemDB() - app := NewBaseApp(t.Name(), logger, db, nil, options...) - require.Equal(t, t.Name(), app.Name()) - - app.MountStores(capKey1, capKey2) - app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) - - // stores are mounted - err := app.LoadLatestVersion() - require.Nil(t, err) - return app -} - -func testLoadVersionHelper(t *testing.T, app *BaseApp, expectedHeight int64, expectedID storetypes.CommitID) { - lastHeight := app.LastBlockHeight() - lastID := app.LastCommitID() - require.Equal(t, expectedHeight, lastHeight) - require.Equal(t, expectedID, lastID) -} diff --git a/baseapp/block_gas_test.go b/baseapp/block_gas_test.go index 4f765e340fb1..c2bb2c9d85a4 100644 --- a/baseapp/block_gas_test.go +++ b/baseapp/block_gas_test.go @@ -5,12 +5,12 @@ import ( "math" "testing" + dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmjson "github.com/tendermint/tendermint/libs/json" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" "cosmossdk.io/depinject" @@ -22,6 +22,7 @@ import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/runtime" store "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil/configurator" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" @@ -80,9 +81,14 @@ func TestBaseApp_BlockGas(t *testing.T) { err error ) - appConfig := depinject.Configs(makeTestConfig()) - - err = depinject.Inject(appConfig, + err = depinject.Inject(configurator.NewAppConfig( + configurator.AuthModule(), + configurator.TxModule(), + configurator.ParamsModule(), + configurator.ConsensusModule(), + configurator.BankModule(), + configurator.StakingModule(), + ), &bankKeeper, &accountKeeper, &interfaceRegistry, @@ -214,7 +220,7 @@ func createTestTx(txConfig client.TxConfig, txBuilder client.TxBuilder, privs [] Sequence: accSeqs[i], } sigV2, err := tx.SignWithPrivKey( - txConfig.SignModeHandler().DefaultMode(), signerData, + nil, txConfig.SignModeHandler().DefaultMode(), signerData, //nolint:staticcheck txBuilder, priv, txConfig, accSeqs[i]) if err != nil { return nil, nil, err diff --git a/baseapp/grpcrouter.go b/baseapp/grpcrouter.go index d311f085c0e4..4ce3d63e9541 100644 --- a/baseapp/grpcrouter.go +++ b/baseapp/grpcrouter.go @@ -79,7 +79,7 @@ func (qrt *GRPCQueryRouter) RegisterService(sd *grpc.ServiceDesc, handler interf qrt.routes[fqName] = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error) { // call the method handler from the service description with the handler object, // a wrapped sdk.Context with proto-unmarshaled data from the ABCI request data - res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), func(i interface{}) error { + res, err := methodHandler(handler, ctx, func(i interface{}) error { return qrt.cdc.Unmarshal(req.Data, i) }, nil) if err != nil { diff --git a/baseapp/grpcrouter_test.go b/baseapp/grpcrouter_test.go index 7a672b10b54f..1bf1fce0763b 100644 --- a/baseapp/grpcrouter_test.go +++ b/baseapp/grpcrouter_test.go @@ -6,9 +6,9 @@ import ( "sync" "testing" + dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/libs/log" - dbm "github.com/tendermint/tm-db" "cosmossdk.io/depinject" "github.com/cosmos/cosmos-sdk/baseapp" diff --git a/baseapp/grpcserver.go b/baseapp/grpcserver.go index 9424a5e7e3ca..d04f71d1abce 100644 --- a/baseapp/grpcserver.go +++ b/baseapp/grpcserver.go @@ -47,7 +47,7 @@ func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { // Create the sdk.Context. Passing false as 2nd arg, as we can't // actually support proofs with gRPC right now. - sdkCtx, err := app.createQueryContext(height, false) + sdkCtx, err := app.CreateQueryContext(height, false) if err != nil { return nil, err } diff --git a/baseapp/msg_service_router.go b/baseapp/msg_service_router.go index 02192e892d8c..360bd8910512 100644 --- a/baseapp/msg_service_router.go +++ b/baseapp/msg_service_router.go @@ -118,7 +118,7 @@ func (msr *MsgServiceRouter) RegisterService(sd *grpc.ServiceDesc, handler inter } // Call the method handler from the service description with the handler object. // We don't do any decoding here because the decoding was already done. - res, err := methodHandler(handler, sdk.WrapSDKContext(ctx), noopDecoder, interceptor) + res, err := methodHandler(handler, ctx, noopDecoder, interceptor) if err != nil { return nil, err } diff --git a/baseapp/msg_service_router_test.go b/baseapp/msg_service_router_test.go index 06e5bc3e9c8c..d0c70957e8fb 100644 --- a/baseapp/msg_service_router_test.go +++ b/baseapp/msg_service_router_test.go @@ -4,11 +4,11 @@ import ( "os" "testing" + dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - dbm "github.com/tendermint/tm-db" "cosmossdk.io/depinject" "github.com/cosmos/cosmos-sdk/client/tx" @@ -131,7 +131,7 @@ func TestMsgService(t *testing.T) { Sequence: 0, } sigV2, err = tx.SignWithPrivKey( - txConfig.SignModeHandler().DefaultMode(), signerData, + nil, txConfig.SignModeHandler().DefaultMode(), signerData, //nolint:staticcheck // SA1019: txConfig.SignModeHandler().DefaultMode() is deprecated: use txConfig.SignModeHandler().DefaultMode() instead. txBuilder, priv, txConfig, 0) require.NoError(t, err) err = txBuilder.SetSignatures(sigV2) diff --git a/baseapp/options.go b/baseapp/options.go index b45a71985738..22d3aab19485 100644 --- a/baseapp/options.go +++ b/baseapp/options.go @@ -4,13 +4,15 @@ import ( "fmt" "io" - dbm "github.com/tendermint/tm-db" - + dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/snapshots" - snapshottypes "github.com/cosmos/cosmos-sdk/snapshots/types" - "github.com/cosmos/cosmos-sdk/store" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/store/metrics" pruningtypes "github.com/cosmos/cosmos-sdk/store/pruning/types" + "github.com/cosmos/cosmos-sdk/store/snapshots" + snapshottypes "github.com/cosmos/cosmos-sdk/store/snapshots/types" + "github.com/cosmos/cosmos-sdk/store/streaming" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" ) @@ -72,7 +74,7 @@ func SetIAVLDisableFastNode(disable bool) func(*BaseApp) { // SetInterBlockCache provides a BaseApp option function that sets the // inter-block cache. -func SetInterBlockCache(cache sdk.MultiStorePersistentCache) func(*BaseApp) { +func SetInterBlockCache(cache storetypes.MultiStorePersistentCache) func(*BaseApp) { return func(app *BaseApp) { app.setInterBlockCache(cache) } } @@ -124,7 +126,7 @@ func (app *BaseApp) SetDB(db dbm.DB) { app.db = db } -func (app *BaseApp) SetCMS(cms store.CommitMultiStore) { +func (app *BaseApp) SetCMS(cms storetypes.CommitMultiStore) { if app.sealed { panic("SetEndBlocker() on sealed BaseApp") } @@ -232,14 +234,25 @@ func (app *BaseApp) SetInterfaceRegistry(registry types.InterfaceRegistry) { } // SetStreamingService is used to set a streaming service into the BaseApp hooks and load the listeners into the multistore -func (app *BaseApp) SetStreamingService(s StreamingService) { +func (app *BaseApp) SetStreamingService( + appOpts servertypes.AppOptions, + appCodec storetypes.Codec, + keys map[string]*storetypes.KVStoreKey, +) error { + streamers, _, err := streaming.LoadStreamingServices(appOpts, appCodec, app.logger, keys) + if err != nil { + return err + } // add the listeners for each StoreKey - for key, lis := range s.Listeners() { - app.cms.AddListeners(key, lis) + for _, streamer := range streamers { + for key, lis := range streamer.Listeners() { + app.cms.AddListeners(key, lis) + } + // register the StreamingService within the BaseApp + // BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context + app.abciListeners = append(app.abciListeners, streamer) } - // register the StreamingService within the BaseApp - // BaseApp will pass BeginBlock, DeliverTx, and EndBlock requests and responses to the streaming services to update their ABCI context - app.abciListeners = append(app.abciListeners, s) + return nil } // SetTxDecoder sets the TxDecoder if it wasn't provided in the BaseApp constructor. @@ -255,7 +268,7 @@ func (app *BaseApp) SetTxEncoder(txEncoder sdk.TxEncoder) { // SetQueryMultiStore set a alternative MultiStore implementation to support grpc query service. // // Ref: https://github.com/cosmos/cosmos-sdk/issues/13317 -func (app *BaseApp) SetQueryMultiStore(ms sdk.MultiStore) { +func (app *BaseApp) SetQueryMultiStore(ms storetypes.MultiStore) { app.qms = ms } @@ -283,3 +296,12 @@ func (app *BaseApp) SetPrepareProposal(handler sdk.PrepareProposalHandler) { app.prepareProposal = handler } + +// SetStoreMetrics sets the prepare proposal function for the BaseApp. +func (app *BaseApp) SetStoreMetrics(gatherer metrics.StoreMetrics) { + if app.sealed { + panic("SetStoreMetrics() on sealed BaseApp") + } + + app.cms.SetMetrics(gatherer) +} diff --git a/baseapp/recovery.go b/baseapp/recovery.go index 7f0687800c65..00b4d25c9ba8 100644 --- a/baseapp/recovery.go +++ b/baseapp/recovery.go @@ -4,6 +4,7 @@ import ( "fmt" "runtime/debug" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) @@ -47,7 +48,7 @@ func newRecoveryMiddleware(handler RecoveryHandler, next recoveryMiddleware) rec // newOutOfGasRecoveryMiddleware creates a standard OutOfGas recovery middleware for app.runTx method. func newOutOfGasRecoveryMiddleware(gasWanted uint64, ctx sdk.Context, next recoveryMiddleware) recoveryMiddleware { handler := func(recoveryObj interface{}) error { - err, ok := recoveryObj.(sdk.ErrorOutOfGas) + err, ok := recoveryObj.(storetypes.ErrorOutOfGas) if !ok { return nil } diff --git a/baseapp/state.go b/baseapp/state.go index addc89cb342c..da9c588e40e4 100644 --- a/baseapp/state.go +++ b/baseapp/state.go @@ -1,17 +1,18 @@ package baseapp import ( + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type state struct { - ms sdk.CacheMultiStore + ms storetypes.CacheMultiStore ctx sdk.Context } // CacheMultiStore calls and returns a CacheMultiStore on the state's underling // CacheMultiStore. -func (st *state) CacheMultiStore() sdk.CacheMultiStore { +func (st *state) CacheMultiStore() storetypes.CacheMultiStore { return st.ms.CacheMultiStore() } diff --git a/baseapp/utils_test.go b/baseapp/utils_test.go new file mode 100644 index 000000000000..bdd45d35894a --- /dev/null +++ b/baseapp/utils_test.go @@ -0,0 +1,392 @@ +package baseapp_test + +import ( + "bytes" + "context" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "net/url" + "os" + "reflect" + "strconv" + "testing" + "unsafe" + + runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" + "cosmossdk.io/core/appconfig" + "cosmossdk.io/depinject" + dbm "github.com/cosmos/cosmos-db" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/baseapp" + baseapptestutil "github.com/cosmos/cosmos-sdk/baseapp/testutil" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/runtime" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/mempool" + signingtypes "github.com/cosmos/cosmos-sdk/types/tx/signing" + _ "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + _ "github.com/cosmos/cosmos-sdk/x/bank" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + _ "github.com/cosmos/cosmos-sdk/x/consensus" + _ "github.com/cosmos/cosmos-sdk/x/mint" + _ "github.com/cosmos/cosmos-sdk/x/params" + _ "github.com/cosmos/cosmos-sdk/x/staking" +) + +var ParamStoreKey = []byte("paramstore") + +func defaultLogger() log.Logger { + if testing.Verbose() { + return log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "baseapp/test") + } + + return log.NewNopLogger() +} + +// GenesisStateWithSingleValidator initializes GenesisState with a single validator and genesis accounts +// that also act as delegators. +func GenesisStateWithSingleValidator(t *testing.T, codec codec.Codec, builder *runtime.AppBuilder) map[string]json.RawMessage { + t.Helper() + + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + + // create validator set with single validator + validator := tmtypes.NewValidator(pubKey, 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balances := []banktypes.Balance{ + { + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))), + }, + } + + genesisState := builder.DefaultGenesis() + // sus + genesisState, err = simtestutil.GenesisStateWithValSet(codec, genesisState, valSet, []authtypes.GenesisAccount{acc}, balances...) + require.NoError(t, err) + + return genesisState +} + +func makeMinimalConfig() depinject.Config { + var mempoolOpt runtime.BaseAppOption = baseapp.SetMempool(mempool.NewSenderNonceMempool()) + return depinject.Configs( + depinject.Supply(mempoolOpt), + appconfig.Compose(&appv1alpha1.Config{ + Modules: []*appv1alpha1.ModuleConfig{ + { + Name: "runtime", + Config: appconfig.WrapAny(&runtimev1alpha1.Module{ + AppName: "BaseAppApp", + }), + }, + }, + })) +} + +type MsgKeyValueImpl struct{} + +func (m MsgKeyValueImpl) Set(ctx context.Context, msg *baseapptestutil.MsgKeyValue) (*baseapptestutil.MsgCreateKeyValueResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + sdkCtx.KVStore(capKey2).Set(msg.Key, msg.Value) + return &baseapptestutil.MsgCreateKeyValueResponse{}, nil +} + +type CounterServerImplGasMeterOnly struct { + gas uint64 +} + +func (m CounterServerImplGasMeterOnly) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter) (*baseapptestutil.MsgCreateCounterResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + gas := m.gas + + // if no gas is provided, use the counter as gas. This is useful for testing + if gas == 0 { + gas = uint64(msg.Counter) + } + + sdkCtx.GasMeter().ConsumeGas(gas, "test") + return &baseapptestutil.MsgCreateCounterResponse{}, nil +} + +type NoopCounterServerImpl struct{} + +func (m NoopCounterServerImpl) IncrementCounter( + _ context.Context, + _ *baseapptestutil.MsgCounter, +) (*baseapptestutil.MsgCreateCounterResponse, error) { + return &baseapptestutil.MsgCreateCounterResponse{}, nil +} + +type CounterServerImpl struct { + t *testing.T + capKey storetypes.StoreKey + deliverKey []byte +} + +func (m CounterServerImpl) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter) (*baseapptestutil.MsgCreateCounterResponse, error) { + return incrementCounter(ctx, m.t, m.capKey, m.deliverKey, msg) +} + +type Counter2ServerImpl struct { + t *testing.T + capKey storetypes.StoreKey + deliverKey []byte +} + +func (m Counter2ServerImpl) IncrementCounter(ctx context.Context, msg *baseapptestutil.MsgCounter2) (*baseapptestutil.MsgCreateCounterResponse, error) { + return incrementCounter(ctx, m.t, m.capKey, m.deliverKey, msg) +} + +func incrementCounter(ctx context.Context, + t *testing.T, + capKey storetypes.StoreKey, + deliverKey []byte, + msg sdk.Msg, +) (*baseapptestutil.MsgCreateCounterResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + store := sdkCtx.KVStore(capKey) + + sdkCtx.GasMeter().ConsumeGas(5, "test") + + var msgCount int64 + + switch m := msg.(type) { + case *baseapptestutil.MsgCounter: + if m.FailOnHandler { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure") + } + msgCount = m.Counter + case *baseapptestutil.MsgCounter2: + if m.FailOnHandler { + return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "message handler failure") + } + msgCount = m.Counter + } + + sdkCtx.EventManager().EmitEvents( + counterEvent(sdk.EventTypeMessage, msgCount), + ) + + _, err := incrementingCounter(t, store, deliverKey, msgCount) + if err != nil { + return nil, err + } + + return &baseapptestutil.MsgCreateCounterResponse{}, nil +} + +func counterEvent(evType string, msgCount int64) sdk.Events { + return sdk.Events{ + sdk.NewEvent( + evType, + sdk.NewAttribute("update_counter", fmt.Sprintf("%d", msgCount)), + ), + } +} + +func anteHandlerTxTest(t *testing.T, capKey storetypes.StoreKey, storeKey []byte) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) { + store := ctx.KVStore(capKey) + counter, failOnAnte := parseTxMemo(t, tx) + + if failOnAnte { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "ante handler failure") + } + + _, err := incrementingCounter(t, store, storeKey, counter) + if err != nil { + return ctx, err + } + + ctx.EventManager().EmitEvents( + counterEvent("ante_handler", counter), + ) + + ctx = ctx.WithPriority(testTxPriority) + return ctx, nil + } +} + +func incrementingCounter(t *testing.T, store storetypes.KVStore, counterKey []byte, counter int64) (*sdk.Result, error) { + storedCounter := getIntFromStore(t, store, counterKey) + require.Equal(t, storedCounter, counter) + setIntOnStore(store, counterKey, counter+1) + return &sdk.Result{}, nil +} + +func setIntOnStore(store storetypes.KVStore, key []byte, i int64) { + bz := make([]byte, 8) + n := binary.PutVarint(bz, i) + store.Set(key, bz[:n]) +} + +type paramStore struct { + db *dbm.MemDB +} + +func (ps *paramStore) Set(_ sdk.Context, value *tmproto.ConsensusParams) { + bz, err := json.Marshal(value) + if err != nil { + panic(err) + } + + ps.db.Set(ParamStoreKey, bz) +} + +func (ps *paramStore) Has(_ sdk.Context) bool { + ok, err := ps.db.Has(ParamStoreKey) + if err != nil { + panic(err) + } + + return ok +} + +func (ps paramStore) Get(ctx sdk.Context) (*tmproto.ConsensusParams, error) { + bz, err := ps.db.Get(ParamStoreKey) + if err != nil { + panic(err) + } + + if len(bz) == 0 { + return nil, errors.New("params not found") + } + + var params tmproto.ConsensusParams + if err := json.Unmarshal(bz, ¶ms); err != nil { + panic(err) + } + + return ¶ms, nil +} + +func setTxSignature(t *testing.T, builder client.TxBuilder, nonce uint64) { + privKey := secp256k1.GenPrivKeyFromSecret([]byte("test")) + pubKey := privKey.PubKey() + err := builder.SetSignatures( + signingtypes.SignatureV2{ + PubKey: pubKey, + Sequence: nonce, + Data: &signingtypes.SingleSignatureData{}, + }, + ) + require.NoError(t, err) +} + +func testLoadVersionHelper(t *testing.T, app *baseapp.BaseApp, expectedHeight int64, expectedID storetypes.CommitID) { + lastHeight := app.LastBlockHeight() + lastID := app.LastCommitID() + require.Equal(t, expectedHeight, lastHeight) + require.Equal(t, expectedID, lastID) +} + +func getCheckStateCtx(app *baseapp.BaseApp) sdk.Context { + v := reflect.ValueOf(app).Elem() + f := v.FieldByName("checkState") + rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem() + return rf.MethodByName("Context").Call(nil)[0].Interface().(sdk.Context) +} + +func getDeliverStateCtx(app *baseapp.BaseApp) sdk.Context { + v := reflect.ValueOf(app).Elem() + f := v.FieldByName("deliverState") + rf := reflect.NewAt(f.Type(), unsafe.Pointer(f.UnsafeAddr())).Elem() + return rf.MethodByName("Context").Call(nil)[0].Interface().(sdk.Context) +} + +func parseTxMemo(t *testing.T, tx sdk.Tx) (counter int64, failOnAnte bool) { + txWithMemo, ok := tx.(sdk.TxWithMemo) + require.True(t, ok) + + memo := txWithMemo.GetMemo() + vals, err := url.ParseQuery(memo) + require.NoError(t, err) + + counter, err = strconv.ParseInt(vals.Get("counter"), 10, 64) + require.NoError(t, err) + + failOnAnte = vals.Get("failOnAnte") == "true" + return counter, failOnAnte +} + +func newTxCounter(t *testing.T, cfg client.TxConfig, counter int64, msgCounters ...int64) signing.Tx { + msgs := make([]sdk.Msg, 0, len(msgCounters)) + for _, c := range msgCounters { + msg := &baseapptestutil.MsgCounter{Counter: c, FailOnHandler: false} + msgs = append(msgs, msg) + } + + builder := cfg.NewTxBuilder() + builder.SetMsgs(msgs...) + builder.SetMemo("counter=" + strconv.FormatInt(counter, 10) + "&failOnAnte=false") + setTxSignature(t, builder, uint64(counter)) + + return builder.GetTx() +} + +func getIntFromStore(t *testing.T, store storetypes.KVStore, key []byte) int64 { + bz := store.Get(key) + if len(bz) == 0 { + return 0 + } + + i, err := binary.ReadVarint(bytes.NewBuffer(bz)) + require.NoError(t, err) + + return i +} + +func setFailOnAnte(t *testing.T, cfg client.TxConfig, tx signing.Tx, failOnAnte bool) signing.Tx { + builder := cfg.NewTxBuilder() + builder.SetMsgs(tx.GetMsgs()...) + + memo := tx.GetMemo() + vals, err := url.ParseQuery(memo) + require.NoError(t, err) + + vals.Set("failOnAnte", strconv.FormatBool(failOnAnte)) + memo = vals.Encode() + builder.SetMemo(memo) + setTxSignature(t, builder, 1) + + return builder.GetTx() +} + +func setFailOnHandler(cfg client.TxConfig, tx signing.Tx, fail bool) signing.Tx { + builder := cfg.NewTxBuilder() + builder.SetMemo(tx.GetMemo()) + + msgs := tx.GetMsgs() + for i, msg := range msgs { + msgs[i] = &baseapptestutil.MsgCounter{ + Counter: msg.(*baseapptestutil.MsgCounter).Counter, + FailOnHandler: fail, + } + } + + builder.SetMsgs(msgs...) + return builder.GetTx() +} From d872851e7125e54e66686e346dc2be1dff5cac31 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Wed, 8 Mar 2023 10:33:28 -0500 Subject: [PATCH 24/24] update to DRAFT --- docs/architecture/adr-054-semver-compatible-modules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adr-054-semver-compatible-modules.md b/docs/architecture/adr-054-semver-compatible-modules.md index c7eb413e899d..be63e8dbde69 100644 --- a/docs/architecture/adr-054-semver-compatible-modules.md +++ b/docs/architecture/adr-054-semver-compatible-modules.md @@ -6,7 +6,7 @@ ## Status -PROPOSED +DRAFT ## Abstract @@ -430,7 +430,7 @@ Other downsides to this approach are: ## Decision -Based on discussions within the team, the current draft consensus is the following: +The latest **DRAFT** proposal is: 1. we are alignment on adopting [ADR 033](./adr-033-protobuf-inter-module-comm.md) not just as an addition to the framework, but as a core replacement to the keeper paradigm entirely.