feat: backport unordered transactions (#23708)

Co-authored-by: Aleksandr Bezobchuk <alexanderbez@users.noreply.github.com>
Co-authored-by: yihuang <huang@crypto.com>
Co-authored-by: Facundo <facundomedica@gmail.com>
Co-authored-by: Facundo Medica <14063057+facundomedica@users.noreply.github.com>
Co-authored-by: Alex | Interchain Labs <alex@interchainlabs.io>
This commit is contained in:
Tyler 2025-02-27 11:01:50 -08:00 committed by GitHub
parent ff779eca8d
commit 7f7c41e4aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
63 changed files with 3091 additions and 1295 deletions

View File

@ -40,6 +40,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* (all) [23708](https://github.com/cosmos/cosmos-sdk/pull/23708) Add unordered transaction support.
* Adds a `--timeout-timestamp` flag that allows users to specify a block time at which the unordered transactions should expire from the mempool.
* (x/epochs) [#23815](https://github.com/cosmos/cosmos-sdk/pull/23815) Upstream `x/epochs` from Osmosis
* (client) [#21074](https://github.com/cosmos/cosmos-sdk/pull/21074) Add auto cli for node service
@ -148,9 +150,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements
* (telemetry) [#19903](https://github.com/cosmos/cosmos-sdk/pull/19903) Conditionally emit metrics based on enablement.
* **Introduction of `Now` Function**: Added a new function called `Now` to the telemetry package. It returns the current system time if telemetry is enabled, or a zero time if telemetry is not enabled.
* **Atomic Global Variable**: Implemented an atomic global variable to manage the state of telemetry's enablement. This ensures thread safety for the telemetry state.
* **Conditional Telemetry Emission**: All telemetry functions have been updated to emit metrics only when telemetry is enabled. They perform a check with `isTelemetryEnabled()` and return early if telemetry is disabled, minimizing unnecessary operations and overhead.
* **Introduction of `Now` Function**: Added a new function called `Now` to the telemetry package. It returns the current system time if telemetry is enabled, or a zero time if telemetry is not enabled.
* **Atomic Global Variable**: Implemented an atomic global variable to manage the state of telemetry's enablement. This ensures thread safety for the telemetry state.
* **Conditional Telemetry Emission**: All telemetry functions have been updated to emit metrics only when telemetry is enabled. They perform a check with `isTelemetryEnabled()` and return early if telemetry is disabled, minimizing unnecessary operations and overhead.
* (deps) [#19810](https://github.com/cosmos/cosmos-sdk/pull/19810) Upgrade prometheus version and fix API breaking change due to prometheus bump.
* (deps) [#19810](https://github.com/cosmos/cosmos-sdk/pull/19810) Bump `cosmossdk.io/store` to v1.1.0.
* (server) [#19884](https://github.com/cosmos/cosmos-sdk/pull/19884) Add start customizability to start command options.
@ -312,10 +314,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (baseapp) [#17667](https://github.com/cosmos/cosmos-sdk/pull/17667) Close databases opened by SDK in `baseApp.Close()`.
* (types/module) [#17554](https://github.com/cosmos/cosmos-sdk/pull/17554) Introduce `HasABCIGenesis` which is implemented by a module only when a validatorset update needs to be returned.
* (cli) [#17389](https://github.com/cosmos/cosmos-sdk/pull/17389) gRPC CometBFT commands have been added under `<aapd> q consensus comet`. CometBFT commands placement in the SDK has been simplified. See the exhaustive list below.
* `client/rpc.StatusCommand()` is now at `server.StatusCommand()`
* `client/rpc.StatusCommand()` is now at `server.StatusCommand()`
* (testutil) [#17216](https://github.com/cosmos/cosmos-sdk/issues/17216) Add `DefaultContextWithKeys` to `testutil` package.
* (cli) [#17187](https://github.com/cosmos/cosmos-sdk/pull/17187) Do not use `ctx.PrintObjectLegacy` in commands anymore.
* `<appd> q gov proposer [proposal-id]` now returns a proposal id as int instead of string.
* `<appd> q gov proposer [proposal-id]` now returns a proposal id as int instead of string.
* (x/staking) [#17164](https://github.com/cosmos/cosmos-sdk/pull/17164) Add `BondedTokensAndPubKeyByConsAddr` to the keeper to enable vote extension verification.
* (x/group, x/gov) [#17109](https://github.com/cosmos/cosmos-sdk/pull/17109) Let proposal summary be 40x longer than metadata limit.
* (version) [#17096](https://github.com/cosmos/cosmos-sdk/pull/17096) Improve `getSDKVersion()` to handle module replacements.
@ -337,8 +339,8 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/consensus) [#15553](https://github.com/cosmos/cosmos-sdk/pull/15553) Migrate consensus module to use collections.
* (server) [#15358](https://github.com/cosmos/cosmos-sdk/pull/15358) Add `server.InterceptConfigsAndCreateContext` as alternative to `server.InterceptConfigsPreRunHandler` which does not set the server context and the default SDK logger.
* (mempool) [#15328](https://github.com/cosmos/cosmos-sdk/pull/15328) Improve the `PriorityNonceMempool`:
* Support generic transaction prioritization, instead of `ctx.Priority()`
* Improve construction through the use of a single `PriorityNonceMempoolConfig` instead of option functions
* Support generic transaction prioritization, instead of `ctx.Priority()`
* Improve construction through the use of a single `PriorityNonceMempoolConfig` instead of option functions
* (x/authz) [#15164](https://github.com/cosmos/cosmos-sdk/pull/15164) Add `MsgCancelUnbondingDelegation` to staking authorization.
* (server) [#15041](https://github.com/cosmos/cosmos-sdk/pull/15041) Remove unnecessary sleeps from gRPC and API server initiation. The servers will start and accept requests as soon as they're ready.
* (baseapp) [#15023](https://github.com/cosmos/cosmos-sdk/pull/15023) & [#15213](https://github.com/cosmos/cosmos-sdk/pull/15213) Add `MessageRouter` interface to baseapp and pass it to authz, gov and groups instead of concrete type.
@ -351,7 +353,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) Return undelegate amount in MsgUndelegateResponse.
* [#14529](https://github.com/cosmos/cosmos-sdk/pull/14529) Add new property `BondDenom` to `SimulationState` struct.
* (store) [#14439](https://github.com/cosmos/cosmos-sdk/pull/14439) Remove global metric gatherer from store.
* By default store has a no op metric gatherer, the application developer must set another metric gatherer or us the provided one in `store/metrics`.
* By default store has a no op metric gatherer, the application developer must set another metric gatherer or us the provided one in `store/metrics`.
* (store) [#14438](https://github.com/cosmos/cosmos-sdk/pull/14438) Pass logger from baseapp to store.
* (baseapp) [#14417](https://github.com/cosmos/cosmos-sdk/pull/14417) The store package no longer has a dependency on baseapp.
* (module) [#14415](https://github.com/cosmos/cosmos-sdk/pull/14415) Loosen assertions in SetOrderBeginBlockers() and SetOrderEndBlockers().
@ -383,15 +385,15 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types) [#17358](https://github.com/cosmos/cosmos-sdk/pull/17358) Remove deprecated `sdk.Handler`, use `baseapp.MsgServiceHandler` instead.
* (client) [#17197](https://github.com/cosmos/cosmos-sdk/pull/17197) `keys.Commands` does not take a home directory anymore. It is inferred from the root command.
* (x/staking) [#17157](https://github.com/cosmos/cosmos-sdk/pull/17157) `GetValidatorsByPowerIndexKey` and `ValidateBasic` for historical info takes a validator address codec in order to be able to decode/encode addresses.
* `GetOperator()` now returns the address as it is represented in state, by default this is an encoded address
* `GetConsAddr() ([]byte, error)` returns `[]byte` instead of sdk.ConsAddres.
* `FromABCIEvidence` & `GetConsensusAddress(consAc address.Codec)` now take a consensus address codec to be able to decode the incoming address.
* (x/distribution) `Delegate` & `SlashValidator` helper function added the mock staking keeper as a parameter passed to the function
* `GetOperator()` now returns the address as it is represented in state, by default this is an encoded address
* `GetConsAddr() ([]byte, error)` returns `[]byte` instead of sdk.ConsAddres.
* `FromABCIEvidence` & `GetConsensusAddress(consAc address.Codec)` now take a consensus address codec to be able to decode the incoming address.
* (x/distribution) `Delegate` & `SlashValidator` helper function added the mock staking keeper as a parameter passed to the function
* (x/staking) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgCreateValidator`, `NewValidator`, `NewMsgCancelUnbondingDelegation`, `NewMsgUndelegate`, `NewMsgBeginRedelegate`, `NewMsgDelegate` and `NewMsgEditValidator` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`:
* `NewRedelegation` and `NewUnbondingDelegation` takes a validatorAddressCodec and a delegatorAddressCodec in order to decode the addresses.
* `NewRedelegationResponse` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`.
* `NewMsgCreateValidator.Validate()` takes an address codec in order to decode the address.
* `BuildCreateValidatorMsg` takes a ValidatorAddressCodec in order to decode addresses.
* `NewRedelegation` and `NewUnbondingDelegation` takes a validatorAddressCodec and a delegatorAddressCodec in order to decode the addresses.
* `NewRedelegationResponse` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`.
* `NewMsgCreateValidator.Validate()` takes an address codec in order to decode the address.
* `BuildCreateValidatorMsg` takes a ValidatorAddressCodec in order to decode addresses.
* (x/slashing) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgUnjail` takes a string instead of `sdk.ValAddress`
* (x/genutil) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `GenAppStateFromConfig`, AddGenesisAccountCmd and `GenTxCmd` takes an addresscodec to decode addresses.
* (x/distribution) [#17098](https://github.com/cosmos/cosmos-sdk/pull/17098) `NewMsgDepositValidatorRewardsPool`, `NewMsgFundCommunityPool`, `NewMsgWithdrawValidatorCommission` and `NewMsgWithdrawDelegatorReward` takes a string instead of `sdk.ValAddress` or `sdk.AccAddress`.
@ -405,18 +407,18 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/auth) [#16423](https://github.com/cosmos/cosmos-sdk/pull/16423) `helpers.AddGenesisAccount` has been moved to `x/genutil` to remove the cyclic dependency between `x/auth` and `x/genutil`.
* (baseapp) [#16342](https://github.com/cosmos/cosmos-sdk/pull/16342) NewContext was renamed to NewContextLegacy. The replacement (NewContext) now does not take a header, instead you should set the header via `WithHeaderInfo` or `WithBlockHeight`. Note that `WithBlockHeight` will soon be depreacted and its recommneded to use `WithHeaderInfo`.
* (x/mint) [#16329](https://github.com/cosmos/cosmos-sdk/pull/16329) Use collections for state management:
* Removed: keeper `GetParams`, `SetParams`, `GetMinter`, `SetMinter`.
* Removed: keeper `GetParams`, `SetParams`, `GetMinter`, `SetMinter`.
* (x/crisis) [#16328](https://github.com/cosmos/cosmos-sdk/pull/16328) Use collections for state management:
* Removed: keeper `GetConstantFee`, `SetConstantFee`
* Removed: keeper `GetConstantFee`, `SetConstantFee`
* (x/staking) [#16324](https://github.com/cosmos/cosmos-sdk/pull/16324) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. Notable changes:
* `Validator` method now returns `types.ErrNoValidatorFound` instead of `nil` when not found.
* `Validator` method now returns `types.ErrNoValidatorFound` instead of `nil` when not found.
* (x/distribution) [#16302](https://github.com/cosmos/cosmos-sdk/pull/16302) Use collections for FeePool state management.
* Removed: keeper `GetFeePool`, `SetFeePool`, `GetFeePoolCommunityCoins`
* Removed: keeper `GetFeePool`, `SetFeePool`, `GetFeePoolCommunityCoins`
* (types) [#16272](https://github.com/cosmos/cosmos-sdk/pull/16272) `FeeGranter` in the `FeeTx` interface returns `[]byte` instead of `string`.
* (x/gov) [#16268](https://github.com/cosmos/cosmos-sdk/pull/16268) Use collections for proposal state management (part 2):
* this finalizes the gov collections migration
* Removed: types all the key related functions
* Removed: keeper `InsertActiveProposalsQueue`, `RemoveActiveProposalsQueue`, `InsertInactiveProposalsQueue`, `RemoveInactiveProposalsQueue`, `IterateInactiveProposalsQueue`, `IterateActiveProposalsQueue`, `ActiveProposalsQueueIterator`, `InactiveProposalsQueueIterator`
* this finalizes the gov collections migration
* Removed: types all the key related functions
* Removed: keeper `InsertActiveProposalsQueue`, `RemoveActiveProposalsQueue`, `InsertInactiveProposalsQueue`, `RemoveInactiveProposalsQueue`, `IterateInactiveProposalsQueue`, `IterateActiveProposalsQueue`, `ActiveProposalsQueueIterator`, `InactiveProposalsQueueIterator`
* (x/slashing) [#16246](https://github.com/cosmos/cosmos-sdk/issues/16246) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`. `GetValidatorSigningInfo` now returns an error instead of a `found bool`, the error can be `nil` (found), `ErrNoSigningInfoFound` (not found) and any other error.
* (module) [#16227](https://github.com/cosmos/cosmos-sdk/issues/16227) `manager.RunMigrations()` now take a `context.Context` instead of a `sdk.Context`.
* (x/crisis) [#16216](https://github.com/cosmos/cosmos-sdk/issues/16216) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` instead of panicking.
@ -424,18 +426,18 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (cli) [#16209](https://github.com/cosmos/cosmos-sdk/pull/16209) Add API `StartCmdWithOptions` to create customized start command.
* (x/mint) [#16179](https://github.com/cosmos/cosmos-sdk/issues/16179) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error`.
* (x/gov) [#16171](https://github.com/cosmos/cosmos-sdk/pull/16171) Use collections for proposal state management (part 1):
* Removed: keeper: `GetProposal`, `UnmarshalProposal`, `MarshalProposal`, `IterateProposal`, `GetProposal`, `GetProposalFiltered`, `GetProposals`, `GetProposalID`, `SetProposalID`
* Removed: errors unused errors
* Removed: keeper: `GetProposal`, `UnmarshalProposal`, `MarshalProposal`, `IterateProposal`, `GetProposal`, `GetProposalFiltered`, `GetProposals`, `GetProposalID`, `SetProposalID`
* Removed: errors unused errors
* (x/gov) [#16164](https://github.com/cosmos/cosmos-sdk/pull/16164) Use collections for vote state management:
* Removed: types `VoteKey`, `VoteKeys`
* Removed: keeper `IterateVotes`, `IterateAllVotes`, `GetVotes`, `GetVote`, `SetVote`
* Removed: types `VoteKey`, `VoteKeys`
* Removed: keeper `IterateVotes`, `IterateAllVotes`, `GetVotes`, `GetVote`, `SetVote`
* (sims) [#16155](https://github.com/cosmos/cosmos-sdk/pull/16155)
* `simulation.NewOperationMsg` now marshals the operation msg as proto bytes instead of legacy amino JSON bytes.
* `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed.
* The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`.
* `simulation.NewOperationMsg` now marshals the operation msg as proto bytes instead of legacy amino JSON bytes.
* `simulation.NewOperationMsg` is now 2-arity instead of 3-arity with the obsolete argument `codec.ProtoCodec` removed.
* The field `OperationMsg.Msg` is now of type `[]byte` instead of `json.RawMessage`.
* (x/gov) [#16127](https://github.com/cosmos/cosmos-sdk/pull/16127) Use collections for deposit state management:
* The following methods are removed from the gov keeper: `GetDeposit`, `GetAllDeposits`, `IterateAllDeposits`.
* The following functions are removed from the gov types: `DepositKey`, `DepositsKey`.
* The following methods are removed from the gov keeper: `GetDeposit`, `GetAllDeposits`, `IterateAllDeposits`.
* The following functions are removed from the gov types: `DepositKey`, `DepositsKey`.
* (x/gov) [#16118](https://github.com/cosmos/cosmos-sdk/pull/16118/) Use collections for constituion and params state management.
* (x/gov) [#16106](https://github.com/cosmos/cosmos-sdk/pull/16106) Remove gRPC query methods from gov keeper.
* (x/*all*) [#16052](https://github.com/cosmos/cosmos-sdk/pull/16062) `GetSignBytes` implementations on messages and global legacy amino codec definitions have been removed from all modules.
@ -443,7 +445,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types/math) [#16040](https://github.com/cosmos/cosmos-sdk/pull/16798) Remove aliases in `types/math.go` (part 2).
* (types/math) [#16040](https://github.com/cosmos/cosmos-sdk/pull/16040) Remove aliases in `types/math.go` (part 1).
* (x/auth) [#16016](https://github.com/cosmos/cosmos-sdk/pull/16016) Use collections for accounts state management:
* removed: keeper `HasAccountByID`, `AccountAddressByID`, `SetParams
* removed: keeper `HasAccountByID`, `AccountAddressByID`, `SetParams
* (x/genutil) [#15999](https://github.com/cosmos/cosmos-sdk/pull/15999) Genutil now takes the `GenesisTxHanlder` interface instead of deliverTx. The interface is implemented on baseapp
* (x/gov) [#15988](https://github.com/cosmos/cosmos-sdk/issues/15988) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey`, methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context` and return an `error` (instead of panicking or returning a `found bool`). Iterators callback functions now return an error instead of a `bool`.
* (x/auth) [#15985](https://github.com/cosmos/cosmos-sdk/pull/15985) The `AccountKeeper` does not expose the `QueryServer` and `MsgServer` APIs anymore.
@ -454,23 +456,23 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/crisis) [#15852](https://github.com/cosmos/cosmos-sdk/pull/15852) Crisis keeper now takes a instance of the address codec to be able to decode user addresses
* (x/auth) [#15822](https://github.com/cosmos/cosmos-sdk/pull/15822) The type of struct field `ante.HandlerOptions.SignModeHandler` has been changed to `x/tx/signing.HandlerMap`.
* (client) [#15822](https://github.com/cosmos/cosmos-sdk/pull/15822) The return type of the interface method `TxConfig.SignModeHandler` has been changed to `x/tx/signing.HandlerMap`.
* The signature of `VerifySignature` has been changed to accept a `x/tx/signing.HandlerMap` and other structs from `x/tx` as arguments.
* The signature of `NewTxConfigWithTextual` has been deprecated and its signature changed to accept a `SignModeOptions`.
* The signature of `NewSigVerificationDecorator` has been changed to accept a `x/tx/signing.HandlerMap`.
* The signature of `VerifySignature` has been changed to accept a `x/tx/signing.HandlerMap` and other structs from `x/tx` as arguments.
* The signature of `NewTxConfigWithTextual` has been deprecated and its signature changed to accept a `SignModeOptions`.
* The signature of `NewSigVerificationDecorator` has been changed to accept a `x/tx/signing.HandlerMap`.
* (x/bank) [#15818](https://github.com/cosmos/cosmos-sdk/issues/15818) `BaseViewKeeper`'s `Logger` method now doesn't require a context. `NewBaseKeeper`, `NewBaseSendKeeper` and `NewBaseViewKeeper` now also require a `log.Logger` to be passed in.
* (x/genutil) [#15679](https://github.com/cosmos/cosmos-sdk/pull/15679) `MigrateGenesisCmd` now takes a `MigrationMap` instead of having the SDK genesis migration hardcoded.
* (client) [#15673](https://github.com/cosmos/cosmos-sdk/pull/15673) Move `client/keys.OutputFormatJSON` and `client/keys.OutputFormatText` to `client/flags` package.
* (x/*all*) [#15648](https://github.com/cosmos/cosmos-sdk/issues/15648) Make `SetParams` consistent across all modules and validate the params at the message handling instead of `SetParams` method.
* (codec) [#15600](https://github.com/cosmos/cosmos-sdk/pull/15600) [#15873](https://github.com/cosmos/cosmos-sdk/pull/15873) add support for getting signers to `codec.Codec` and `InterfaceRegistry`:
* `InterfaceRegistry` is has unexported methods and implements `protodesc.Resolver` plus the `RangeFiles` and `SigningContext` methods. All implementations of `InterfaceRegistry` by other users must now embed the official implementation.
* `Codec` has new methods `InterfaceRegistry`, `GetMsgAnySigners`, `GetMsgV1Signers`, and `GetMsgV2Signers` as well as unexported methods. All implementations of `Codec` by other users must now embed an official implementation from the `codec` package.
* `AminoCodec` is marked as deprecated and no longer implements `Codec.
* `InterfaceRegistry` is has unexported methods and implements `protodesc.Resolver` plus the `RangeFiles` and `SigningContext` methods. All implementations of `InterfaceRegistry` by other users must now embed the official implementation.
* `Codec` has new methods `InterfaceRegistry`, `GetMsgAnySigners`, `GetMsgV1Signers`, and `GetMsgV2Signers` as well as unexported methods. All implementations of `Codec` by other users must now embed an official implementation from the `codec` package.
* `AminoCodec` is marked as deprecated and no longer implements `Codec.
* (client) [#15597](https://github.com/cosmos/cosmos-sdk/pull/15597) `RegisterNodeService` now requires a config parameter.
* (x/nft) [#15588](https://github.com/cosmos/cosmos-sdk/pull/15588) `NewKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`.
* (baseapp) [#15568](https://github.com/cosmos/cosmos-sdk/pull/15568) `SetIAVLLazyLoading` is removed from baseapp.
* (x/genutil) [#15567](https://github.com/cosmos/cosmos-sdk/pull/15567) `CollectGenTxsCmd` & `GenTxCmd` takes a address.Codec to be able to decode addresses.
* (x/bank) [#15567](https://github.com/cosmos/cosmos-sdk/pull/15567) `GenesisBalance.GetAddress` now returns a string instead of `sdk.AccAddress`
* `MsgSendExec` test helper function now takes a address.Codec
* `MsgSendExec` test helper function now takes a address.Codec
* (x/auth) [#15520](https://github.com/cosmos/cosmos-sdk/pull/15520) `NewAccountKeeper` now takes a `KVStoreService` instead of a `StoreKey` and methods in the `Keeper` now take a `context.Context` instead of a `sdk.Context`.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) `runTxMode`s were renamed to `execMode`. `ModeDeliver` as changed to `ModeFinalize` and a new `ModeVoteExtension` was added for vote extensions.
* (baseapp) [#15519](https://github.com/cosmos/cosmos-sdk/pull/15519/files) Writing of state to the multistore was moved to `FinalizeBlock`. `Commit` still handles the committing values to disk.
@ -486,29 +488,29 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284)
* (x/gov) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`.
* (x/authx) [#15284](https://github.com/cosmos/cosmos-sdk/pull/15284) `NewKeeper` now requires `codec.Codec`.
* `types/tx.Tx` no longer implements `sdk.Tx`.
* `sdk.Tx` now requires a new method `GetMsgsV2()`.
* `sdk.Msg.GetSigners` was deprecated and is no longer supported. Use the `cosmos.msg.v1.signer` protobuf annotation instead.
* `TxConfig` has a new method `SigningContext() *signing.Context`.
* `SigVerifiableTx.GetSigners()` now returns `([][]byte, error)` instead of `[]sdk.AccAddress`.
* `AccountKeeper` now has an `AddressCodec() address.Codec` method and the expected `AccountKeeper` for `x/auth/ante` expects this method.
* `types/tx.Tx` no longer implements `sdk.Tx`.
* `sdk.Tx` now requires a new method `GetMsgsV2()`.
* `sdk.Msg.GetSigners` was deprecated and is no longer supported. Use the `cosmos.msg.v1.signer` protobuf annotation instead.
* `TxConfig` has a new method `SigningContext() *signing.Context`.
* `SigVerifiableTx.GetSigners()` now returns `([][]byte, error)` instead of `[]sdk.AccAddress`.
* `AccountKeeper` now has an `AddressCodec() address.Codec` method and the expected `AccountKeeper` for `x/auth/ante` expects this method.
* [#15211](https://github.com/cosmos/cosmos-sdk/pull/15211) Remove usage of `github.com/cometbft/cometbft/libs/bytes.HexBytes` in favor of `[]byte` thorough the SDK.
* (crypto) [#15070](https://github.com/cosmos/cosmos-sdk/pull/15070) `GenerateFromPassword` and `Cost` from `bcrypt.go` now take a `uint32` instead of a `int` type.
* (types) [#15067](https://github.com/cosmos/cosmos-sdk/pull/15067) Remove deprecated alias from `types/errors`. Use `cosmossdk.io/errors` instead.
* (server) [#15041](https://github.com/cosmos/cosmos-sdk/pull/15041) Refactor how gRPC and API servers are started to remove unnecessary sleeps:
* `api.Server#Start` now accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the API server can gracefully exit. The caller does not need to stop the server.
* To start the gRPC server you must first create the server via `NewGRPCServer`, after which you can start the gRPC server via `StartGRPCServer` which accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the gRPC server can gracefully exit. The caller does not need to stop the server.
* Rename `WaitForQuitSignals` to `ListenForQuitSignals`. Note, this function is no longer blocking. Thus the caller is expected to provide a `context.CancelFunc` which indicates that when a signal is caught, that any spawned processes can gracefully exit.
* Remove `ServerStartTime` constant.
* `api.Server#Start` now accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the API server can gracefully exit. The caller does not need to stop the server.
* To start the gRPC server you must first create the server via `NewGRPCServer`, after which you can start the gRPC server via `StartGRPCServer` which accepts a `context.Context`. The caller is responsible for ensuring that the context is canceled such that the gRPC server can gracefully exit. The caller does not need to stop the server.
* Rename `WaitForQuitSignals` to `ListenForQuitSignals`. Note, this function is no longer blocking. Thus the caller is expected to provide a `context.CancelFunc` which indicates that when a signal is caught, that any spawned processes can gracefully exit.
* Remove `ServerStartTime` constant.
* [#15011](https://github.com/cosmos/cosmos-sdk/pull/15011) All functions that were taking a CometBFT logger, now take `cosmossdk.io/log.Logger` instead.
* (simapp) [#14977](https://github.com/cosmos/cosmos-sdk/pull/14977) Move simulation helpers functions (`AppStateFn` and `AppStateRandomizedFn`) to `testutil/sims`. These takes an extra genesisState argument which is the default state of the app.
* (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Allow a human readable denomination for coins when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest`.
* [#14847](https://github.com/cosmos/cosmos-sdk/pull/14847) App and ModuleManager methods `InitGenesis`, `ExportGenesis`, `BeginBlock` and `EndBlock` now also return an error.
* (x/upgrade) [#14764](https://github.com/cosmos/cosmos-sdk/pull/14764) The `x/upgrade` module is extracted to have a separate go.mod file which allows it to be a standalone module.
* (x/auth) [#14758](https://github.com/cosmos/cosmos-sdk/pull/14758) Refactor transaction searching:
* Refactor `QueryTxsByEvents` to accept a `query` of type `string` instead of `events` of type `[]string`
* Refactor CLI methods to accept `--query` flag instead of `--events`
* Pass `prove=false` to Tendermint's `TxSearch` RPC method
* Refactor `QueryTxsByEvents` to accept a `query` of type `string` instead of `events` of type `[]string`
* Refactor CLI methods to accept `--query` flag instead of `--events`
* Pass `prove=false` to Tendermint's `TxSearch` RPC method
* (simulation) [#14751](https://github.com/cosmos/cosmos-sdk/pull/14751) Remove the `MsgType` field from `simulation.OperationInput` struct.
* (store) [#14746](https://github.com/cosmos/cosmos-sdk/pull/14746) Extract Store in its own go.mod and rename the package to `cosmossdk.io/store`.
* (x/nft) [#14725](https://github.com/cosmos/cosmos-sdk/pull/14725) Extract NFT in its own go.mod and rename the package to `cosmossdk.io/x/nft`.
@ -542,16 +544,16 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (all) The migration of modules to [AutoCLI](https://docs.cosmos.network/main/core/autocli) led to no changes in UX but a [small change in CLI outputs](https://github.com/cosmos/cosmos-sdk/issues/16651) where results can be nested.
* (all) Query pagination flags have been renamed with the migration to AutoCLI:
* `--reverse` -> `--page-reverse`
* `--offset` -> `--page-offset`
* `--limit` -> `--page-limit`
* `--count-total` -> `--page-count-total`
* `--reverse` -> `--page-reverse`
* `--offset` -> `--page-offset`
* `--limit` -> `--page-limit`
* `--count-total` -> `--page-count-total`
* (cli) [#17184](https://github.com/cosmos/cosmos-sdk/pull/17184) All json keys returned by the `status` command are now snake case instead of pascal case.
* (server) [#17177](https://github.com/cosmos/cosmos-sdk/pull/17177) Remove `iavl-lazy-loading` configuration.
* (x/gov) [#16987](https://github.com/cosmos/cosmos-sdk/pull/16987) In `<appd> query gov proposals` the proposal status flag have renamed from `--status` to `--proposal-status`. Additionally, that flags now uses the ENUM values: `PROPOSAL_STATUS_DEPOSIT_PERIOD`, `PROPOSAL_STATUS_VOTING_PERIOD`, `PROPOSAL_STATUS_PASSED`, `PROPOSAL_STATUS_REJECTED`, `PROPOSAL_STATUS_FAILED`.
* (x/bank) [#16899](https://github.com/cosmos/cosmos-sdk/pull/16899) With the migration to AutoCLI some bank commands have been split in two:
* Use `total-supply` (or `total`) for querying the total supply and `total-supply-of` for querying the supply of a specific denom.
* Use `denoms-metadata` for querying all denom metadata and `denom-metadata` for querying a specific denom metadata.
* Use `total-supply` (or `total`) for querying the total supply and `total-supply-of` for querying the supply of a specific denom.
* Use `denoms-metadata` for querying all denom metadata and `denom-metadata` for querying a specific denom metadata.
* (rosetta) [#16276](https://github.com/cosmos/cosmos-sdk/issues/16276) Rosetta migration to standalone repo.
* (cli) [#15826](https://github.com/cosmos/cosmos-sdk/pull/15826) Remove `<appd> q account` command. Use `<appd> q auth account` instead.
* (cli) [#15299](https://github.com/cosmos/cosmos-sdk/pull/15299) Remove `--amino` flag from `sign` and `multi-sign` commands. Amino `StdTx` has been deprecated for a while. Amino JSON signing still works as expected.
@ -598,7 +600,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types) [#16980](https://github.com/cosmos/cosmos-sdk/pull/16980) Deprecate `IntProto` and `DecProto`. Instead, `math.Int` and `math.LegacyDec` should be used respectively. Both types support `Marshal` and `Unmarshal` for binary serialization.
* (x/staking) [#14567](https://github.com/cosmos/cosmos-sdk/pull/14567) The `delegator_address` field of `MsgCreateValidator` has been deprecated.
The validator address bytes and delegator address bytes refer to the same account while creating validator (defer only in bech32 notation).
The validator address bytes and delegator address bytes refer to the same account while creating validator (defer only in bech32 notation).
## Previous Versions

View File

@ -3,502 +3,109 @@
This guide provides instructions for upgrading to specific versions of Cosmos SDK.
Note, always read the **SimApp** section for more information on application wiring updates.
## [v0.50.x](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.50.0)
## [v0.53.x](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.53.0)
### Migration to CometBFT (Part 2)
#### Unordered Transactions
The Cosmos SDK has migrated in its previous versions, to CometBFT.
Some functions have been renamed to reflect the naming change.
The Cosmos SDK now supports unordered transactions. This means that transactions
can be executed in any order and doesn't require the client to deal with or manage
nonces. This also means the order of execution is not guaranteed.
Following an exhaustive list:
* `client.TendermintRPC` -> `client.CometRPC`
* `clitestutil.MockTendermintRPC` -> `clitestutil.MockCometRPC`
* `clitestutilgenutil.CreateDefaultTendermintConfig` -> `clitestutilgenutil.CreateDefaultCometConfig`
* Package `client/grpc/tmservice` -> `client/grpc/cmtservice`
Additionally, the commands and flags mentioning `tendermint` have been renamed to `comet`.
These commands and flags are still supported for backward compatibility.
For backward compatibility, the `**/tendermint/**` gRPC services are still supported.
Additionally, the SDK is starting its abstraction from CometBFT Go types through the codebase:
* The usage of the CometBFT logger has been replaced by the Cosmos SDK logger interface (`cosmossdk.io/log.Logger`).
* The usage of `github.com/cometbft/cometbft/libs/bytes.HexByte` has been replaced by `[]byte`.
* Usage of an application genesis (see [genutil](#xgenutil)).
#### Enable Vote Extensions
:::tip
This is an optional feature that is disabled by default.
:::
Once all the code changes required to implement Vote Extensions are in place,
they can be enabled by setting the consensus param `Abci.VoteExtensionsEnableHeight`
to a value greater than zero.
In a new chain, this can be done in the `genesis.json` file.
For existing chains this can be done in two ways:
* During an upgrade the value is set in an upgrade handler.
* A governance proposal that changes the consensus param **after a coordinated upgrade has taken place**.
### BaseApp
All ABCI methods now accept a pointer to the request and response types defined
by CometBFT. In addition, they also return errors. An ABCI method should only
return errors in cases where a catastrophic failure has occurred and the application
should halt. However, this is abstracted away from the application developer. Any
handler that an application can define or set that returns an error, will gracefully
by handled by `BaseApp` on behalf of the application.
BaseApp calls of `BeginBlock` & `Endblock` are now private but are still exposed
to the application to define via the `Manager` type. `FinalizeBlock` is public
and should be used in order to test and run operations. This means that although
`BeginBlock` & `Endblock` no longer exist in the ABCI interface, they are automatically
called by `BaseApp` during `FinalizeBlock`. Specifically, the order of operations
is `BeginBlock` -> `DeliverTx` (for all txs) -> `EndBlock`.
ABCI++ 2.0 also brings `ExtendVote` and `VerifyVoteExtension` ABCI methods. These
methods allow applications to extend and verify pre-commit votes. The Cosmos SDK
allows an application to define handlers for these methods via `ExtendVoteHandler`
and `VerifyVoteExtensionHandler` respectively. Please see [here](https://docs.cosmos.network/v0.50/build/building-apps/vote-extensions)
for more info.
#### Set PreBlocker
A `SetPreBlocker` method has been added to BaseApp. This is essential for BaseApp to run `PreBlock` which runs before begin blocker other modules, and allows to modify consensus parameters, and the changes are visible to the following state machine logics.
Read more about other use cases [here](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-068-preblock.md).
`depinject` / app di users need to add `x/upgrade` in their `app_config.go` / `app.yml`:
Unordered transactions are automatically enabled when using `depinject` / app di, simply supply the `servertypes.AppOptions` in `app.go`:
```diff
+ PreBlockers: []string{
+ upgradetypes.ModuleName,
+ },
BeginBlockers: []string{
- upgradetypes.ModuleName,
minttypes.ModuleName,
}
```
When using (legacy) application wiring, the following must be added to `app.go`:
```diff
+app.ModuleManager.SetOrderPreBlockers(
+ upgradetypes.ModuleName,
+)
app.ModuleManager.SetOrderBeginBlockers(
- upgradetypes.ModuleName,
)
+ app.SetPreBlocker(app.PreBlocker)
// ... //
+func (app *SimApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
+ return app.ModuleManager.PreBlock(ctx, req)
+}
```
#### Events
The log section of `abci.TxResult` is not populated in the case of successful
msg(s) execution. Instead a new attribute is added to all messages indicating
the `msg_index` which identifies which events and attributes relate the same
transaction.
`BeginBlock` & `EndBlock` Events are now emitted through `FinalizeBlock` but have
an added attribute, `mode=BeginBlock|EndBlock`, to identify if the event belongs
to `BeginBlock` or `EndBlock`.
### Config files
Confix is a new SDK tool for modifying and migrating configuration of the SDK.
It is the replacement of the `config.Cmd` command from the `client/config` package.
Use the following command to migrate your configuration:
```bash
simd config migrate v0.50
```
If you were using `<appd> config [key]` or `<appd> config [key] [value]` to set and get values from the `client.toml`, replace it with `<appd> config get client [key]` and `<appd> config set client [key] [value]`. The extra verbosity is due to the extra functionalities added in config.
More information about [confix](https://docs.cosmos.network/main/tooling/confix) and how to add it in your application binary in the [documentation](https://docs.cosmos.network/main/tooling/confix).
#### gRPC-Web
gRPC-Web is now listening to the same address and port as the gRPC Gateway API server (default: `localhost:1317`).
The possibility to listen to a different address has been removed, as well as its settings.
Use `confix` to clean-up your `app.toml`. A nginx (or alike) reverse-proxy can be set to keep the previous behavior.
#### Database Support
ClevelDB, BoltDB and BadgerDB are not supported anymore. To migrate from a unsupported database to a supported database please use a database migration tool.
### Protobuf
With the deprecation of the Amino JSON codec defined in [cosmos/gogoproto](https://github.com/cosmos/gogoproto) in favor of the protoreflect powered x/tx/aminojson codec, module developers are encouraged verify that their messages have the correct protobuf annotations to deterministically produce identical output from both codecs.
For core SDK types equivalence is asserted by generative testing of [SignableTypes](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-beta.0/tests/integration/rapidgen/rapidgen.go#L102) in [TestAminoJSON_Equivalence](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-beta.0/tests/integration/tx/aminojson/aminojson_test.go#L94).
**TODO: summarize proto annotation requirements.**
#### Stringer
The `gogoproto.goproto_stringer = false` annotation has been removed from most proto files. This means that the `String()` method is being generated for types that previously had this annotation. The generated `String()` method uses `proto.CompactTextString` for _stringifying_ structs.
[Verify](https://github.com/cosmos/cosmos-sdk/pull/13850#issuecomment-1328889651) the usage of the modified `String()` methods and double-check that they are not used in state-machine code.
### SimApp
In this section we describe the changes made in Cosmos SDK' SimApp.
**These changes are directly applicable to your application wiring.**
#### Module Assertions
Previously, all modules were required to be set in `OrderBeginBlockers`, `OrderEndBlockers` and `OrderInitGenesis / OrderExportGenesis` in `app.go` / `app_config.go`. This is no longer the case, the assertion has been loosened to only require modules implementing, respectively, the `appmodule.HasBeginBlocker`, `appmodule.HasEndBlocker` and `appmodule.HasGenesis` / `module.HasGenesis` interfaces.
#### Module wiring
The following modules `NewKeeper` function now take a `KVStoreService` instead of a `StoreKey`:
* `x/auth`
* `x/authz`
* `x/bank`
* `x/consensus`
* `x/crisis`
* `x/distribution`
* `x/evidence`
* `x/feegrant`
* `x/gov`
* `x/mint`
* `x/nft`
* `x/slashing`
* `x/upgrade`
**Users using `depinject` / app di do not need any changes, this is abstracted for them.**
Users manually wiring their chain need to use the `runtime.NewKVStoreService` method to create a `KVStoreService` from a `StoreKey`:
```diff
app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(
appCodec,
- keys[consensusparamtypes.StoreKey]
+ runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]),
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)
```
#### Logger
Replace all your CometBFT logger imports by `cosmossdk.io/log`.
Additionally, `depinject` / app di users must now supply a logger through the main `depinject.Supply` function instead of passing it to `appBuilder.Build`.
```diff
appConfig = depinject.Configs(
AppConfig,
depinject.Supply(
// supply the application options
appOpts,
+ logger,
...
```
```diff
- app.App = appBuilder.Build(logger, db, traceStore, baseAppOptions...)
+ app.App = appBuilder.Build(db, traceStore, baseAppOptions...)
```
User manually wiring their chain need to add the logger argument when creating the `x/bank` keeper.
#### Module Basics
Previously, the `ModuleBasics` was a global variable that was used to register all modules' `AppModuleBasic` implementation.
The global variable has been removed and the basic module manager can be now created from the module manager.
This is automatically done for `depinject` / app di users, however for supplying different app module implementation, pass them via `depinject.Supply` in the main `AppConfig` (`app_config.go`):
```go
depinject.Supply(
// supply custom module basics
map[string]module.AppModuleBasic{
genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator),
govtypes.ModuleName: gov.NewAppModuleBasic(
[]govclient.ProposalHandler{
paramsclient.ProposalHandler,
},
),
},
)
```
Users manually wiring their chain need to use the new `module.NewBasicManagerFromManager` function, after the module manager creation, and pass a `map[string]module.AppModuleBasic` as argument for optionally overriding some module's `AppModuleBasic`.
#### AutoCLI
[`AutoCLI`](https://docs.cosmos.network/main/core/autocli) has been implemented by the SDK for all its module CLI queries. This means chains must add the following in their `root.go` to enable `AutoCLI` in their application:
```go
if err := autoCliOpts.EnhanceRootCommand(rootCmd); err != nil {
panic(err)
}
```
Where `autoCliOpts` is the autocli options of the app, containing all modules and codecs.
That value can injected by depinject ([see root_v2.go](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-beta.0/simapp/simd/cmd/root_v2.go#L49-L67)) or manually provided by the app ([see legacy app.go](https://github.com/cosmos/cosmos-sdk/blob/v0.50.0-beta.0/simapp/app.go#L636-L655)).
:::warning
Not doing this will result in all core SDK modules queries not to be included in the binary.
:::
Additionally `AutoCLI` automatically adds the custom modules commands to the root command for all modules implementing the [`appmodule.AppModule`](https://pkg.go.dev/cosmossdk.io/core/appmodule#AppModule) interface.
This means, after ensuring all the used modules implement this interface, the following can be removed from your `root.go`:
```diff
func txCommand() *cobra.Command {
....
- appd.ModuleBasics.AddTxCommands(cmd)
}
```
```diff
func queryCommand() *cobra.Command {
....
- appd.ModuleBasics.AddQueryCommands(cmd)
}
```
### Packages
#### Math
References to `types/math.go` which contained aliases for math types aliasing the `cosmossdk.io/math` package have been removed.
Import directly the `cosmossdk.io/math` package instead.
#### Store
References to `types/store.go` which contained aliases for store types have been remapped to point to appropriate `store/types`, hence the `types/store.go` file is no longer needed and has been removed.
##### Extract Store to a standalone module
The `store` module is extracted to have a separate go.mod file which allows it be a standalone module.
All the store imports are now renamed to use `cosmossdk.io/store` instead of `github.com/cosmos/cosmos-sdk/store` across the SDK.
##### Streaming
[ADR-38](https://docs.cosmos.network/main/architecture/adr-038-state-listening) has been implemented in the SDK.
To continue using state streaming, replace `streaming.LoadStreamingServices` by the following in your `app.go`:
```go
if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil {
panic(err)
}
```
#### Client
The return type of the interface method `TxConfig.SignModeHandler()` has been changed from `x/auth/signing.SignModeHandler` to `x/tx/signing.HandlerMap`. This change is transparent to most users as the `TxConfig` interface is typically implemented by private `x/auth/tx.config` struct (as returned by `auth.NewTxConfig`) which has been updated to return the new type. If users have implemented their own `TxConfig` interface, they will need to update their implementation to return the new type.
##### Textual sign mode
A new sign mode is available in the SDK that produces more human readable output, currently only available on Ledger
devices but soon to be implemented in other UIs.
:::tip
This sign mode does not allow offline signing
:::
When using (legacy) application wiring, the following must be added to `app.go` after setting the app's bank keeper:
```go
enabledSignModes := append(tx.DefaultSignModes, sigtypes.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts := tx.ConfigOptions{
EnabledSignModes: enabledSignModes,
TextualCoinMetadataQueryFn: txmodule.NewBankKeeperCoinMetadataQueryFn(app.BankKeeper),
}
txConfig, err := tx.NewTxConfigWithOptions(
appCodec,
txConfigOpts,
+ // supply the application options
+ appOpts,
// supply the logger
logger,
)
if err != nil {
log.Fatalf("Failed to create new TxConfig with options: %v", err)
}
app.txConfig = txConfig
```
When using `depinject` / `app di`, **it's enabled by default** if there's a bank keeper present.
<details>
<summary>Step-by-step Wiring </summary>
If you are still using the legacy wiring, you must enable unordered transactions manually:
And in the application client (usually `root.go`):
* Update the `App` constructor to create, load, and save the unordered transaction
manager.
```go
if !clientCtx.Offline {
txConfigOpts.EnabledSignModes = append(txConfigOpts.EnabledSignModes, signing.SignMode_SIGN_MODE_TEXTUAL)
txConfigOpts.TextualCoinMetadataQueryFn = txmodule.NewGRPCCoinMetadataQueryFn(clientCtx)
txConfigWithTextual, err := tx.NewTxConfigWithOptions(
codec.NewProtoCodec(clientCtx.InterfaceRegistry),
txConfigOpts,
)
if err != nil {
return err
}
clientCtx = clientCtx.WithTxConfig(txConfigWithTextual)
}
```
```go
func NewApp(...) *App {
// ...
When using `depinject` / `app di`, the a tx config should be recreated from the `txConfigOpts` to use `NewGRPCCoinMetadataQueryFn` instead of depending on the bank keeper (that is used in the server).
// create, start, and load the unordered tx manager
utxDataDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data")
app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir)
app.UnorderedTxManager.Start()
To learn more see the [docs](https://docs.cosmos.network/main/learn/advanced/transactions#sign_mode_textual) and the [ADR-050](https://docs.cosmos.network/main/build/architecture/adr-050-sign-mode-textual).
if err := app.UnorderedTxManager.OnInit(); err != nil {
panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err))
}
}
```
### Modules
* Add the decorator to the existing AnteHandler chain, which should be as early
as possible.
#### `**all**`
```go
anteDecorators := []sdk.AnteDecorator{
ante.NewSetUpContextDecorator(),
// ...
ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.TxManager, options.Environment),
// ...
}
* [RFC 001](https://docs.cosmos.network/main/rfc/rfc-001-tx-validation) has defined a simplification of the message validation process for modules.
The `sdk.Msg` interface has been updated to not require the implementation of the `ValidateBasic` method.
It is now recommended to validate message directly in the message server. When the validation is performed in the message server, the `ValidateBasic` method on a message is no longer required and can be removed.
return sdk.ChainAnteDecorators(anteDecorators...), nil
```
* Messages no longer need to implement the `LegacyMsg` interface and implementations of `GetSignBytes` can be deleted. Because of this change, global legacy Amino codec definitions and their registration in `init()` can safely be removed as well.
* If the App has a SnapshotManager defined, you must also register the extension
for the TxManager.
* The `AppModuleBasic` interface has been simplified. Defining `GetTxCmd() *cobra.Command` and `GetQueryCmd() *cobra.Command` is no longer required. The module manager detects when module commands are defined. If AutoCLI is enabled, `EnhanceRootCommand()` will add the auto-generated commands to the root command, unless a custom module command is defined and register that one instead.
```go
if manager := app.SnapshotManager(); manager != nil {
err := manager.RegisterExtensions(unorderedtx.NewSnapshotter(app.UnorderedTxManager))
if err != nil {
panic(fmt.Errorf("failed to register snapshot extension: %s", err))
}
}
```
* The following modules' `Keeper` methods now take in a `context.Context` instead of `sdk.Context`. Any module that has an interfaces for them (like "expected keepers") will need to update and re-generate mocks if needed:
* Create or update the App's `Preblocker()` method to call the unordered tx
manager's `OnNewBlock()` method.
* `x/authz`
* `x/bank`
* `x/mint`
* `x/crisis`
* `x/distribution`
* `x/evidence`
* `x/gov`
* `x/slashing`
* `x/upgrade`
```go
...
app.SetPreblocker(app.PreBlocker)
...
* `BeginBlock` and `EndBlock` have changed their signature, so it is important that any module implementing them are updated accordingly.
func (app *SimApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
app.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
return app.ModuleManager.PreBlock(ctx, req)
}
```
```diff
- BeginBlock(sdk.Context, abci.RequestBeginBlock)
+ BeginBlock(context.Context) error
```
* Create or update the App's `Close()` method to close the unordered tx manager.
Note, this is critical as it ensures the manager's state is written to file
such that when the node restarts, it can recover the state to provide replay
protection.
```diff
- EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate
+ EndBlock(context.Context) error
```
```go
func (app *App) Close() error {
// ...
In case a module requires to return `abci.ValidatorUpdate` from `EndBlock`, it can use the `HasABCIEndBlock` interface instead.
// close the unordered tx manager
if e := app.UnorderedTxManager.Close(); e != nil {
err = errors.Join(err, e)
}
```diff
- EndBlock(sdk.Context, abci.RequestEndBlock) []abci.ValidatorUpdate
+ EndBlock(context.Context) ([]abci.ValidatorUpdate, error)
```
return err
}
```
:::tip
It is possible to ensure that a module implements the correct interfaces by using compiler assertions in your `x/{moduleName}/module.go`:
</details>
```go
var (
_ module.AppModuleBasic = (*AppModule)(nil)
_ module.AppModuleSimulation = (*AppModule)(nil)
_ module.HasGenesis = (*AppModule)(nil)
_ appmodule.AppModule = (*AppModule)(nil)
_ appmodule.HasBeginBlocker = (*AppModule)(nil)
_ appmodule.HasEndBlocker = (*AppModule)(nil)
...
)
```
Read more on those interfaces [here](https://docs.cosmos.network/v0.50/building-modules/module-manager#application-module-interfaces).
:::
* `GetSigners()` is no longer required to be implemented on `Msg` types. The SDK will automatically infer the signers from the `Signer` field on the message. The signer field is required on all messages unless using a custom signer function.
To find out more please read the [signer field](../../build/building-modules/05-protobuf-annotations.md#signer) & [here](https://github.com/cosmos/cosmos-sdk/blob/7352d0bce8e72121e824297df453eb1059c28da8/docs/docs/build/building-modules/02-messages-and-queries.md#L40) documentation.
<!-- Link to docs once redeployed -->
#### `x/auth`
For ante handler construction via `ante.NewAnteHandler`, the field `ante.HandlerOptions.SignModeHandler` has been updated to `x/tx/signing/HandlerMap` from `x/auth/signing/SignModeHandler`. Callers typically fetch this value from `client.TxConfig.SignModeHandler()` (which is also changed) so this change should be transparent to most users.
#### `x/capability`
Capability has been moved to [IBC Go](https://github.com/cosmos/ibc-go). IBC v8 will contain the necessary changes to incorporate the new module location.
#### `x/genutil`
The Cosmos SDK has migrated from a CometBFT genesis to a application managed genesis file.
The genesis is now fully handled by `x/genutil`. This has no consequences for running chains:
* Importing a CometBFT genesis is still supported.
* Exporting a genesis now exports the genesis as an application genesis.
When needing to read an application genesis, use the following helpers from the `x/genutil/types` package:
```go
// AppGenesisFromReader reads the AppGenesis from the reader.
func AppGenesisFromReader(reader io.Reader) (*AppGenesis, error)
// AppGenesisFromFile reads the AppGenesis from the provided file.
func AppGenesisFromFile(genFile string) (*AppGenesis, error)
```
#### `x/gov`
##### Expedited Proposals
The `gov` v1 module now supports expedited governance proposals. When a proposal is expedited, the voting period will be shortened to `ExpeditedVotingPeriod` parameter. An expedited proposal must have an higher voting threshold than a classic proposal, that threshold is defined with the `ExpeditedThreshold` parameter.
##### Cancelling Proposals
The `gov` module now supports cancelling governance proposals. When a proposal is canceled, all the deposits of the proposal are either burnt or sent to `ProposalCancelDest` address. The deposits burn rate will be determined by a new parameter called `ProposalCancelRatio` parameter.
```text
1. deposits * proposal_cancel_ratio will be burned or sent to `ProposalCancelDest` address , if `ProposalCancelDest` is empty then deposits will be burned.
2. deposits * (1 - proposal_cancel_ratio) will be sent to depositors.
```
By default, the new `ProposalCancelRatio` parameter is set to `0.5` during migration and `ProposalCancelDest` is set to empty string (i.e. burnt).
#### `x/evidence`
##### Extract evidence to a standalone module
The `x/evidence` module is extracted to have a separate go.mod file which allows it be a standalone module.
All the evidence imports are now renamed to use `cosmossdk.io/x/evidence` instead of `github.com/cosmos/cosmos-sdk/x/evidence` across the SDK.
#### `x/nft`
##### Extract nft to a standalone module
The `x/nft` module is extracted to have a separate go.mod file which allows it to be a standalone module.
All the evidence imports are now renamed to use `cosmossdk.io/x/nft` instead of `github.com/cosmos/cosmos-sdk/x/nft` across the SDK.
#### x/feegrant
##### Extract feegrant to a standalone module
The `x/feegrant` module is extracted to have a separate go.mod file which allows it to be a standalone module.
All the feegrant imports are now renamed to use `cosmossdk.io/x/feegrant` instead of `github.com/cosmos/cosmos-sdk/x/feegrant` across the SDK.
#### `x/upgrade`
##### Extract upgrade to a standalone module
The `x/upgrade` module is extracted to have a separate go.mod file which allows it to be a standalone module.
All the upgrade imports are now renamed to use `cosmossdk.io/x/upgrade` instead of `github.com/cosmos/cosmos-sdk/x/upgrade` across the SDK.
### Tooling
#### Rosetta
Rosetta has moved to it's own [repo](https://github.com/cosmos/rosetta) and not imported by the Cosmos SDK SimApp by default.
Any user who is interested on using the tool can connect it standalone to any node without the need to add it as part of the node binary.
The rosetta tool also allows multi chain connections.
To submit an unordered transaction, the client must set the `unordered` flag to
`true` and ensure a reasonable `timeout_height` is set. The `timeout_height` is
used as a TTL for the transaction and is used to provide replay protection. See
[ADR-070](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-070-unordered-transactions.md)
for more details.

View File

@ -2,11 +2,15 @@
package txv1beta1
import (
fmt "fmt"
io "io"
reflect "reflect"
sync "sync"
_ "cosmossdk.io/api/amino"
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"
@ -14,9 +18,7 @@ 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"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
)
var _ protoreflect.List = (*_Tx_3_list)(nil)
@ -2767,6 +2769,8 @@ var (
fd_TxBody_messages protoreflect.FieldDescriptor
fd_TxBody_memo protoreflect.FieldDescriptor
fd_TxBody_timeout_height protoreflect.FieldDescriptor
fd_TxBody_unordered protoreflect.FieldDescriptor
fd_TxBody_timeout_timestamp protoreflect.FieldDescriptor
fd_TxBody_extension_options protoreflect.FieldDescriptor
fd_TxBody_non_critical_extension_options protoreflect.FieldDescriptor
)
@ -2777,6 +2781,8 @@ func init() {
fd_TxBody_messages = md_TxBody.Fields().ByName("messages")
fd_TxBody_memo = md_TxBody.Fields().ByName("memo")
fd_TxBody_timeout_height = md_TxBody.Fields().ByName("timeout_height")
fd_TxBody_unordered = md_TxBody.Fields().ByName("unordered")
fd_TxBody_timeout_timestamp = md_TxBody.Fields().ByName("timeout_timestamp")
fd_TxBody_extension_options = md_TxBody.Fields().ByName("extension_options")
fd_TxBody_non_critical_extension_options = md_TxBody.Fields().ByName("non_critical_extension_options")
}
@ -2864,6 +2870,18 @@ func (x *fastReflection_TxBody) Range(f func(protoreflect.FieldDescriptor, proto
return
}
}
if x.Unordered != false {
value := protoreflect.ValueOfBool(x.Unordered)
if !f(fd_TxBody_unordered, value) {
return
}
}
if x.TimeoutTimestamp != nil {
value := protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect())
if !f(fd_TxBody_timeout_timestamp, value) {
return
}
}
if len(x.ExtensionOptions) != 0 {
value := protoreflect.ValueOfList(&_TxBody_1023_list{list: &x.ExtensionOptions})
if !f(fd_TxBody_extension_options, value) {
@ -2897,6 +2915,10 @@ func (x *fastReflection_TxBody) Has(fd protoreflect.FieldDescriptor) bool {
return x.Memo != ""
case "cosmos.tx.v1beta1.TxBody.timeout_height":
return x.TimeoutHeight != uint64(0)
case "cosmos.tx.v1beta1.TxBody.unordered":
return x.Unordered != false
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
return x.TimeoutTimestamp != nil
case "cosmos.tx.v1beta1.TxBody.extension_options":
return len(x.ExtensionOptions) != 0
case "cosmos.tx.v1beta1.TxBody.non_critical_extension_options":
@ -2923,6 +2945,10 @@ func (x *fastReflection_TxBody) Clear(fd protoreflect.FieldDescriptor) {
x.Memo = ""
case "cosmos.tx.v1beta1.TxBody.timeout_height":
x.TimeoutHeight = uint64(0)
case "cosmos.tx.v1beta1.TxBody.unordered":
x.Unordered = false
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
x.TimeoutTimestamp = nil
case "cosmos.tx.v1beta1.TxBody.extension_options":
x.ExtensionOptions = nil
case "cosmos.tx.v1beta1.TxBody.non_critical_extension_options":
@ -2955,6 +2981,12 @@ func (x *fastReflection_TxBody) Get(descriptor protoreflect.FieldDescriptor) pro
case "cosmos.tx.v1beta1.TxBody.timeout_height":
value := x.TimeoutHeight
return protoreflect.ValueOfUint64(value)
case "cosmos.tx.v1beta1.TxBody.unordered":
value := x.Unordered
return protoreflect.ValueOfBool(value)
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
value := x.TimeoutTimestamp
return protoreflect.ValueOfMessage(value.ProtoReflect())
case "cosmos.tx.v1beta1.TxBody.extension_options":
if len(x.ExtensionOptions) == 0 {
return protoreflect.ValueOfList(&_TxBody_1023_list{})
@ -2995,6 +3027,10 @@ func (x *fastReflection_TxBody) Set(fd protoreflect.FieldDescriptor, value proto
x.Memo = value.Interface().(string)
case "cosmos.tx.v1beta1.TxBody.timeout_height":
x.TimeoutHeight = value.Uint()
case "cosmos.tx.v1beta1.TxBody.unordered":
x.Unordered = value.Bool()
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
x.TimeoutTimestamp = value.Message().Interface().(*timestamppb.Timestamp)
case "cosmos.tx.v1beta1.TxBody.extension_options":
lv := value.List()
clv := lv.(*_TxBody_1023_list)
@ -3029,6 +3065,11 @@ func (x *fastReflection_TxBody) Mutable(fd protoreflect.FieldDescriptor) protore
}
value := &_TxBody_1_list{list: &x.Messages}
return protoreflect.ValueOfList(value)
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
if x.TimeoutTimestamp == nil {
x.TimeoutTimestamp = new(timestamppb.Timestamp)
}
return protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect())
case "cosmos.tx.v1beta1.TxBody.extension_options":
if x.ExtensionOptions == nil {
x.ExtensionOptions = []*anypb.Any{}
@ -3045,6 +3086,8 @@ func (x *fastReflection_TxBody) Mutable(fd protoreflect.FieldDescriptor) protore
panic(fmt.Errorf("field memo of message cosmos.tx.v1beta1.TxBody is not mutable"))
case "cosmos.tx.v1beta1.TxBody.timeout_height":
panic(fmt.Errorf("field timeout_height of message cosmos.tx.v1beta1.TxBody is not mutable"))
case "cosmos.tx.v1beta1.TxBody.unordered":
panic(fmt.Errorf("field unordered of message cosmos.tx.v1beta1.TxBody is not mutable"))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.tx.v1beta1.TxBody"))
@ -3065,6 +3108,11 @@ func (x *fastReflection_TxBody) NewField(fd protoreflect.FieldDescriptor) protor
return protoreflect.ValueOfString("")
case "cosmos.tx.v1beta1.TxBody.timeout_height":
return protoreflect.ValueOfUint64(uint64(0))
case "cosmos.tx.v1beta1.TxBody.unordered":
return protoreflect.ValueOfBool(false)
case "cosmos.tx.v1beta1.TxBody.timeout_timestamp":
m := new(timestamppb.Timestamp)
return protoreflect.ValueOfMessage(m.ProtoReflect())
case "cosmos.tx.v1beta1.TxBody.extension_options":
list := []*anypb.Any{}
return protoreflect.ValueOfList(&_TxBody_1023_list{list: &list})
@ -3153,6 +3201,13 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods {
if x.TimeoutHeight != 0 {
n += 1 + runtime.Sov(uint64(x.TimeoutHeight))
}
if x.Unordered {
n += 2
}
if x.TimeoutTimestamp != nil {
l = options.Size(x.TimeoutTimestamp)
n += 1 + l + runtime.Sov(uint64(l))
}
if len(x.ExtensionOptions) > 0 {
for _, e := range x.ExtensionOptions {
l = options.Size(e)
@ -3230,6 +3285,30 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods {
dAtA[i] = 0xfa
}
}
if x.TimeoutTimestamp != nil {
encoded, err := options.Marshal(x.TimeoutTimestamp)
if err != nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded)))
i--
dAtA[i] = 0x2a
}
if x.Unordered {
i--
if x.Unordered {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if x.TimeoutHeight != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.TimeoutHeight))
i--
@ -3392,6 +3471,62 @@ func (x *fastReflection_TxBody) ProtoMethods() *protoiface.Methods {
break
}
}
case 4:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Unordered", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
x.Unordered = bool(v != 0)
case 5:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if x.TimeoutTimestamp == nil {
x.TimeoutTimestamp = &timestamppb.Timestamp{}
}
if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.TimeoutTimestamp); err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
case 1023:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ExtensionOptions", wireType)
@ -8414,11 +8549,29 @@ type TxBody struct {
Messages []*anypb.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"`
// memo is any arbitrary note/comment to be added to the transaction.
// WARNING: in clients, any publicly exposed text should not be called memo,
// but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122).
// but should be called `note` instead (see
// https://github.com/cosmos/cosmos-sdk/issues/9122).
Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"`
// timeout is the block height after which this transaction will not
// be processed by the chain
// timeout_height is the block height after which this transaction will not
// be processed by the chain.
TimeoutHeight uint64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"`
// unordered, when set to true, indicates that the transaction signer(s)
// intend for the transaction to be evaluated and executed in an un-ordered
// fashion. Specifically, the account's nonce will NOT be checked or
// incremented, which allows for fire-and-forget as well as concurrent
// transaction execution.
//
// Note, when set to true, the existing 'timeout_timestamp' value must
// be set and will be used to correspond to a timestamp in which the transaction is deemed
// valid.
Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"`
// timeout_timestamp is the block time after which this transaction will not
// be processed by the chain.
//
// Note, if unordered=true this value MUST be set
// and will act as a short-lived TTL in which the transaction is deemed valid
// and kept in memory to prevent duplicates.
TimeoutTimestamp *timestamppb.Timestamp `protobuf:"bytes,5,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty"`
// extension_options are arbitrary options that can be added by chains
// when the default options are not sufficient. If any of these are present
// and can't be handled, the transaction will be rejected
@ -8470,6 +8623,20 @@ func (x *TxBody) GetTimeoutHeight() uint64 {
return 0
}
func (x *TxBody) GetUnordered() bool {
if x != nil {
return x.Unordered
}
return false
}
func (x *TxBody) GetTimeoutTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.TimeoutTimestamp
}
return nil
}
func (x *TxBody) GetExtensionOptions() []*anypb.Any {
if x != nil {
return x.ExtensionOptions
@ -8703,13 +8870,15 @@ type Fee struct {
// gas_limit is the maximum gas that can be used in transaction processing
// before an out of gas error occurs
GasLimit uint64 `protobuf:"varint,2,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
// if unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees.
// the payer must be a tx signer (and thus have signed this field in AuthInfo).
// setting this field does *not* change the ordering of required signers for the transaction.
// if unset, the first signer is responsible for paying the fees. If set, the
// specified account must pay the fees. the payer must be a tx signer (and
// thus have signed this field in AuthInfo). setting this field does *not*
// change the ordering of required signers for the transaction.
Payer string `protobuf:"bytes,3,opt,name=payer,proto3" json:"payer,omitempty"`
// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used
// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does
// not support fee grants, this will fail
// if set, the fee payer (either the first signer or the value of the payer
// field) requests that a fee grant be used to pay fees instead of the fee
// payer's own balance. If an appropriate fee grant does not exist or the
// chain does not support fee grants, this will fail
Granter string `protobuf:"bytes,4,opt,name=granter,proto3" json:"granter,omitempty"`
}
@ -8989,160 +9158,169 @@ var file_cosmos_tx_v1beta1_tx_proto_rawDesc = []byte{
0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x63, 0x6f, 0x73,
0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x02, 0x54, 0x78, 0x12, 0x2d, 0x0a,
0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e,
0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x38, 0x0a, 0x09,
0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x61, 0x75,
0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e,
0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x05, 0x54, 0x78, 0x52, 0x61, 0x77, 0x12,
0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x26,
0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, 0x79, 0x74, 0x65,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66,
0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e,
0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e, 0x44,
0x6f, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65,
0x73, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68,
0x49, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61,
0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61,
0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f,
0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xf2, 0x01, 0x0a, 0x10,
0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75, 0x78,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8d, 0x01, 0x0a, 0x02, 0x54, 0x78, 0x12, 0x2d,
0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63,
0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31,
0x2e, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x38, 0x0a,
0x09, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62,
0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x61,
0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67,
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x6e, 0x0a, 0x05, 0x54, 0x78, 0x52, 0x61, 0x77,
0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12,
0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12,
0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65,
0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e,
0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e,
0x63, 0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69, 0x70,
0x22, 0x95, 0x02, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x30, 0x0a, 0x08, 0x6d,
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x41, 0x6e, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x12, 0x0a,
0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d,
0x6f, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69,
0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x42, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff, 0x07,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, 0x65, 0x78, 0x74, 0x65,
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a, 0x0a, 0x1e,
0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74,
0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xff,
0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1b, 0x6e, 0x6f, 0x6e,
0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x08, 0x41, 0x75, 0x74,
0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x5f,
0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e,
0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x69, 0x67, 0x6e,
0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x03, 0x66, 0x65, 0x65, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78,
0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x03, 0x66, 0x65,
0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74,
0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69, 0x70, 0x22,
0x97, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x33,
0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e,
0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1a, 0x0a,
0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52,
0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xe0, 0x02, 0x0a, 0x08, 0x4d, 0x6f,
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e,
0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49,
0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x06, 0x73, 0x69,
0x6e, 0x67, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e,
0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f,
0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x48, 0x00, 0x52, 0x05, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x1a,
0x41, 0x0a, 0x06, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f,
0x64, 0x65, 0x1a, 0x90, 0x01, 0x0a, 0x05, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x4b, 0x0a, 0x08,
0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f,
0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x6d,
0x75, 0x6c, 0x74, 0x69, 0x73, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e,
0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x69, 0x74, 0x41, 0x72, 0x72, 0x61, 0x79, 0x52,
0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x6d, 0x6f, 0x64,
0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e,
0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, 0x79, 0x74,
0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x49, 0x6e,
0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0a, 0x73, 0x69, 0x67,
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x22, 0x92, 0x01, 0x0a, 0x07, 0x53, 0x69, 0x67, 0x6e,
0x44, 0x6f, 0x63, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65,
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74,
0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f,
0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74,
0x68, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68,
0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68,
0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61,
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0xf2, 0x01, 0x0a,
0x10, 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75,
0x78, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73,
0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69,
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64,
0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62,
0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65,
0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65,
0x6e, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62,
0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69,
0x70, 0x22, 0x86, 0x03, 0x0a, 0x06, 0x54, 0x78, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x30, 0x0a, 0x08,
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x12, 0x12,
0x0a, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65,
0x6d, 0x6f, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x68, 0x65,
0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x6e, 0x6f,
0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x75, 0x6e,
0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x51, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08,
0xc8, 0xde, 0x1f, 0x01, 0x90, 0xdf, 0x1f, 0x01, 0x52, 0x10, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75,
0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x42, 0x0a, 0x11, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18,
0xff, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, 0x65, 0x78,
0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x5a,
0x0a, 0x1e, 0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x65,
0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0xff, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1b, 0x6e,
0x6f, 0x6e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73,
0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa4, 0x01, 0x0a, 0x08, 0x41,
0x75, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x0c, 0x73, 0x69, 0x67, 0x6e, 0x65,
0x72, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61,
0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65,
0x49, 0x6e, 0x66, 0x6f, 0x73, 0x42, 0x05, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x22, 0x81, 0x02, 0x0a,
0x03, 0x46, 0x65, 0x65, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61,
0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42,
0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e,
0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x63, 0x6f, 0x69,
0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12,
0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2e, 0x0a, 0x05,
0x70, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d,
0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x07,
0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2,
0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x73, 0x69,
0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x12, 0x28, 0x0a, 0x03, 0x66, 0x65, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e,
0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x46, 0x65, 0x65, 0x52, 0x03,
0x66, 0x65, 0x65, 0x12, 0x2c, 0x0a, 0x03, 0x74, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x16, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62,
0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x69, 0x70, 0x42, 0x02, 0x18, 0x01, 0x52, 0x03, 0x74, 0x69,
0x70, 0x22, 0x97, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f,
0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x38, 0x0a, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e,
0x66, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12,
0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x22, 0xe0, 0x02, 0x0a, 0x08,
0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3c, 0x0a, 0x06, 0x73, 0x69, 0x6e, 0x67,
0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64,
0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x06,
0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x05, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74,
0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e,
0x66, 0x6f, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x48, 0x00, 0x52, 0x05, 0x6d, 0x75, 0x6c, 0x74,
0x69, 0x1a, 0x41, 0x0a, 0x06, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x12, 0x37, 0x0a, 0x04, 0x6d,
0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d,
0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31,
0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04,
0x6d, 0x6f, 0x64, 0x65, 0x1a, 0x90, 0x01, 0x0a, 0x05, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x12, 0x4b,
0x0a, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f,
0x2e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x73, 0x69, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61,
0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0x42, 0x69, 0x74, 0x41, 0x72, 0x72, 0x61,
0x79, 0x52, 0x08, 0x62, 0x69, 0x74, 0x61, 0x72, 0x72, 0x61, 0x79, 0x12, 0x3a, 0x0a, 0x0a, 0x6d,
0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x2e, 0x4d, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x6d, 0x6f,
0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x73, 0x42, 0x05, 0x0a, 0x03, 0x73, 0x75, 0x6d, 0x22, 0x81,
0x02, 0x0a, 0x03, 0x46, 0x65, 0x65, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e,
0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69,
0x6e, 0x42, 0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73,
0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x43, 0x6f,
0x69, 0x6e, 0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x5f, 0x63,
0x6f, 0x69, 0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02,
0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x2e,
0x0a, 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2,
0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72,
0x22, 0xb6, 0x01, 0x0a, 0x03, 0x54, 0x69, 0x70, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43,
0x6f, 0x69, 0x6e, 0x42, 0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67, 0x69, 0x74,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63,
0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
0x43, 0x6f, 0x69, 0x6e, 0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61, 0x63, 0x79,
0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e,
0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x74,
0x69, 0x70, 0x70, 0x65, 0x72, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xce, 0x01, 0x0a, 0x0d, 0x41, 0x75,
0x78, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4,
0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
0x3e, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x64, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31,
0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44, 0x69, 0x72,
0x65, 0x63, 0x74, 0x41, 0x75, 0x78, 0x52, 0x07, 0x73, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x12,
0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e,
0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x69, 0x6e,
0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x6f,
0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x67, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x42, 0xb4, 0x01, 0x0a, 0x15, 0x63,
0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62,
0x65, 0x74, 0x61, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70,
0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x3b, 0x74, 0x78, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03,
0x43, 0x54, 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x54, 0x78, 0x2e,
0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1d, 0x43, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c,
0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13, 0x43, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x54, 0x78, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x05, 0x70, 0x61, 0x79, 0x65, 0x72, 0x12, 0x32,
0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42,
0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74,
0x65, 0x72, 0x22, 0xb6, 0x01, 0x0a, 0x03, 0x54, 0x69, 0x70, 0x12, 0x79, 0x0a, 0x06, 0x61, 0x6d,
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73,
0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31,
0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x46, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x28, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65,
0x73, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x9a, 0xe7, 0xb0, 0x2a, 0x0c, 0x6c, 0x65, 0x67, 0x61,
0x63, 0x79, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0xa8, 0xe7, 0xb0, 0x2a, 0x01, 0x52, 0x06, 0x61,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f,
0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52,
0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x3a, 0x02, 0x18, 0x01, 0x22, 0xce, 0x01, 0x0a, 0x0d,
0x41, 0x75, 0x78, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x32, 0x0a,
0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18,
0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x12, 0x3e, 0x0a, 0x08, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x64, 0x6f, 0x63, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e,
0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x44, 0x6f, 0x63, 0x44,
0x69, 0x72, 0x65, 0x63, 0x74, 0x41, 0x75, 0x78, 0x52, 0x07, 0x73, 0x69, 0x67, 0x6e, 0x44, 0x6f,
0x63, 0x12, 0x37, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x23, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e,
0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e,
0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69,
0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x73, 0x69, 0x67, 0x42, 0xb4, 0x01, 0x0a,
0x15, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76,
0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x07, 0x54, 0x78, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50,
0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f,
0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x74, 0x78, 0x2f, 0x76, 0x31,
0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x74, 0x78, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2,
0x02, 0x03, 0x43, 0x54, 0x58, 0xaa, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x54,
0x78, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x11, 0x43, 0x6f, 0x73, 0x6d,
0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x1d,
0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x54, 0x78, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61,
0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x13,
0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x54, 0x78, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65,
0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -9173,9 +9351,10 @@ var file_cosmos_tx_v1beta1_tx_proto_goTypes = []interface{}{
(*ModeInfo_Single)(nil), // 11: cosmos.tx.v1beta1.ModeInfo.Single
(*ModeInfo_Multi)(nil), // 12: cosmos.tx.v1beta1.ModeInfo.Multi
(*anypb.Any)(nil), // 13: google.protobuf.Any
(*v1beta12.Coin)(nil), // 14: cosmos.base.v1beta1.Coin
(v1beta1.SignMode)(0), // 15: cosmos.tx.signing.v1beta1.SignMode
(*v1beta11.CompactBitArray)(nil), // 16: cosmos.crypto.multisig.v1beta1.CompactBitArray
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
(*v1beta12.Coin)(nil), // 15: cosmos.base.v1beta1.Coin
(v1beta1.SignMode)(0), // 16: cosmos.tx.signing.v1beta1.SignMode
(*v1beta11.CompactBitArray)(nil), // 17: cosmos.crypto.multisig.v1beta1.CompactBitArray
}
var file_cosmos_tx_v1beta1_tx_proto_depIdxs = []int32{
4, // 0: cosmos.tx.v1beta1.Tx.body:type_name -> cosmos.tx.v1beta1.TxBody
@ -9183,27 +9362,28 @@ var file_cosmos_tx_v1beta1_tx_proto_depIdxs = []int32{
13, // 2: cosmos.tx.v1beta1.SignDocDirectAux.public_key:type_name -> google.protobuf.Any
9, // 3: cosmos.tx.v1beta1.SignDocDirectAux.tip:type_name -> cosmos.tx.v1beta1.Tip
13, // 4: cosmos.tx.v1beta1.TxBody.messages:type_name -> google.protobuf.Any
13, // 5: cosmos.tx.v1beta1.TxBody.extension_options:type_name -> google.protobuf.Any
13, // 6: cosmos.tx.v1beta1.TxBody.non_critical_extension_options:type_name -> google.protobuf.Any
6, // 7: cosmos.tx.v1beta1.AuthInfo.signer_infos:type_name -> cosmos.tx.v1beta1.SignerInfo
8, // 8: cosmos.tx.v1beta1.AuthInfo.fee:type_name -> cosmos.tx.v1beta1.Fee
9, // 9: cosmos.tx.v1beta1.AuthInfo.tip:type_name -> cosmos.tx.v1beta1.Tip
13, // 10: cosmos.tx.v1beta1.SignerInfo.public_key:type_name -> google.protobuf.Any
7, // 11: cosmos.tx.v1beta1.SignerInfo.mode_info:type_name -> cosmos.tx.v1beta1.ModeInfo
11, // 12: cosmos.tx.v1beta1.ModeInfo.single:type_name -> cosmos.tx.v1beta1.ModeInfo.Single
12, // 13: cosmos.tx.v1beta1.ModeInfo.multi:type_name -> cosmos.tx.v1beta1.ModeInfo.Multi
14, // 14: cosmos.tx.v1beta1.Fee.amount:type_name -> cosmos.base.v1beta1.Coin
14, // 15: cosmos.tx.v1beta1.Tip.amount:type_name -> cosmos.base.v1beta1.Coin
3, // 16: cosmos.tx.v1beta1.AuxSignerData.sign_doc:type_name -> cosmos.tx.v1beta1.SignDocDirectAux
15, // 17: cosmos.tx.v1beta1.AuxSignerData.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode
15, // 18: cosmos.tx.v1beta1.ModeInfo.Single.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode
16, // 19: cosmos.tx.v1beta1.ModeInfo.Multi.bitarray:type_name -> cosmos.crypto.multisig.v1beta1.CompactBitArray
7, // 20: cosmos.tx.v1beta1.ModeInfo.Multi.mode_infos:type_name -> cosmos.tx.v1beta1.ModeInfo
21, // [21:21] is the sub-list for method output_type
21, // [21:21] is the sub-list for method input_type
21, // [21:21] is the sub-list for extension type_name
21, // [21:21] is the sub-list for extension extendee
0, // [0:21] is the sub-list for field type_name
14, // 5: cosmos.tx.v1beta1.TxBody.timeout_timestamp:type_name -> google.protobuf.Timestamp
13, // 6: cosmos.tx.v1beta1.TxBody.extension_options:type_name -> google.protobuf.Any
13, // 7: cosmos.tx.v1beta1.TxBody.non_critical_extension_options:type_name -> google.protobuf.Any
6, // 8: cosmos.tx.v1beta1.AuthInfo.signer_infos:type_name -> cosmos.tx.v1beta1.SignerInfo
8, // 9: cosmos.tx.v1beta1.AuthInfo.fee:type_name -> cosmos.tx.v1beta1.Fee
9, // 10: cosmos.tx.v1beta1.AuthInfo.tip:type_name -> cosmos.tx.v1beta1.Tip
13, // 11: cosmos.tx.v1beta1.SignerInfo.public_key:type_name -> google.protobuf.Any
7, // 12: cosmos.tx.v1beta1.SignerInfo.mode_info:type_name -> cosmos.tx.v1beta1.ModeInfo
11, // 13: cosmos.tx.v1beta1.ModeInfo.single:type_name -> cosmos.tx.v1beta1.ModeInfo.Single
12, // 14: cosmos.tx.v1beta1.ModeInfo.multi:type_name -> cosmos.tx.v1beta1.ModeInfo.Multi
15, // 15: cosmos.tx.v1beta1.Fee.amount:type_name -> cosmos.base.v1beta1.Coin
15, // 16: cosmos.tx.v1beta1.Tip.amount:type_name -> cosmos.base.v1beta1.Coin
3, // 17: cosmos.tx.v1beta1.AuxSignerData.sign_doc:type_name -> cosmos.tx.v1beta1.SignDocDirectAux
16, // 18: cosmos.tx.v1beta1.AuxSignerData.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode
16, // 19: cosmos.tx.v1beta1.ModeInfo.Single.mode:type_name -> cosmos.tx.signing.v1beta1.SignMode
17, // 20: cosmos.tx.v1beta1.ModeInfo.Multi.bitarray:type_name -> cosmos.crypto.multisig.v1beta1.CompactBitArray
7, // 21: cosmos.tx.v1beta1.ModeInfo.Multi.mode_infos:type_name -> cosmos.tx.v1beta1.ModeInfo
22, // [22:22] is the sub-list for method output_type
22, // [22:22] is the sub-list for method input_type
22, // [22:22] is the sub-list for extension type_name
22, // [22:22] is the sub-list for extension extendee
0, // [0:22] is the sub-list for field type_name
}
func init() { file_cosmos_tx_v1beta1_tx_proto_init() }

View File

@ -21,7 +21,7 @@ import (
)
type (
// ValidatorStore defines the interface contract require for verifying vote
// ValidatorStore defines the interface contract required for verifying vote
// extension signatures. Typically, this will be implemented by the x/staking
// module, which has knowledge of the CometBFT public key.
ValidatorStore interface {
@ -83,7 +83,7 @@ func ValidateVoteExtensions(
totalVP += vote.Validator.Power
// Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the
// previous block (the block vote is for) could not have been committed.
// previous block (the block the vote is for) could not have been committed.
if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit {
continue
}
@ -286,35 +286,41 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
invalidTxs []sdk.Tx // invalid txs to be removed out of the loop to avoid dead lock
)
mempool.SelectBy(ctx, h.mempool, req.Txs, func(memTx sdk.Tx) bool {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}
// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
unorderedTx, ok := memTx.(sdk.TxWithUnordered)
isUnordered := ok && unorderedTx.GetUnordered()
txSignersSeqs := make(map[string]uint64)
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue
// if the tx is unordered, we don't need to check the sequence, we just add it
if !isUnordered {
signerData, err := h.signerExtAdapter.GetSigners(memTx)
if err != nil {
// propagate the error to the caller
resError = err
return false
}
// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
// If the signers aren't in selectedTxsSignersSeqs then we haven't seen them before
// so we add them and continue given that we don't need to check the sequence.
shouldAdd := true
for _, signer := range signerData {
seq, ok := selectedTxsSignersSeqs[signer.Signer.String()]
if !ok {
txSignersSeqs[signer.Signer.String()] = signer.Sequence
continue
}
// If we have seen this signer before in this block, we must make
// sure that the current sequence is seq+1; otherwise is invalid
// and we skip it.
if seq+1 != signer.Sequence {
shouldAdd = false
break
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}
txSignersSeqs[signer.Signer.String()] = signer.Sequence
}
if !shouldAdd {
return true
}
// NOTE: Since transaction verification was already executed in CheckTx,
@ -331,18 +337,21 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan
}
txsLen := len(h.txSelector.SelectedTxs(ctx))
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
// If the tx is unordered, we don't need to update the sender sequence.
if !isUnordered {
for sender, seq := range txSignersSeqs {
// If txsLen != selectedTxsNums is true, it means that we've
// added a new tx to the selected txs, so we need to update
// the sequence of the sender.
if txsLen != selectedTxsNums {
selectedTxsSignersSeqs[sender] = seq
} else if _, ok := selectedTxsSignersSeqs[sender]; !ok {
// The transaction hasn't been added but it passed the
// verification, so we know that the sequence is correct.
// So we set this sender's sequence to seq-1, in order
// to avoid unnecessary calls to PrepareProposalVerifyTx.
selectedTxsSignersSeqs[sender] = seq - 1
}
}
}
selectedTxsNums = txsLen

View File

@ -85,7 +85,6 @@ func TestBaseApp_BlockGas(t *testing.T) {
configurator.NewAppConfig(
configurator.AuthModule(),
configurator.TxModule(),
configurator.ParamsModule(),
configurator.ConsensusModule(),
configurator.BankModule(),
configurator.StakingModule(),
@ -115,12 +114,13 @@ func TestBaseApp_BlockGas(t *testing.T) {
genState := GenesisStateWithSingleValidator(t, cdc, appBuilder)
stateBytes, err := cmtjson.MarshalIndent(genState, "", " ")
require.NoError(t, err)
bapp.InitChain(&abci.RequestInitChain{
_, err = bapp.InitChain(&abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simtestutil.DefaultConsensusParams,
AppStateBytes: stateBytes,
})
require.NoError(t, err)
ctx := bapp.NewContext(false)
// tx fee

View File

@ -74,6 +74,8 @@ const (
FlagOffset = "offset"
FlagCountTotal = "count-total"
FlagTimeoutHeight = "timeout-height"
FlagTimeoutTimestamp = "timeout-timestamp"
FlagUnordered = "unordered"
FlagKeyAlgorithm = "algo"
FlagKeyType = "key-type"
FlagFeePayer = "fee-payer"
@ -135,7 +137,9 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
f.Bool(FlagOffline, false, "Offline mode (does not allow any online functionality)")
f.BoolP(FlagSkipConfirmation, "y", false, "Skip tx broadcasting prompt confirmation")
f.String(FlagSignMode, "", "Choose sign mode (direct|amino-json|direct-aux|textual), this is an advanced feature")
f.Uint64(FlagTimeoutHeight, 0, "Set a block timeout height to prevent the tx from being committed past a certain height")
f.Uint64(FlagTimeoutHeight, 0, "DEPRECATED: Please use --timeout-timestamp instead. Set a block timeout height to prevent the tx from being committed past a certain height")
f.Int64(FlagTimeoutTimestamp, 0, "Set a block timeout timestamp to prevent the tx from being committed past a certain time")
f.Bool(FlagUnordered, false, "Enable unordered transaction delivery; must be used in conjunction with --timeout-timestamp")
f.String(FlagFeePayer, "", "Fee payer pays fees for the transaction instead of deducting from the signer")
f.String(FlagFeeGranter, "", "Fee granter grants fees for the transaction")
f.String(FlagTip, "", "Tip is the amount that is going to be transferred to the fee payer on the target chain. This flag is only valid when used with --aux, and is ignored if the target chain didn't enable the TipDecorator")
@ -145,6 +149,9 @@ func AddTxFlagsToCmd(cmd *cobra.Command) {
f.String(FlagGas, "", fmt.Sprintf("gas limit to set per-transaction; set to %q to calculate sufficient gas automatically. Note: %q option doesn't always report accurate results. Set a valid coin value to adjust the result. Can be used instead of %q. (default %d)",
GasFlagAuto, GasFlagAuto, FlagFees, DefaultGasLimit))
cmd.MarkFlagsMutuallyExclusive(FlagTimeoutHeight, FlagTimeoutTimestamp)
cmd.MarkFlagsRequiredTogether(FlagUnordered, FlagTimeoutTimestamp)
AddKeyringFlags(f)
}

View File

@ -2,9 +2,11 @@ package tx
import (
"context"
"time"
"github.com/cosmos/gogoproto/proto"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb"
txv1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1"
txsigning "cosmossdk.io/x/tx/signing"
@ -58,6 +60,14 @@ func (b *AuxTxBuilder) SetTimeoutHeight(height uint64) {
b.auxSignerData.SignDoc.BodyBytes = nil
}
// SetTimeoutTimestamp sets a timeout timestamp in the tx.
func (b *AuxTxBuilder) SetTimeoutTimestamp(timestamp time.Time) {
b.checkEmptyFields()
b.body.TimeoutTimestamp = timestamppb.New(timestamp)
b.auxSignerData.SignDoc.BodyBytes = nil
}
// SetMsgs sets an array of Msgs in the tx.
func (b *AuxTxBuilder) SetMsgs(msgs ...sdk.Msg) error {
anys := make([]*anypb.Any, len(msgs))
@ -209,9 +219,10 @@ func (b *AuxTxBuilder) GetSignBytes() ([]byte, error) {
})
auxBody := &txv1beta1.TxBody{
Messages: body.Messages,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
Messages: body.Messages,
Memo: body.Memo,
TimeoutHeight: body.TimeoutHeight,
TimeoutTimestamp: body.TimeoutTimestamp,
// AuxTxBuilder has no concern with extension options, so we set them to nil.
// This preserves pre-PR#16025 behavior where extension options were ignored, this code path:
// https://github.com/cosmos/cosmos-sdk/blob/ac3c209326a26b46f65a6cc6f5b5ebf6beb79b38/client/tx/aux_builder.go#L193

View File

@ -3,8 +3,10 @@ package tx
import (
"errors"
"fmt"
"math/big"
"os"
"strings"
"time"
"github.com/cosmos/go-bip39"
"github.com/spf13/pflag"
@ -32,9 +34,11 @@ type Factory struct {
sequence uint64
gas uint64
timeoutHeight uint64
timeoutTimestamp time.Time
gasAdjustment float64
chainID string
fromName string
unordered bool
offline bool
generateOnly bool
memo string
@ -50,6 +54,14 @@ type Factory struct {
// NewFactoryCLI creates a new Factory.
func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, error) {
if clientCtx.Viper == nil {
clientCtx = clientCtx.WithViper("")
}
if err := clientCtx.Viper.BindPFlags(flagSet); err != nil {
return Factory{}, fmt.Errorf("failed to bind flags to viper: %w", err)
}
signMode := signing.SignMode_SIGN_MODE_UNSPECIFIED
switch clientCtx.SignModeStr {
case flags.SignModeDirect:
@ -67,18 +79,21 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
var accNum, accSeq uint64
if clientCtx.Offline {
if flagSet.Changed(flags.FlagAccountNumber) && flagSet.Changed(flags.FlagSequence) {
accNum, _ = flagSet.GetUint64(flags.FlagAccountNumber)
accSeq, _ = flagSet.GetUint64(flags.FlagSequence)
accNum = clientCtx.Viper.GetUint64(flags.FlagAccountNumber)
accSeq = clientCtx.Viper.GetUint64(flags.FlagSequence)
} else {
return Factory{}, errors.New("account-number and sequence must be set in offline mode")
}
}
gasAdj, _ := flagSet.GetFloat64(flags.FlagGasAdjustment)
memo, _ := flagSet.GetString(flags.FlagNote)
timeoutHeight, _ := flagSet.GetUint64(flags.FlagTimeoutHeight)
gasAdj := clientCtx.Viper.GetFloat64(flags.FlagGasAdjustment)
memo := clientCtx.Viper.GetString(flags.FlagNote)
timestampUnix := clientCtx.Viper.GetInt64(flags.FlagTimeoutTimestamp)
timeoutTimestamp := time.Unix(timestampUnix, 0)
timeoutHeight := clientCtx.Viper.GetUint64(flags.FlagTimeoutHeight)
unordered := clientCtx.Viper.GetBool(flags.FlagUnordered)
gasStr, _ := flagSet.GetString(flags.FlagGas)
gasStr := clientCtx.Viper.GetString(flags.FlagGas)
gasSetting, _ := flags.ParseGasSetting(gasStr)
f := Factory{
@ -94,6 +109,8 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
accountNumber: accNum,
sequence: accSeq,
timeoutHeight: timeoutHeight,
timeoutTimestamp: timeoutTimestamp,
unordered: unordered,
gasAdjustment: gasAdj,
memo: memo,
signMode: signMode,
@ -101,10 +118,10 @@ func NewFactoryCLI(clientCtx client.Context, flagSet *pflag.FlagSet) (Factory, e
feePayer: clientCtx.FeePayer,
}
feesStr, _ := flagSet.GetString(flags.FlagFees)
feesStr := clientCtx.Viper.GetString(flags.FlagFees)
f = f.WithFees(feesStr)
gasPricesStr, _ := flagSet.GetString(flags.FlagGasPrices)
gasPricesStr := clientCtx.Viper.GetString(flags.FlagGasPrices)
f = f.WithGasPrices(gasPricesStr)
f = f.WithPreprocessTxHook(clientCtx.PreprocessTxHook)
@ -123,6 +140,8 @@ func (f Factory) Fees() sdk.Coins { return f.fees }
func (f Factory) GasPrices() sdk.DecCoins { return f.gasPrices }
func (f Factory) AccountRetriever() client.AccountRetriever { return f.accountRetriever }
func (f Factory) TimeoutHeight() uint64 { return f.timeoutHeight }
func (f Factory) TimeoutTimestamp() time.Time { return f.timeoutTimestamp }
func (f Factory) Unordered() bool { return f.unordered }
func (f Factory) FromName() string { return f.fromName }
// SimulateAndExecute returns the option to simulate and then execute the transaction
@ -236,6 +255,18 @@ func (f Factory) WithTimeoutHeight(height uint64) Factory {
return f
}
// WithTimeoutTimestamp returns a copy of the Factory with an updated timeout timestamp.
func (f Factory) WithTimeoutTimestamp(timestamp time.Time) Factory {
f.timeoutTimestamp = timestamp
return f
}
// WithUnordered returns a copy of the Factory with an updated unordered field.
func (f Factory) WithUnordered(v bool) Factory {
f.unordered = v
return f
}
// WithFeeGranter returns a copy of the Factory with an updated fee granter.
func (f Factory) WithFeeGranter(fg sdk.AccAddress) Factory {
f.feeGranter = fg
@ -311,14 +342,16 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
return nil, errors.New("cannot provide both fees and gas prices")
}
glDec := math.LegacyNewDec(int64(f.gas))
// f.gas is a uint64 and we should convert to LegacyDec
// without the risk of under/overflow via uint64->int64.
gasLimitDec := math.LegacyNewDecFromBigInt(new(big.Int).SetUint64(f.gas))
// Derive the fees based on the provided gas prices, where
// fee = ceil(gasPrice * gasLimit).
fees = make(sdk.Coins, len(f.gasPrices))
for i, gp := range f.gasPrices {
fee := gp.Amount.Mul(glDec)
fee := gp.Amount.Mul(gasLimitDec)
fees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
}
}
@ -340,6 +373,8 @@ func (f Factory) BuildUnsignedTx(msgs ...sdk.Msg) (client.TxBuilder, error) {
tx.SetFeeGranter(f.feeGranter)
tx.SetFeePayer(f.feePayer)
tx.SetTimeoutHeight(f.TimeoutHeight())
tx.SetTimeoutTimestamp(f.TimeoutTimestamp())
tx.SetUnordered(f.Unordered())
if etx, ok := tx.(client.ExtendedTxBuilder); ok {
etx.SetExtensionOptions(f.extOptions...)
@ -482,7 +517,7 @@ func (f Factory) Prepare(clientCtx client.Context) (Factory, error) {
}
fc := f
from := clientCtx.GetFromAddress()
from := clientCtx.FromAddress
if err := fc.accountRetriever.EnsureExists(clientCtx, from); err != nil {
return fc, err

View File

@ -1,6 +1,8 @@
package client
import (
"time"
txsigning "cosmossdk.io/x/tx/signing"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@ -48,6 +50,8 @@ type (
SetFeePayer(feePayer sdk.AccAddress)
SetGasLimit(limit uint64)
SetTimeoutHeight(height uint64)
SetTimeoutTimestamp(timestamp time.Time)
SetUnordered(v bool)
SetFeeGranter(feeGranter sdk.AccAddress)
AddAuxSignerData(tx.AuxSignerData) error
}

View File

@ -0,0 +1,337 @@
# ADR 070: Unordered Transactions
## Changelog
* Dec 4, 2023: Initial Draft (@yihuang, @tac0turtle, @alexanderbez)
* Jan 30, 2024: Include section on deterministic transaction encoding
## Status
ACCEPTED
## Abstract
We propose a way to do replay-attack protection without enforcing the order of
transactions, without requiring the use of nonces. In this way, we can support
un-ordered transaction inclusion.
## Context
As of today, the nonce value (account sequence number) prevents replay-attack and
ensures the transactions from the same sender are included into blocks and executed
in sequential order. However it makes it tricky to send many transactions from the
same sender concurrently in a reliable way. IBC relayer and crypto exchanges are
typical examples of such use cases.
## Decision
We propose to add a boolean field `unordered` to transaction body to mark "un-ordered"
transactions.
Un-ordered transactions will bypass the nonce rules and follow the rules described
below instead, in contrary, the default ordered transactions are not impacted by
this proposal, they'll follow the nonce rules the same as before.
When an un-ordered transaction is included into a block, the transaction hash is
recorded in a dictionary. New transactions are checked against this dictionary for
duplicates, and to prevent the dictionary grow indefinitely, the transaction must
specify `timeout_timestamp` for expiration, so it's safe to removed it from the
dictionary after it's expired.
The dictionary can be simply implemented as an in-memory golang map, a preliminary
analysis shows that the memory consumption won't be too big, for example `32M = 32 * 1024 * 1024`
can support 1024 blocks where each block contains 1024 unordered transactions. For
safety, we should limit the range of `timeout_timestamp` to prevent very long expiration,
and limit the size of the dictionary.
### Transaction Format
```protobuf
message TxBody {
...
bool unordered = 4;
}
```
### Replay Protection
In order to provide replay protection, a user should ensure that the transaction's
TTL value is relatively short-lived but long enough to provide enough time to be
included in a block, e.g. ~10 minutes.
We facilitate this by storing the transaction's hash in a durable map, `UnorderedTxManager`,
to prevent duplicates, i.e. replay attacks. Upon transaction ingress during `CheckTx`,
we check if the transaction's hash exists in this map or if the TTL value is stale,
i.e. before the current block time. If so, we reject it. Upon inclusion in a block
during `DeliverTx`, the transaction's hash is set in the map along with it's TTL
value.
This map is evaluated at the end of each block, e.g. ABCI `Commit`, and all stale
transactions, i.e. transactions's TTL value who's now beyond the committed block,
are purged from the map.
An important point to note is that in theory, it may be possible to submit an unordered
transaction twice, or multiple times, before the transaction is included in a block.
However, we'll note a few important layers of protection and mitigation:
* Assuming CometBFT is used as the underlying consensus engine and a non-noop mempool
is used, CometBFT will reject the duplicate for you.
* For applications that leverage ABCI++, `ProcessProposal` should evaluate and reject
malicious proposals with duplicate transactions.
* For applications that leverage their own application mempool, their mempool should
reject the duplicate for you.
* Finally, worst case if the duplicate transaction is somehow selected for a block
proposal, 2nd and all further attempts to evaluate it, will fail during `DeliverTx`,
so worst case you just end up filling up block space with a duplicate transaction.
```golang
type TxHash [32]byte
const PurgeLoopSleepMS = 500
// UnorderedTxManager contains the tx hash dictionary for duplicates checking,
// and expire them when block production progresses.
type UnorderedTxManager struct {
// blockCh defines a channel to receive newly committed block time
blockCh chan time.Time
mu sync.RWMutex
// txHashes defines a map from tx hash -> TTL value, which is used for duplicate
// checking and replay protection, as well as purging the map when the TTL is
// expired.
txHashes map[TxHash]time.Time
}
func NewUnorderedTxManager() *UnorderedTxManager {
m := &UnorderedTxManager{
blockCh: make(chan time.Time, 16),
txHashes: make(map[TxHash]time.Time),
}
return m
}
func (m *UnorderedTxManager) Start() {
go m.purgeLoop()
}
func (m *UnorderedTxManager) Close() error {
close(m.blockCh)
m.blockCh = nil
return nil
}
func (m *UnorderedTxManager) Contains(hash TxHash) bool{
m.mu.RLock()
defer m.mu.RUnlock()
_, ok := m.txHashes[hash]
return ok
}
func (m *UnorderedTxManager) Size() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.txHashes)
}
func (m *UnorderedTxManager) Add(hash TxHash, expire time.Time) {
m.mu.Lock()
defer m.mu.Unlock()
m.txHashes[hash] = expire
}
// OnNewBlock send the latest block time to the background purge loop, which
// should be called in ABCI Commit event.
func (m *UnorderedTxManager) OnNewBlock(blockTime time.Time) {
m.blockCh <- blockTime
}
// expiredTxs returns expired tx hashes based on the provided block time.
func (m *UnorderedTxManager) expiredTxs(blockTime time.Time) []TxHash {
m.mu.RLock()
defer m.mu.RUnlock()
var result []TxHash
for txHash, expire := range m.txHashes {
if blockTime.After(expire) {
result = append(result, txHash)
}
}
return result
}
func (m *UnorderedTxManager) purge(txHashes []TxHash) {
m.mu.Lock()
defer m.mu.Unlock()
for _, txHash := range txHashes {
delete(m.txHashes, txHash)
}
}
// purgeLoop removes expired tx hashes in the background
func (m *UnorderedTxManager) purgeLoop() error {
for {
latestTime, ok := m.batchReceive()
if !ok {
// channel closed
return
}
hashes := m.expiredTxs(latestTime)
if len(hashes) > 0 {
m.purge(hashes)
}
}
}
// channelBatchRecv try to exhaust the channel buffer when it's not empty,
// and block when it's empty.
func channelBatchRecv[T any](ch <-chan *T) []*T {
item := <-ch // block if channel is empty
if item == nil {
// channel is closed
return nil
}
remaining := len(ch)
result := make([]*T, 0, remaining+1)
result = append(result, item)
for i := 0; i < remaining; i++ {
result = append(result, <-ch)
}
return result
}
```
### AnteHandler Decorator
In order to facilitate bypassing nonce verification, we have to modify the existing
`IncrementSequenceDecorator` AnteHandler decorator to skip the nonce verification
when the transaction is marked as un-ordered.
```golang
func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if tx.UnOrdered() {
return next(ctx, tx, simulate)
}
// ...
}
```
In addition, we need to introduce a new decorator to perform the un-ordered transaction
verification and map lookup.
```golang
const (
// DefaultMaxTimeoutDuration defines the default maximum duration an un-ordered transaction
// can set.
DefaultMaxTimeoutDuration = time.Minute * 40
)
type DedupTxDecorator struct {
m *UnorderedTxManager
maxTimeoutDuration time.Time
}
func (d *DedupTxDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
// only apply to un-ordered transactions
if !tx.UnOrdered() {
return next(ctx, tx, simulate)
}
headerInfo := d.env.HeaderService.HeaderInfo(ctx)
timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp()
if timeoutTimestamp.IsZero() || timeoutTimestamp.Unix() == 0 {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction must have timeout_timestamp set")
}
if timeoutTimestamp.Before(headerInfo.Time) {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "unordered transaction has a timeout_timestamp that has already passed")
}
if timeoutTimestamp.After(headerInfo.Time.Add(d.maxTimeoutDuration)) {
return ctx, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unordered tx ttl exceeds %s", d.maxTimeoutDuration.String())
}
// in order to create a deterministic hash based on the tx, we need to hash the contents of the tx with signature
// Get a Buffer from the pool
buf := bufPool.Get().(*bytes.Buffer)
// Make sure to reset the buffer
buf.Reset()
// Use the buffer
for _, msg := range tx.GetMsgs() {
// loop through the messages and write them to the buffer
// encoding the msg to bytes makes it deterministic within the state machine.
// Malleability is not a concern here because the state machine will encode the transaction deterministically.
bz, err := proto.Marshal(msg)
if err != nil {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "failed to marshal message")
}
buf.Write(bz)
}
// check for duplicates
// check for duplicates
if d.txManager.Contains(txHash) {
return ctx, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "tx %X is duplicated")
}
if d.env.TransactionService.ExecMode(ctx) == transaction.ExecModeFinalize {
// a new tx included in the block, add the hash to the unordered tx manager
d.txManager.Add(txHash, ttl)
}
return next(ctx, tx, simulate)
}
```
### Transaction Hashes
It is absolutely vital that transaction hashes are deterministic, i.e. transaction
encoding is not malleable. If a given transaction, which is otherwise valid, can
be encoded to produce different hashes, which reflect the same valid transaction,
then a duplicate unordered transaction can be submitted and included in a block.
In order to prevent this, the decoded transaction contents is taken. Starting with the content of the transaction we marshal the transaction in order to prevent a client reordering the transaction. Next we include the gas and timeout timestamp as part of the identifier. All these fields are signed over in the transaction payload. If one of them changes the signature will not match the transaction.
### State Management
On start up, the node needs to ensure the TxManager's state contains all un-expired
transactions that have been committed to the chain. This is critical since if the
state is not properly initialized, the node will not reject duplicate transactions
and thus will not provide replay protection, and will likely get an app hash mismatch error.
We propose to write all un-expired unordered transactions from the TxManager's to
file on disk. On start up, the node will read this file and re-populate the TxManager's
map. The write to file will happen when the node gracefully shuts down on `Close()`.
Note, this is not a perfect solution, in the context of store v1. With store v2,
we can omit explicit file handling altogether and simply write the all the transactions
to non-consensus state, i.e State Storage (SS).
Alternatively, we can write all the transactions to consensus state.
## Consequences
### Positive
* Support un-ordered and concurrent transaction inclusion.
### Negative
* Requires additional storage overhead and management of processed unordered
transactions that exist outside of consensus state.
## References
* https://github.com/cosmos/cosmos-sdk/issues/13009

View File

@ -8,6 +8,7 @@ import "cosmos/base/v1beta1/coin.proto";
import "cosmos/tx/signing/v1beta1/signing.proto";
import "google/protobuf/any.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/timestamp.proto";
option go_package = "github.com/cosmos/cosmos-sdk/types/tx";
@ -105,13 +106,33 @@ message TxBody {
// memo is any arbitrary note/comment to be added to the transaction.
// WARNING: in clients, any publicly exposed text should not be called memo,
// but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122).
// but should be called `note` instead (see
// https://github.com/cosmos/cosmos-sdk/issues/9122).
string memo = 2;
// timeout is the block height after which this transaction will not
// be processed by the chain
// timeout_height is the block height after which this transaction will not
// be processed by the chain.
uint64 timeout_height = 3;
// unordered, when set to true, indicates that the transaction signer(s)
// intend for the transaction to be evaluated and executed in an un-ordered
// fashion. Specifically, the account's nonce will NOT be checked or
// incremented, which allows for fire-and-forget as well as concurrent
// transaction execution.
//
// Note, when set to true, the existing 'timeout_timestamp' value must
// be set and will be used to correspond to a timestamp in which the transaction is deemed
// valid.
bool unordered = 4;
// timeout_timestamp is the block time after which this transaction will not
// be processed by the chain.
//
// Note, if unordered=true this value MUST be set
// and will act as a short-lived TTL in which the transaction is deemed valid
// and kept in memory to prevent duplicates.
google.protobuf.Timestamp timeout_timestamp = 5 [(gogoproto.nullable) = true, (gogoproto.stdtime) = true];
// extension_options are arbitrary options that can be added by chains
// when the default options are not sufficient. If any of these are present
// and can't be handled, the transaction will be rejected
@ -211,14 +232,16 @@ message Fee {
// before an out of gas error occurs
uint64 gas_limit = 2;
// if unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees.
// the payer must be a tx signer (and thus have signed this field in AuthInfo).
// setting this field does *not* change the ordering of required signers for the transaction.
// if unset, the first signer is responsible for paying the fees. If set, the
// specified account must pay the fees. the payer must be a tx signer (and
// thus have signed this field in AuthInfo). setting this field does *not*
// change the ordering of required signers for the transaction.
string payer = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used
// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does
// not support fee grants, this will fail
// if set, the fee payer (either the first signer or the value of the payer
// field) requests that a fee grant be used to pay fees instead of the fee
// payer's own balance. If an appropriate fee grant does not exist or the
// chain does not support fee grants, this will fail
string granter = 4 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

View File

@ -25,6 +25,7 @@ import (
servertypes "github.com/cosmos/cosmos-sdk/server/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)
@ -40,7 +41,9 @@ import (
type App struct {
*baseapp.BaseApp
ModuleManager *module.Manager
ModuleManager *module.Manager
UnorderedTxManager *unorderedtx.Manager
configurator module.Configurator
config *runtimev1alpha1.Module
storeKeys []storetypes.StoreKey
@ -157,6 +160,9 @@ func (a *App) Load(loadLatest bool) error {
// PreBlocker application updates every pre block
func (a *App) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
if a.UnorderedTxManager != nil {
a.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
}
return a.ModuleManager.PreBlock(ctx)
}

View File

@ -2,6 +2,9 @@
set -e -o pipefail
LINT_TAGS="e2e,ledger,test_ledger_mock,system_test"
export LINT_TAGS
REPO_ROOT="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )/.." &> /dev/null && pwd )"
export REPO_ROOT
@ -10,7 +13,7 @@ lint_module() {
shift
cd "$(dirname "$root")" &&
echo "linting $(grep "^module" go.mod) [$(date -Iseconds -u)]" &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ --build-tags=${LINT_TAGS}
}
export -f lint_module
@ -31,7 +34,7 @@ else
for f in $(dirname $(echo "$GIT_DIFF" | tr -d "'") | uniq); do
echo "linting $f [$(date -Iseconds -u)]" &&
cd $f &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ --build-tags=${LINT_TAGS} &&
cd $REPO_ROOT
done
fi

View File

@ -2,6 +2,10 @@
set -e -o pipefail
LINT_TAGS="e2e,ledger,test_ledger_mock,system_test"
export LINT_TAGS
REPO_ROOT="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )/.." &> /dev/null && pwd )"
export REPO_ROOT
@ -10,7 +14,7 @@ lint_module() {
shift
cd "$(dirname "$root")" &&
echo "linting $(grep "^module" go.mod) [$(date -Iseconds -u)]" &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ --build-tags=${LINT_TAGS}
}
export -f lint_module
@ -31,7 +35,7 @@ else
for f in $(dirname $(echo "$GIT_DIFF" | tr -d "'") | uniq); do
echo "linting $f [$(date -Iseconds -u)]" &&
cd $f &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ &&
golangci-lint run ./... -c "${REPO_ROOT}/.golangci.yml" "$@" --new-from-rev=HEAD~ --build-tags=${LINT_TAGS} &&
cd $REPO_ROOT
done
fi

View File

@ -7,6 +7,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
)
// HandlerOptions are the options required for constructing a default SDK AnteHandler.
@ -47,5 +48,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
}
if options.UnorderedTxManager != nil {
anteDecorators = append(anteDecorators, ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.UnorderedTxManager, ante.DefaultSha256GasCost))
}
return sdk.ChainAnteDecorators(anteDecorators...), nil
}

View File

@ -7,6 +7,12 @@ import (
"fmt"
"io"
"os"
"path/filepath"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cast"
autocliv1 "cosmossdk.io/api/cosmos/autocli/v1"
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
@ -31,10 +37,6 @@ import (
"cosmossdk.io/x/upgrade"
upgradekeeper "cosmossdk.io/x/upgrade/keeper"
upgradetypes "cosmossdk.io/x/upgrade/types"
abci "github.com/cometbft/cometbft/abci/types"
dbm "github.com/cosmos/cosmos-db"
"github.com/cosmos/gogoproto/proto"
"github.com/spf13/cast"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
@ -59,6 +61,7 @@ import (
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
authcodec "github.com/cosmos/cosmos-sdk/x/auth/codec"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
"github.com/cosmos/cosmos-sdk/x/auth/posthandler"
@ -163,6 +166,8 @@ type SimApp struct {
ModuleManager *module.Manager
BasicModuleManager module.BasicManager
UnorderedTxManager *unorderedtx.Manager
// simulation manager
sm *module.SimulationManager
@ -373,7 +378,7 @@ func NewSimApp(
app.GovKeeper = *govKeeper.SetHooks(
govtypes.NewMultiGovHooks(
// register the governance hooks
// register the governance hooks
),
)
@ -525,6 +530,25 @@ func NewSimApp(
}
app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules)
// create, start, and load the unordered tx manager
utxDataDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data")
app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir)
app.UnorderedTxManager.Start()
if err := app.UnorderedTxManager.OnInit(); err != nil {
panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err))
}
// register custom snapshot extensions (if any)
if manager := app.SnapshotManager(); manager != nil {
err := manager.RegisterExtensions(
unorderedtx.NewSnapshotter(app.UnorderedTxManager),
)
if err != nil {
panic(fmt.Errorf("failed to register snapshot extension: %s", err))
}
}
app.sm.RegisterStoreDecoders()
// initialize stores
@ -578,11 +602,12 @@ func (app *SimApp) setAnteHandler(txConfig client.TxConfig) {
anteHandler, err := NewAnteHandler(
HandlerOptions{
ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
UnorderedTxManager: app.UnorderedTxManager,
},
&app.CircuitKeeper,
},
@ -606,11 +631,18 @@ func (app *SimApp) setPostHandler() {
app.SetPostHandler(postHandler)
}
// Close implements the Application interface and closes all necessary application
// resources.
func (app *SimApp) Close() error {
return app.UnorderedTxManager.Close()
}
// Name returns the name of the App
func (app *SimApp) Name() string { return app.BaseApp.Name() }
// PreBlocker application updates every pre block
func (app *SimApp) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) {
app.UnorderedTxManager.OnNewBlock(ctx.BlockTime())
return app.ModuleManager.PreBlock(ctx)
}

View File

@ -3,9 +3,12 @@
package simapp
import (
"fmt"
"io"
"path/filepath"
dbm "github.com/cosmos/cosmos-db"
"github.com/spf13/cast"
clienthelpers "cosmossdk.io/client/v2/helpers"
"cosmossdk.io/depinject"
@ -19,6 +22,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/runtime"
@ -30,6 +34,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -63,6 +68,8 @@ type SimApp struct {
txConfig client.TxConfig
interfaceRegistry codectypes.InterfaceRegistry
UnorderedTxManager *unorderedtx.Manager
// keepers
AccountKeeper authkeeper.AccountKeeper
BankKeeper bankkeeper.Keeper
@ -243,9 +250,6 @@ func NewSimApp(
app.sm.RegisterStoreDecoders()
// set custom ante handler
app.setAnteHandler(app.txConfig)
// A custom InitChainer can be set if extra pre-init-genesis logic is required.
// By default, when using app wiring enabled module, this is not required.
// For instance, the upgrade module will set automatically the module version map in its init genesis thanks to app wiring.
@ -257,6 +261,28 @@ func NewSimApp(
// return app.App.InitChainer(ctx, req)
// })
// create, start, and load the unordered tx manager
utxDataDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data")
app.UnorderedTxManager = unorderedtx.NewManager(utxDataDir)
app.UnorderedTxManager.Start()
if err := app.UnorderedTxManager.OnInit(); err != nil {
panic(fmt.Errorf("failed to initialize unordered tx manager: %w", err))
}
// register custom snapshot extensions (if any)
if manager := app.SnapshotManager(); manager != nil {
err := manager.RegisterExtensions(
unorderedtx.NewSnapshotter(app.UnorderedTxManager),
)
if err != nil {
panic(fmt.Errorf("failed to register snapshot extension: %w", err))
}
}
// set custom ante handler
app.setAnteHandler(app.txConfig)
if err := app.Load(loadLatest); err != nil {
panic(err)
}
@ -270,11 +296,12 @@ func (app *SimApp) setAnteHandler(txConfig client.TxConfig) {
anteHandler, err := NewAnteHandler(
HandlerOptions{
ante.HandlerOptions{
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
SignModeHandler: txConfig.SignModeHandler(),
FeegrantKeeper: app.FeeGrantKeeper,
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
UnorderedTxManager: app.UnorderedTxManager,
},
&app.CircuitKeeper,
},

View File

@ -22,7 +22,6 @@ import (
client "github.com/cometbft/cometbft/rpc/client/http"
ctypes "github.com/cometbft/cometbft/rpc/core/types"
tmtypes "github.com/cometbft/cometbft/types"
"github.com/creachadair/tomledit"
"github.com/stretchr/testify/require"
"github.com/tidwall/sjson"
@ -733,14 +732,6 @@ func (s *SystemUnderTest) AddFullnode(t *testing.T, beforeStart ...func(nodeNumb
configFile := filepath.Join(configPath, tomlFile)
_ = os.Remove(configFile)
_ = MustCopyFile(filepath.Join(WorkDir, s.nodePath(0), "config", tomlFile), configFile)
if tomlFile == "app.toml" && IsV2() {
file := filepath.Join(WorkDir, s.nodePath(nodeNumber), "config", tomlFile)
EditToml(file, func(doc *tomledit.Document) {
SetValue(doc, fmt.Sprintf("%s:%d", node.IP, DefaultApiPort+nodeNumber), "grpc-gateway", "address")
SetValue(doc, fmt.Sprintf("%s:%d", node.IP, DefaultRestPort+nodeNumber), "rest", "address")
SetValue(doc, fmt.Sprintf("%s:%d", node.IP, DefaultTelemetryPort+nodeNumber), "telemetry", "address")
})
}
}
peers := make([]string, len(allNodes)-1)
for i, n := range allNodes[0 : len(allNodes)-1] {

View File

@ -13,12 +13,6 @@ import (
"github.com/creachadair/tomledit/parser"
)
// IsV2 checks if the tests run with simapp v2
func IsV2() bool {
buildOptions := os.Getenv("COSMOS_BUILD_OPTIONS")
return strings.Contains(buildOptions, "v2")
}
// SingleHostTestnetCmdInitializer default testnet cmd that supports the --single-host param
type SingleHostTestnetCmdInitializer struct {
execBinary string
@ -75,12 +69,7 @@ func (s SingleHostTestnetCmdInitializer) Initialize() {
"--keyring-backend=test",
"--commit-timeout=" + s.commitTimeout.String(),
"--single-host",
}
if IsV2() {
args = append(args, "--server.minimum-gas-prices="+s.minGasPrice)
} else {
args = append(args, "--minimum-gas-prices="+s.minGasPrice)
"--minimum-gas-prices=" + s.minGasPrice,
}
s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")))
@ -127,12 +116,7 @@ func (s ModifyConfigYamlInitializer) Initialize() {
"--output-dir=" + s.outputDir,
"--v=" + strconv.Itoa(s.initialNodesCount),
"--keyring-backend=test",
}
if IsV2() {
args = append(args, "--server.minimum-gas-prices="+s.minGasPrice)
} else {
args = append(args, "--minimum-gas-prices="+s.minGasPrice)
"--minimum-gas-prices=" + s.minGasPrice,
}
s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " ")))

View File

@ -5,7 +5,7 @@ WAIT_TIME ?= 45s
all: test format
test:
go test -mod=readonly -failfast -timeout=15m -tags='system_test' ./... --wait-time=$(WAIT_TIME)
go test -mod=readonly -failfast -timeout=15m -tags='system_test' ./... --wait-time=$(WAIT_TIME) --verbose
format:
find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" -not -path "./client/lcd/statik/statik.go" | xargs gofumpt -w

View File

@ -4,6 +4,11 @@ go 1.23.0
toolchain go1.24.0
replace (
cosmossdk.io/api => ../../api
cosmossdk.io/systemtests => ../../systemtests
)
require (
github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect
github.com/cosmos/cosmos-sdk v0.50.12 // indirect
@ -31,8 +36,6 @@ require (
)
require (
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.4-20241120201313-68e42a58b301.1 // indirect
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.4-20240130113600-88ef6483f90f.1 // indirect
cosmossdk.io/api v0.8.2 // indirect
cosmossdk.io/collections v0.4.0 // indirect
cosmossdk.io/core v0.11.0 // indirect
@ -92,7 +95,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
@ -158,14 +161,14 @@ require (
golang.org/x/arch v0.13.0 // indirect
golang.org/x/crypto v0.35.0 // indirect
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/net v0.35.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4 // indirect
google.golang.org/protobuf v1.36.4 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gotest.tools/v3 v3.5.1 // indirect
@ -173,5 +176,3 @@ require (
pgregory.net/rapid v1.1.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
replace cosmossdk.io/systemtests => ../../systemtests

View File

@ -1,11 +1,5 @@
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.4-20241120201313-68e42a58b301.1 h1:lcvKfPJ0GTMLh1Ib9n9b3Hx/U2lXj27rb5pujo3EKko=
buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.4-20241120201313-68e42a58b301.1/go.mod h1:dW1kItnxv+SgI6SBjokdyIZqKl2uhOJahkOqIXDNDC8=
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.4-20240130113600-88ef6483f90f.1 h1:xn+yVpC5XMvaSQWjfRWmitcYemPznXR7Y65rIMTxoiU=
buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.4-20240130113600-88ef6483f90f.1/go.mod h1:9oTVKh0Ppx5zXStsybi9Zb//6TuLreQxSZqBDE25JGo=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cosmossdk.io/api v0.8.2 h1:klzA1RODd9tTawJ2CbBd/34RV/cB9qtd9oJN6rcRqqg=
cosmossdk.io/api v0.8.2/go.mod h1:XJUwQrihIDjErzs3+jm1zO/9KRzKf4HMjRzXC+l+Cio=
cosmossdk.io/collections v0.4.0 h1:PFmwj2W8szgpD5nOd8GWH6AbYNi1f2J6akWXJ7P5t9s=
cosmossdk.io/collections v0.4.0/go.mod h1:oa5lUING2dP+gdDquow+QjlF45eL1t4TJDypgGd+tv0=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=
@ -344,8 +338,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@ -845,8 +839,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -975,10 +969,10 @@ google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY=
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo=
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E=
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4 h1:yrTuav+chrF0zF/joFGICKTzYv7mh/gr9AgEXrVU8ao=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250122153221-138b5a5a4fd4/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk=
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
@ -1013,8 +1007,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -1,3 +1,5 @@
//go:build system_test
package systemtests
import (

View File

@ -1,3 +1,5 @@
//go:build system_test
package systemtests
import (

View File

@ -0,0 +1,54 @@
//go:build system_test
package systemtests
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
systest "cosmossdk.io/systemtests"
)
func TestUnorderedTXDuplicate(t *testing.T) {
// scenario: test unordered tx duplicate
// given a running chain with a tx in the unordered tx pool
// when a new tx with the same hash is broadcasted
// then the new tx should be rejected
systest.Sut.ResetChain(t)
cli := systest.NewCLIWrapper(t, systest.Sut, systest.Verbose)
// add genesis account with some tokens
account1Addr := cli.AddKey("account1")
account2Addr := cli.AddKey("account2")
systest.Sut.ModifyGenesisCLI(t,
[]string{"genesis", "add-genesis-account", account1Addr, "10000000stake"},
)
systest.Sut.StartChain(t)
timeoutTimestamp := time.Now().Add(time.Minute)
// send tokens
cmd := []string{"tx", "bank", "send", account1Addr, account2Addr, "5000stake", "--from=" + account1Addr, "--fees=1stake", fmt.Sprintf("--timeout-timestamp=%v", timeoutTimestamp.Unix()), "--unordered", "--sequence=1", "--note=1"}
rsp1 := cli.Run(cmd...)
systest.RequireTxSuccess(t, rsp1)
assertDuplicateErr := func(xt assert.TestingT, gotErr error, gotOutputs ...interface{}) bool {
require.Len(t, gotOutputs, 1)
output := gotOutputs[0].(string)
code := gjson.Get(output, "code")
require.True(t, code.Exists())
require.Equal(t, int64(19), code.Int()) // 19 == already in mempool.
return false // always abort
}
rsp2 := cli.WithRunErrorMatcher(assertDuplicateErr).Run(cmd...)
systest.RequireTxFailure(t, rsp2)
require.Eventually(t, func() bool {
return cli.QueryBalance(account2Addr, "stake") == 5000
}, 10*systest.Sut.BlockTime(), 200*time.Millisecond, "TX was not executed before timeout")
}

View File

@ -290,7 +290,7 @@ message TestUpdatedTxBody {
repeated google.protobuf.Any messages = 1;
string memo = 2;
int64 timeout_height = 3;
uint64 some_new_field = 4;
uint64 some_new_field = 5;
string some_new_field_non_critical_field = 1050;
repeated google.protobuf.Any extension_options = 1023;
repeated google.protobuf.Any non_critical_extension_options = 2047;

View File

@ -23036,7 +23036,7 @@ func (x *fastReflection_TestUpdatedTxBody) ProtoMethods() *protoiface.Methods {
if x.SomeNewField != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.SomeNewField))
i--
dAtA[i] = 0x20
dAtA[i] = 0x28
}
if x.TimeoutHeight != 0 {
i = runtime.EncodeVarint(dAtA, i, uint64(x.TimeoutHeight))
@ -23200,7 +23200,7 @@ func (x *fastReflection_TestUpdatedTxBody) ProtoMethods() *protoiface.Methods {
break
}
}
case 4:
case 5:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SomeNewField", wireType)
}
@ -26508,7 +26508,7 @@ type TestUpdatedTxBody struct {
Messages []*anypb.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"`
Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"`
TimeoutHeight int64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"`
SomeNewField uint64 `protobuf:"varint,4,opt,name=some_new_field,json=someNewField,proto3" json:"some_new_field,omitempty"`
SomeNewField uint64 `protobuf:"varint,5,opt,name=some_new_field,json=someNewField,proto3" json:"some_new_field,omitempty"`
SomeNewFieldNonCriticalField string `protobuf:"bytes,1050,opt,name=some_new_field_non_critical_field,json=someNewFieldNonCriticalField,proto3" json:"some_new_field_non_critical_field,omitempty"`
ExtensionOptions []*anypb.Any `protobuf:"bytes,1023,rep,name=extension_options,json=extensionOptions,proto3" json:"extension_options,omitempty"`
NonCriticalExtensionOptions []*anypb.Any `protobuf:"bytes,2047,rep,name=non_critical_extension_options,json=nonCriticalExtensionOptions,proto3" json:"non_critical_extension_options,omitempty"`
@ -27410,7 +27410,7 @@ var file_testpb_unknonwnproto_proto_rawDesc = []byte{
0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, 0x20, 0x01,
0x28, 0x03, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68,
0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x6e, 0x65, 0x77, 0x5f, 0x66, 0x69,
0x65, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x73, 0x6f, 0x6d, 0x65, 0x4e,
0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x73, 0x6f, 0x6d, 0x65, 0x4e,
0x65, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x48, 0x0a, 0x21, 0x73, 0x6f, 0x6d, 0x65, 0x5f,
0x6e, 0x65, 0x77, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72,
0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x9a, 0x08, 0x20,

View File

@ -2578,7 +2578,7 @@ type TestUpdatedTxBody struct {
Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"`
Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"`
TimeoutHeight int64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"`
SomeNewField uint64 `protobuf:"varint,4,opt,name=some_new_field,json=someNewField,proto3" json:"some_new_field,omitempty"`
SomeNewField uint64 `protobuf:"varint,5,opt,name=some_new_field,json=someNewField,proto3" json:"some_new_field,omitempty"`
SomeNewFieldNonCriticalField string `protobuf:"bytes,1050,opt,name=some_new_field_non_critical_field,json=someNewFieldNonCriticalField,proto3" json:"some_new_field_non_critical_field,omitempty"`
ExtensionOptions []*types.Any `protobuf:"bytes,1023,rep,name=extension_options,json=extensionOptions,proto3" json:"extension_options,omitempty"`
NonCriticalExtensionOptions []*types.Any `protobuf:"bytes,2047,rep,name=non_critical_extension_options,json=nonCriticalExtensionOptions,proto3" json:"non_critical_extension_options,omitempty"`
@ -2906,7 +2906,7 @@ var fileDescriptor_fe4560133be9209a = []byte{
0x1a, 0x5f, 0x6a, 0x70, 0x6d, 0xc5, 0x85, 0x3e, 0x73, 0x17, 0xf8, 0x0e, 0x14, 0x66, 0x84, 0x73,
0x7b, 0xac, 0x3c, 0xd0, 0x36, 0xa6, 0x56, 0x82, 0x92, 0xd5, 0x3c, 0x23, 0x33, 0x16, 0x57, 0xb3,
0x1c, 0x4b, 0x13, 0x84, 0x37, 0x23, 0x2c, 0x10, 0x83, 0x09, 0xf1, 0xc6, 0x13, 0x11, 0xf1, 0x78,
0x25, 0x92, 0x1e, 0x2a, 0x21, 0x7e, 0x1f, 0xca, 0x9c, 0xcd, 0xc8, 0x60, 0x79, 0x6d, 0xca, 0xaa,
0x25, 0x92, 0x1e, 0x2a, 0x21, 0x7e, 0x1f, 0xca, 0x9c, 0xcd, 0xc8, 0x60, 0x79, 0x6d, 0xca, 0xa9,
0x6b, 0x53, 0x49, 0x4a, 0x8f, 0x22, 0x63, 0xf1, 0x21, 0xfc, 0x60, 0x15, 0x35, 0x58, 0xd3, 0x82,
0x7f, 0x17, 0xb6, 0xe0, 0xf7, 0xd2, 0x3b, 0x8f, 0x5e, 0x6f, 0xc7, 0x7d, 0xb8, 0x46, 0xe6, 0x82,
0x50, 0x99, 0x23, 0x03, 0xa6, 0x3e, 0xe5, 0x72, 0xfd, 0xdf, 0xbb, 0xe7, 0xb8, 0x59, 0x49, 0xf0,
@ -2921,7 +2921,7 @@ var fileDescriptor_fe4560133be9209a = []byte{
0x3c, 0x7f, 0x55, 0xdb, 0xf9, 0xeb, 0xab, 0xda, 0xce, 0x67, 0xcd, 0xb1, 0x27, 0x26, 0xc1, 0xb0,
0xe9, 0xb0, 0x59, 0x2b, 0xfa, 0xc8, 0x1f, 0xfe, 0xdd, 0xe6, 0xee, 0x71, 0x4b, 0x56, 0x7d, 0x20,
0xbc, 0xa9, 0x1a, 0xb8, 0xb6, 0xb0, 0x87, 0x79, 0x45, 0x74, 0xe7, 0x3f, 0x01, 0x00, 0x00, 0xff,
0xff, 0x3a, 0xea, 0x0d, 0xa7, 0x67, 0x18, 0x00, 0x00,
0xff, 0x33, 0x3d, 0xcf, 0x3a, 0x67, 0x18, 0x00, 0x00,
}
func (m *Customer1) Marshal() (dAtA []byte, err error) {
@ -5261,7 +5261,7 @@ func (m *TestUpdatedTxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) {
if m.SomeNewField != 0 {
i = encodeVarintUnknonwnproto(dAtA, i, uint64(m.SomeNewField))
i--
dAtA[i] = 0x20
dAtA[i] = 0x28
}
if m.TimeoutHeight != 0 {
i = encodeVarintUnknonwnproto(dAtA, i, uint64(m.TimeoutHeight))
@ -12602,7 +12602,7 @@ func (m *TestUpdatedTxBody) Unmarshal(dAtA []byte) error {
break
}
}
case 4:
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field SomeNewField", wireType)
}

View File

@ -142,4 +142,8 @@ var (
// ErrPanic should only be set when we recovering from a panic
ErrPanic = errorsmod.ErrPanic
// ErrTxTimeout defines an error for when a tx is rejected out due to an
// explicitly set timeout timestamp.
ErrTxTimeout = errorsmod.Register(RootCodespace, 42, "tx timeout")
)

View File

@ -4,6 +4,7 @@ import (
"fmt"
"math/rand"
"testing"
"time"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/stretchr/testify/require"
@ -52,6 +53,21 @@ type testTx struct {
address sdk.AccAddress
// useful for debugging
strAddress string
unordered bool
timeout *time.Time
}
// GetTimeoutTimeStamp implements types.TxWithUnordered.
func (tx testTx) GetTimeoutTimeStamp() time.Time {
if tx.timeout == nil {
return time.Time{}
}
return *tx.timeout
}
// GetUnordered implements types.TxWithUnordered.
func (tx testTx) GetUnordered() bool {
return tx.unordered
}
func (tx testTx) GetSigners() ([][]byte, error) { panic("not implemented") }

View File

@ -2,6 +2,7 @@ package mempool
import (
"context"
"errors"
"fmt"
"math"
"sync"
@ -222,6 +223,16 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error
sender := sig.Signer.String()
priority := mp.cfg.TxPriority.GetTxPriority(ctx, tx)
nonce := sig.Sequence
// if it's an unordered tx, we use the timeout timestamp instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
timestamp := unordered.GetTimeoutTimeStamp().Unix()
if timestamp < 0 {
return errors.New("invalid timestamp value")
}
nonce = uint64(timestamp)
}
key := txMeta[C]{nonce: nonce, priority: priority, sender: sender}
senderIndex, ok := mp.senderIndices[sender]
@ -458,6 +469,15 @@ func (mp *PriorityNonceMempool[C]) Remove(tx sdk.Tx) error {
sender := sig.Signer.String()
nonce := sig.Sequence
// if it's an unordered tx, we use the timeout timestamp instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
timestamp := unordered.GetTimeoutTimeStamp().Unix()
if timestamp < 0 {
return errors.New("invalid timestamp value")
}
nonce = uint64(timestamp)
}
scoreKey := txMeta[C]{nonce: nonce, sender: sender}
score, ok := mp.scores[scoreKey]
if !ok {

View File

@ -976,3 +976,40 @@ func TestNextSenderTx_TxReplacement(t *testing.T) {
iter := mp.Select(ctx, nil)
require.Equal(t, txs[3], iter.Tx())
}
func TestPriorityNonceMempool_UnorderedTx(t *testing.T) {
ctx := sdk.NewContext(nil, cmtproto.Header{}, false, log.NewNopLogger())
accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 2)
sa := accounts[0].Address
sb := accounts[1].Address
mp := mempool.DefaultPriorityMempool()
now := time.Now()
oneHour := now.Add(1 * time.Hour)
thirtyMin := now.Add(30 * time.Minute)
twoHours := now.Add(2 * time.Hour)
fifteenMin := now.Add(15 * time.Minute)
txs := []testTx{
{id: 1, priority: 0, address: sa, timeout: &thirtyMin, unordered: true},
{id: 0, priority: 0, address: sa, timeout: &oneHour, unordered: true},
{id: 3, priority: 0, address: sb, timeout: &fifteenMin, unordered: true},
{id: 2, priority: 0, address: sb, timeout: &twoHours, unordered: true},
}
for _, tx := range txs {
c := ctx.WithPriority(tx.priority)
require.NoError(t, mp.Insert(c, tx))
}
require.Equal(t, 4, mp.CountTx())
orderedTxs := fetchTxs(mp.Select(ctx, nil), 100000)
require.Equal(t, len(txs), len(orderedTxs))
// check order
for i, tx := range orderedTxs {
require.Equal(t, txs[i].id, tx.(testTx).id)
}
}

View File

@ -4,6 +4,7 @@ import (
"context"
crand "crypto/rand" // #nosec // crypto/rand is used for seed generation
"encoding/binary"
"errors"
"fmt"
"math/rand" // #nosec // math/rand is used for random selection and seeded from crypto/rand
"sync"
@ -139,6 +140,15 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error {
sender := sdk.AccAddress(sig.PubKey.Address()).String()
nonce := sig.Sequence
// if it's an unordered tx, we use the timeout timestamp instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
timestamp := unordered.GetTimeoutTimeStamp().Unix()
if timestamp < 0 {
return errors.New("invalid timestamp value")
}
nonce = uint64(timestamp)
}
senderTxs, found := snm.senders[sender]
if !found {
senderTxs = skiplist.New(skiplist.Uint64)
@ -227,6 +237,15 @@ func (snm *SenderNonceMempool) Remove(tx sdk.Tx) error {
sender := sdk.AccAddress(sig.PubKey.Address()).String()
nonce := sig.Sequence
// if it's an unordered tx, we use the timeout timestamp instead of the nonce
if unordered, ok := tx.(sdk.TxWithUnordered); ok && unordered.GetUnordered() {
timestamp := unordered.GetTimeoutTimeStamp().Unix()
if timestamp < 0 {
return errors.New("invalid timestamp value")
}
nonce = uint64(timestamp)
}
senderTxs, found := snm.senders[sender]
if !found {
return ErrTxNotFound

View File

@ -4,6 +4,7 @@ import (
"fmt"
"math/rand"
"testing"
"time"
cmtproto "github.com/cometbft/cometbft/proto/tendermint/types"
"github.com/stretchr/testify/require"
@ -193,3 +194,67 @@ func (s *MempoolTestSuite) TestTxNotFoundOnSender() {
err = mp.Remove(tx)
require.Equal(t, mempool.ErrTxNotFound, err)
}
func (s *MempoolTestSuite) TestUnorderedTx() {
t := s.T()
ctx := sdk.NewContext(nil, cmtproto.Header{}, false, log.NewNopLogger())
accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 2)
sa := accounts[0].Address
sb := accounts[1].Address
mp := mempool.NewSenderNonceMempool(mempool.SenderNonceMaxTxOpt(5000))
now := time.Now()
oneHour := now.Add(1 * time.Hour)
thirtyMin := now.Add(30 * time.Minute)
twoHours := now.Add(2 * time.Hour)
fifteenMin := now.Add(15 * time.Minute)
txs := []testTx{
{id: 0, address: sa, timeout: &oneHour, unordered: true},
{id: 1, address: sa, timeout: &thirtyMin, unordered: true},
{id: 2, address: sb, timeout: &twoHours, unordered: true},
{id: 3, address: sb, timeout: &fifteenMin, unordered: true},
}
for _, tx := range txs {
c := ctx.WithPriority(tx.priority)
require.NoError(t, mp.Insert(c, tx))
}
require.Equal(t, 4, mp.CountTx())
orderedTxs := fetchTxs(mp.Select(ctx, nil), 100000)
require.Equal(t, len(txs), len(orderedTxs))
// Because the sender is selected randomly it can be any of these options
acceptableOptions := [][]int{
{3, 1, 2, 0},
{3, 1, 0, 2},
{3, 2, 1, 0},
{1, 3, 0, 2},
{1, 3, 2, 0},
{1, 0, 3, 2},
}
orderedTxsIds := make([]int, len(orderedTxs))
for i, tx := range orderedTxs {
orderedTxsIds[i] = tx.(testTx).id
}
anyAcceptableOrder := false
for _, option := range acceptableOptions {
for i, tx := range orderedTxs {
if tx.(testTx).id != txs[option[i]].id {
break
}
if i == len(orderedTxs)-1 {
anyAcceptableOrder = true
}
}
}
require.True(t, anyAcceptableOrder, "expected any of %v but got %v", acceptableOptions, orderedTxsIds)
}

View File

@ -14,15 +14,19 @@ import (
signing "github.com/cosmos/cosmos-sdk/types/tx/signing"
_ "github.com/cosmos/gogoproto/gogoproto"
proto "github.com/cosmos/gogoproto/proto"
github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types"
_ "google.golang.org/protobuf/types/known/timestamppb"
io "io"
math "math"
math_bits "math/bits"
time "time"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
var _ = time.Kitchen
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
@ -356,11 +360,29 @@ type TxBody struct {
Messages []*types.Any `protobuf:"bytes,1,rep,name=messages,proto3" json:"messages,omitempty"`
// memo is any arbitrary note/comment to be added to the transaction.
// WARNING: in clients, any publicly exposed text should not be called memo,
// but should be called `note` instead (see https://github.com/cosmos/cosmos-sdk/issues/9122).
// but should be called `note` instead (see
// https://github.com/cosmos/cosmos-sdk/issues/9122).
Memo string `protobuf:"bytes,2,opt,name=memo,proto3" json:"memo,omitempty"`
// timeout is the block height after which this transaction will not
// be processed by the chain
// timeout_height is the block height after which this transaction will not
// be processed by the chain.
TimeoutHeight uint64 `protobuf:"varint,3,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"`
// unordered, when set to true, indicates that the transaction signer(s)
// intend for the transaction to be evaluated and executed in an un-ordered
// fashion. Specifically, the account's nonce will NOT be checked or
// incremented, which allows for fire-and-forget as well as concurrent
// transaction execution.
//
// Note, when set to true, the existing 'timeout_timestamp' value must
// be set and will be used to correspond to a timestamp in which the transaction is deemed
// valid.
Unordered bool `protobuf:"varint,4,opt,name=unordered,proto3" json:"unordered,omitempty"`
// timeout_timestamp is the block time after which this transaction will not
// be processed by the chain.
//
// Note, if unordered=true this value MUST be set
// and will act as a short-lived TTL in which the transaction is deemed valid
// and kept in memory to prevent duplicates.
TimeoutTimestamp *time.Time `protobuf:"bytes,5,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3,stdtime" json:"timeout_timestamp,omitempty"`
// extension_options are arbitrary options that can be added by chains
// when the default options are not sufficient. If any of these are present
// and can't be handled, the transaction will be rejected
@ -425,6 +447,20 @@ func (m *TxBody) GetTimeoutHeight() uint64 {
return 0
}
func (m *TxBody) GetUnordered() bool {
if m != nil {
return m.Unordered
}
return false
}
func (m *TxBody) GetTimeoutTimestamp() *time.Time {
if m != nil {
return m.TimeoutTimestamp
}
return nil
}
func (m *TxBody) GetExtensionOptions() []*types.Any {
if m != nil {
return m.ExtensionOptions
@ -789,13 +825,15 @@ type Fee struct {
// gas_limit is the maximum gas that can be used in transaction processing
// before an out of gas error occurs
GasLimit uint64 `protobuf:"varint,2,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
// if unset, the first signer is responsible for paying the fees. If set, the specified account must pay the fees.
// the payer must be a tx signer (and thus have signed this field in AuthInfo).
// setting this field does *not* change the ordering of required signers for the transaction.
// if unset, the first signer is responsible for paying the fees. If set, the
// specified account must pay the fees. the payer must be a tx signer (and
// thus have signed this field in AuthInfo). setting this field does *not*
// change the ordering of required signers for the transaction.
Payer string `protobuf:"bytes,3,opt,name=payer,proto3" json:"payer,omitempty"`
// if set, the fee payer (either the first signer or the value of the payer field) requests that a fee grant be used
// to pay fees instead of the fee payer's own balance. If an appropriate fee grant does not exist or the chain does
// not support fee grants, this will fail
// if set, the fee payer (either the first signer or the value of the payer
// field) requests that a fee grant be used to pay fees instead of the fee
// payer's own balance. If an appropriate fee grant does not exist or the
// chain does not support fee grants, this will fail
Granter string `protobuf:"bytes,4,opt,name=granter,proto3" json:"granter,omitempty"`
}
@ -1020,74 +1058,77 @@ func init() {
func init() { proto.RegisterFile("cosmos/tx/v1beta1/tx.proto", fileDescriptor_96d1575ffde80842) }
var fileDescriptor_96d1575ffde80842 = []byte{
// 1059 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0x41, 0x6f, 0x1b, 0x45,
0x14, 0xf6, 0x7a, 0x6d, 0xc7, 0x7e, 0x4d, 0xda, 0x64, 0x14, 0x21, 0xc7, 0x51, 0xdd, 0xe0, 0xaa,
0x60, 0x55, 0x64, 0xb7, 0x4d, 0x0f, 0x94, 0x0a, 0x01, 0x76, 0x43, 0x94, 0xaa, 0x14, 0xa4, 0x4d,
0x4e, 0xbd, 0xac, 0xc6, 0xeb, 0xc9, 0x7a, 0x54, 0xef, 0xcc, 0xb2, 0x33, 0x0b, 0xde, 0x23, 0x3f,
0x00, 0xa9, 0x42, 0x42, 0x48, 0x9c, 0x39, 0x20, 0x4e, 0x3d, 0x20, 0x7e, 0x43, 0x4f, 0xa8, 0xe2,
0xc4, 0x09, 0xaa, 0xe4, 0xd0, 0x3b, 0x7f, 0x00, 0x34, 0xb3, 0xb3, 0x9b, 0xb4, 0xa4, 0x4e, 0x11,
0x48, 0x5c, 0xec, 0x99, 0xb7, 0xdf, 0x7b, 0xf3, 0xbd, 0x37, 0xdf, 0xbc, 0x07, 0x9d, 0x80, 0x8b,
0x88, 0x0b, 0x57, 0xce, 0xdc, 0xcf, 0xae, 0x8f, 0x88, 0xc4, 0xd7, 0x5d, 0x39, 0x73, 0xe2, 0x84,
0x4b, 0x8e, 0x56, 0xf2, 0x6f, 0x8e, 0x9c, 0x39, 0xe6, 0x5b, 0x67, 0x05, 0x47, 0x94, 0x71, 0x57,
0xff, 0xe6, 0xa8, 0xce, 0x6a, 0xc8, 0x43, 0xae, 0x97, 0xae, 0x5a, 0x19, 0xeb, 0xa6, 0x89, 0x1b,
0x24, 0x59, 0x2c, 0xb9, 0x1b, 0xa5, 0x53, 0x49, 0x05, 0x0d, 0xcb, 0x43, 0x0a, 0x83, 0x81, 0x77,
0x0d, 0x7c, 0x84, 0x05, 0x29, 0x31, 0x01, 0xa7, 0xcc, 0x7c, 0x7f, 0xf3, 0x98, 0xa6, 0xa0, 0x21,
0xa3, 0xec, 0x38, 0x92, 0xd9, 0x1b, 0xe0, 0x5a, 0xc8, 0x79, 0x38, 0x25, 0xae, 0xde, 0x8d, 0xd2,
0x03, 0x17, 0xb3, 0xac, 0xf8, 0x94, 0xc7, 0xf0, 0x73, 0xae, 0x26, 0x37, 0xbd, 0xe9, 0x7d, 0x69,
0x41, 0x75, 0x7f, 0x86, 0x36, 0xa1, 0x36, 0xe2, 0xe3, 0xac, 0x6d, 0x6d, 0x58, 0xfd, 0x73, 0x5b,
0x6b, 0xce, 0xdf, 0xf2, 0x77, 0xf6, 0x67, 0x43, 0x3e, 0xce, 0x3c, 0x0d, 0x43, 0x37, 0xa1, 0x85,
0x53, 0x39, 0xf1, 0x29, 0x3b, 0xe0, 0xed, 0xaa, 0xf6, 0x59, 0x3f, 0xc5, 0x67, 0x90, 0xca, 0xc9,
0x1d, 0x76, 0xc0, 0xbd, 0x26, 0x36, 0x2b, 0xd4, 0x05, 0x50, 0xb4, 0xb1, 0x4c, 0x13, 0x22, 0xda,
0xf6, 0x86, 0xdd, 0x5f, 0xf4, 0x4e, 0x58, 0x7a, 0x0c, 0xea, 0xfb, 0x33, 0x0f, 0x7f, 0x8e, 0x2e,
0x02, 0xa8, 0xa3, 0xfc, 0x51, 0x26, 0x89, 0xd0, 0xbc, 0x16, 0xbd, 0x96, 0xb2, 0x0c, 0x95, 0x01,
0xbd, 0x01, 0x17, 0x4a, 0x06, 0x06, 0x53, 0xd5, 0x98, 0xa5, 0xe2, 0xa8, 0x1c, 0x77, 0xd6, 0x79,
0x5f, 0x59, 0xb0, 0xb0, 0x47, 0x43, 0xb6, 0xcd, 0x83, 0xff, 0xea, 0xc8, 0x35, 0x68, 0x06, 0x13,
0x4c, 0x99, 0x4f, 0xc7, 0x6d, 0x7b, 0xc3, 0xea, 0xb7, 0xbc, 0x05, 0xbd, 0xbf, 0x33, 0x46, 0x57,
0xe0, 0x3c, 0x0e, 0x02, 0x9e, 0x32, 0xe9, 0xb3, 0x34, 0x1a, 0x91, 0xa4, 0x5d, 0xdb, 0xb0, 0xfa,
0x35, 0x6f, 0xc9, 0x58, 0x3f, 0xd6, 0xc6, 0xde, 0x1f, 0x16, 0x2c, 0x1b, 0x52, 0xdb, 0x34, 0x21,
0x81, 0x1c, 0xa4, 0xb3, 0xb3, 0xd8, 0xdd, 0x00, 0x88, 0xd3, 0xd1, 0x94, 0x06, 0xfe, 0x03, 0x92,
0x99, 0x3b, 0x59, 0x75, 0x72, 0x4d, 0x38, 0x85, 0x26, 0x9c, 0x01, 0xcb, 0xbc, 0x56, 0x8e, 0xbb,
0x4b, 0xb2, 0x7f, 0x4f, 0x15, 0x75, 0xa0, 0x29, 0xc8, 0xa7, 0x29, 0x61, 0x01, 0x69, 0xd7, 0x35,
0xa0, 0xdc, 0xa3, 0xb7, 0xc0, 0x96, 0x34, 0x6e, 0x37, 0x34, 0x97, 0xd7, 0x4e, 0xd3, 0x14, 0x8d,
0x87, 0xd5, 0xb6, 0xe5, 0x29, 0x58, 0xef, 0xeb, 0x2a, 0x34, 0x72, 0x91, 0xa1, 0x6b, 0xd0, 0x8c,
0x88, 0x10, 0x38, 0xd4, 0x89, 0xda, 0x2f, 0xcd, 0xa4, 0x44, 0x21, 0x04, 0xb5, 0x88, 0x44, 0xb9,
0x16, 0x5b, 0x9e, 0x5e, 0xab, 0x0c, 0x24, 0x8d, 0x08, 0x4f, 0xa5, 0x3f, 0x21, 0x34, 0x9c, 0x48,
0x9d, 0x62, 0xcd, 0x5b, 0x32, 0xd6, 0x5d, 0x6d, 0x44, 0x43, 0x58, 0x21, 0x33, 0x49, 0x98, 0xa0,
0x9c, 0xf9, 0x3c, 0x96, 0x94, 0x33, 0xd1, 0xfe, 0x73, 0x61, 0xce, 0xb1, 0xcb, 0x25, 0xfe, 0x93,
0x1c, 0x8e, 0xee, 0x43, 0x97, 0x71, 0xe6, 0x07, 0x09, 0x95, 0x34, 0xc0, 0x53, 0xff, 0x94, 0x80,
0x17, 0xe6, 0x04, 0x5c, 0x67, 0x9c, 0xdd, 0x36, 0xbe, 0x1f, 0xbe, 0x10, 0xbb, 0xf7, 0x9d, 0x05,
0xcd, 0xe2, 0x21, 0xa1, 0x0f, 0x60, 0x51, 0x89, 0x97, 0x24, 0x5a, 0x85, 0x45, 0x75, 0x2e, 0x9e,
0x52, 0xdb, 0x3d, 0x0d, 0xd3, 0xaf, 0xef, 0x9c, 0x28, 0xd7, 0x02, 0xf5, 0xc1, 0x3e, 0x20, 0xc4,
0x08, 0xe4, 0xb4, 0x4b, 0xd9, 0x21, 0xc4, 0x53, 0x90, 0xe2, 0xfa, 0xec, 0x57, 0xbb, 0xbe, 0x6f,
0x2c, 0x80, 0xe3, 0x33, 0x5f, 0x90, 0xa3, 0xf5, 0x6a, 0x72, 0xbc, 0x09, 0xad, 0x88, 0x8f, 0xc9,
0x59, 0x6d, 0xe5, 0x1e, 0x1f, 0x93, 0xbc, 0xad, 0x44, 0x66, 0xf5, 0x9c, 0x0c, 0xed, 0xe7, 0x65,
0xd8, 0x7b, 0x5a, 0x85, 0x66, 0xe1, 0x82, 0xde, 0x85, 0x86, 0xa0, 0x2c, 0x9c, 0x12, 0xc3, 0xa9,
0x37, 0x27, 0xbe, 0xb3, 0xa7, 0x91, 0xbb, 0x15, 0xcf, 0xf8, 0xa0, 0x77, 0xa0, 0xae, 0xdb, 0xb7,
0x21, 0xf7, 0xfa, 0x3c, 0xe7, 0x7b, 0x0a, 0xb8, 0x5b, 0xf1, 0x72, 0x8f, 0xce, 0x00, 0x1a, 0x79,
0x38, 0xf4, 0x36, 0xd4, 0x14, 0x6f, 0x4d, 0xe0, 0xfc, 0xd6, 0xe5, 0x13, 0x31, 0x8a, 0x86, 0x7e,
0xf2, 0x0e, 0x55, 0x3c, 0x4f, 0x3b, 0x74, 0x1e, 0x5a, 0x50, 0xd7, 0x51, 0xd1, 0x5d, 0x68, 0x8e,
0xa8, 0xc4, 0x49, 0x82, 0x8b, 0xda, 0xba, 0x45, 0x98, 0x7c, 0xec, 0x38, 0xe5, 0x94, 0x29, 0x62,
0xdd, 0xe6, 0x51, 0x8c, 0x03, 0x39, 0xa4, 0x72, 0xa0, 0xdc, 0xbc, 0x32, 0x00, 0xba, 0x05, 0x50,
0x56, 0x5d, 0xb5, 0x34, 0xfb, 0xac, 0xb2, 0xb7, 0x8a, 0xb2, 0x8b, 0x61, 0x1d, 0x6c, 0x91, 0x46,
0xbd, 0x2f, 0xaa, 0x60, 0xef, 0x10, 0x82, 0x32, 0x68, 0xe0, 0x48, 0x75, 0x07, 0x23, 0xcc, 0x72,
0x90, 0xa8, 0xe9, 0x76, 0x82, 0x0a, 0x65, 0xc3, 0x9d, 0xc7, 0xbf, 0x5d, 0xaa, 0xfc, 0xf0, 0xfb,
0xa5, 0x7e, 0x48, 0xe5, 0x24, 0x1d, 0x39, 0x01, 0x8f, 0xdc, 0x62, 0x72, 0xea, 0xbf, 0x4d, 0x31,
0x7e, 0xe0, 0xca, 0x2c, 0x26, 0x42, 0x3b, 0x88, 0x6f, 0x9f, 0x3d, 0xba, 0xba, 0x38, 0x25, 0x21,
0x0e, 0x32, 0x5f, 0xcd, 0x47, 0xf1, 0xfd, 0xb3, 0x47, 0x57, 0x2d, 0xcf, 0x1c, 0x88, 0xd6, 0xa1,
0x15, 0x62, 0xe1, 0x4f, 0x69, 0x44, 0xa5, 0xbe, 0x9e, 0x9a, 0xd7, 0x0c, 0xb1, 0xf8, 0x48, 0xed,
0x91, 0x03, 0xf5, 0x18, 0x67, 0x24, 0xc9, 0x9b, 0xdc, 0xb0, 0xfd, 0xcb, 0x8f, 0x9b, 0xab, 0x86,
0xd9, 0x60, 0x3c, 0x4e, 0x88, 0x10, 0x7b, 0x32, 0xa1, 0x2c, 0xf4, 0x72, 0x18, 0xda, 0x82, 0x85,
0x30, 0xc1, 0x4c, 0x9a, 0xae, 0x37, 0xcf, 0xa3, 0x00, 0xf6, 0x7e, 0xb2, 0xc0, 0xde, 0xa7, 0xf1,
0xff, 0x59, 0x83, 0x6b, 0xd0, 0x90, 0x34, 0x8e, 0x49, 0x92, 0xf7, 0xc1, 0x39, 0xac, 0x0d, 0xee,
0x56, 0xb5, 0x6d, 0xf5, 0x7e, 0xb6, 0x60, 0x69, 0x90, 0xce, 0xf2, 0xc7, 0xbb, 0x8d, 0x25, 0x56,
0xe9, 0xe3, 0x1c, 0xae, 0xd5, 0x35, 0x37, 0x7d, 0x03, 0x44, 0xef, 0x41, 0x53, 0xc9, 0xd7, 0x1f,
0xf3, 0xc0, 0xbc, 0x8e, 0xcb, 0x2f, 0xe9, 0x4a, 0x27, 0xa7, 0x9a, 0xb7, 0x20, 0xcc, 0xf0, 0x2d,
0x5e, 0x85, 0xfd, 0x0f, 0x5f, 0x05, 0x5a, 0x06, 0x5b, 0xd0, 0x50, 0xdf, 0xd3, 0xa2, 0xa7, 0x96,
0xc3, 0xf7, 0x1f, 0x1f, 0x76, 0xad, 0x27, 0x87, 0x5d, 0xeb, 0xe9, 0x61, 0xd7, 0x7a, 0x78, 0xd4,
0xad, 0x3c, 0x39, 0xea, 0x56, 0x7e, 0x3d, 0xea, 0x56, 0xee, 0x5f, 0x39, 0xbb, 0xd0, 0xae, 0x9c,
0x8d, 0x1a, 0xba, 0x41, 0xdd, 0xf8, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x24, 0x52, 0x64, 0xe6, 0x23,
0x0a, 0x00, 0x00,
// 1120 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xc1, 0x6f, 0x1b, 0xc5,
0x17, 0xf6, 0x7a, 0x6d, 0xc7, 0x7e, 0x4d, 0xda, 0x64, 0x54, 0xfd, 0xe4, 0x3a, 0xbf, 0x3a, 0xc1,
0x55, 0xc1, 0xaa, 0xc8, 0x6e, 0x9b, 0x1e, 0x28, 0x15, 0x02, 0xec, 0x86, 0x28, 0x55, 0x29, 0x88,
0x4d, 0x4e, 0xbd, 0xac, 0xc6, 0xbb, 0x93, 0xf5, 0xa8, 0xde, 0x99, 0x65, 0x67, 0x16, 0xbc, 0x47,
0x2e, 0xdc, 0x90, 0x22, 0x2e, 0x48, 0x9c, 0x39, 0x20, 0x4e, 0x3d, 0x20, 0xfe, 0x86, 0x9c, 0x50,
0xc5, 0x89, 0x53, 0x5b, 0x25, 0x87, 0xde, 0xf9, 0x07, 0x40, 0x3b, 0x3b, 0xbb, 0x49, 0xd3, 0xd4,
0x29, 0x02, 0x89, 0x8b, 0x3d, 0xfb, 0xe6, 0x7b, 0x6f, 0xbe, 0x37, 0xf3, 0xbd, 0xf7, 0xa0, 0xe3,
0x71, 0x11, 0x72, 0x61, 0xcb, 0xa9, 0xfd, 0xc5, 0x8d, 0x11, 0x91, 0xf8, 0x86, 0x2d, 0xa7, 0x56,
0x14, 0x73, 0xc9, 0xd1, 0x52, 0xbe, 0x67, 0xc9, 0xa9, 0xa5, 0xf7, 0x3a, 0x4b, 0x38, 0xa4, 0x8c,
0xdb, 0xea, 0x37, 0x47, 0x75, 0x2e, 0x06, 0x3c, 0xe0, 0x6a, 0x69, 0x67, 0x2b, 0x6d, 0x5d, 0xd3,
0x71, 0xbd, 0x38, 0x8d, 0x24, 0xb7, 0xc3, 0x64, 0x22, 0xa9, 0xa0, 0x41, 0x79, 0x48, 0x61, 0xd0,
0xf0, 0xae, 0x86, 0x8f, 0xb0, 0x20, 0x25, 0xc6, 0xe3, 0x94, 0xe9, 0xfd, 0xb7, 0x8e, 0x68, 0x0a,
0x1a, 0x30, 0xca, 0x8e, 0x22, 0xe9, 0x6f, 0x0d, 0xbc, 0x14, 0x70, 0x1e, 0x4c, 0x88, 0xad, 0xbe,
0x46, 0xc9, 0xae, 0x8d, 0x59, 0x5a, 0x6c, 0xe5, 0x31, 0xdc, 0x9c, 0xab, 0xce, 0x2d, 0xdf, 0x5a,
0x39, 0xe9, 0x25, 0x69, 0x48, 0x84, 0xc4, 0x61, 0x94, 0x03, 0x7a, 0xdf, 0x18, 0x50, 0xdd, 0x99,
0xa2, 0x35, 0xa8, 0x8d, 0xb8, 0x9f, 0xb6, 0x8d, 0x55, 0xa3, 0x7f, 0x6e, 0xfd, 0x92, 0xf5, 0xd2,
0x05, 0x59, 0x3b, 0xd3, 0x21, 0xf7, 0x53, 0x47, 0xc1, 0xd0, 0x2d, 0x68, 0xe1, 0x44, 0x8e, 0x5d,
0xca, 0x76, 0x79, 0xbb, 0xaa, 0x7c, 0x96, 0x4f, 0xf1, 0x19, 0x24, 0x72, 0x7c, 0x97, 0xed, 0x72,
0xa7, 0x89, 0xf5, 0x0a, 0x75, 0x01, 0xb2, 0xbc, 0xb0, 0x4c, 0x62, 0x22, 0xda, 0xe6, 0xaa, 0xd9,
0x9f, 0x77, 0x8e, 0x59, 0x7a, 0x0c, 0xea, 0x3b, 0x53, 0x07, 0x7f, 0x89, 0x2e, 0x03, 0x64, 0x47,
0xb9, 0xa3, 0x54, 0x12, 0xa1, 0x78, 0xcd, 0x3b, 0xad, 0xcc, 0x32, 0xcc, 0x0c, 0xe8, 0x4d, 0xb8,
0x50, 0x32, 0xd0, 0x98, 0xaa, 0xc2, 0x2c, 0x14, 0x47, 0xe5, 0xb8, 0xb3, 0xce, 0xfb, 0xd6, 0x80,
0xb9, 0x6d, 0x1a, 0xb0, 0x0d, 0xee, 0xfd, 0x5b, 0x47, 0x5e, 0x82, 0xa6, 0x37, 0xc6, 0x94, 0xb9,
0xd4, 0x6f, 0x9b, 0xab, 0x46, 0xbf, 0xe5, 0xcc, 0xa9, 0xef, 0xbb, 0x3e, 0xba, 0x0a, 0xe7, 0xb1,
0xe7, 0xf1, 0x84, 0x49, 0x97, 0x25, 0xe1, 0x88, 0xc4, 0xed, 0xda, 0xaa, 0xd1, 0xaf, 0x39, 0x0b,
0xda, 0xfa, 0x89, 0x32, 0xf6, 0xfe, 0x30, 0x60, 0x51, 0x93, 0xda, 0xa0, 0x31, 0xf1, 0xe4, 0x20,
0x99, 0x9e, 0xc5, 0xee, 0x26, 0x40, 0x94, 0x8c, 0x26, 0xd4, 0x73, 0x1f, 0x92, 0x54, 0xbf, 0xc9,
0x45, 0x2b, 0x7f, 0x7e, 0xab, 0x78, 0x7e, 0x6b, 0xc0, 0x52, 0xa7, 0x95, 0xe3, 0xee, 0x91, 0xf4,
0x9f, 0x53, 0x45, 0x1d, 0x68, 0x0a, 0xf2, 0x79, 0x42, 0x98, 0x47, 0xda, 0x75, 0x05, 0x28, 0xbf,
0xd1, 0xdb, 0x60, 0x4a, 0x1a, 0xb5, 0x1b, 0x8a, 0xcb, 0xff, 0x4e, 0xd3, 0x14, 0x8d, 0x86, 0xd5,
0xb6, 0xe1, 0x64, 0xb0, 0xde, 0xd7, 0x26, 0x34, 0x72, 0x91, 0xa1, 0xeb, 0xd0, 0x0c, 0x89, 0x10,
0x38, 0x50, 0x89, 0x9a, 0xaf, 0xcc, 0xa4, 0x44, 0x21, 0x04, 0xb5, 0x90, 0x84, 0xb9, 0x16, 0x5b,
0x8e, 0x5a, 0x67, 0x19, 0x64, 0x6a, 0xe7, 0x89, 0x74, 0xc7, 0x84, 0x06, 0x63, 0xa9, 0x52, 0xac,
0x39, 0x0b, 0xda, 0xba, 0xa5, 0x8c, 0xe8, 0xff, 0xd0, 0x4a, 0x18, 0x8f, 0x7d, 0x12, 0x13, 0x5f,
0xe5, 0xd8, 0x74, 0x8e, 0x0c, 0xe8, 0x33, 0x58, 0x2a, 0x82, 0x94, 0xa5, 0xa3, 0x12, 0x3d, 0xb7,
0xde, 0x79, 0x89, 0xd3, 0x4e, 0x81, 0x18, 0x36, 0xf7, 0x9f, 0xac, 0x18, 0x7b, 0x4f, 0x57, 0x0c,
0x67, 0x51, 0xbb, 0x97, 0x7b, 0x68, 0x08, 0x4b, 0x64, 0x2a, 0x09, 0x13, 0x94, 0x33, 0x97, 0x47,
0x92, 0x72, 0x26, 0xda, 0x7f, 0xce, 0xcd, 0xc8, 0x73, 0xb1, 0xc4, 0x7f, 0x9a, 0xc3, 0xd1, 0x03,
0xe8, 0x32, 0xce, 0x5c, 0x2f, 0xa6, 0x92, 0x7a, 0x78, 0xe2, 0x9e, 0x12, 0xf0, 0xc2, 0x8c, 0x80,
0xcb, 0x8c, 0xb3, 0x3b, 0xda, 0xf7, 0xa3, 0x13, 0xb1, 0x7b, 0x3f, 0x18, 0xd0, 0x2c, 0x2a, 0x17,
0x7d, 0x08, 0xf3, 0x59, 0xb5, 0x90, 0x58, 0xc9, 0xbe, 0x78, 0x8e, 0xcb, 0xa7, 0x3c, 0xe6, 0xb6,
0x82, 0xa9, 0x72, 0x3f, 0x27, 0xca, 0xb5, 0x40, 0x7d, 0x30, 0x77, 0x09, 0xd1, 0x8a, 0x3c, 0x4d,
0x05, 0x9b, 0x84, 0x38, 0x19, 0xa4, 0xd0, 0x8b, 0xf9, 0x7a, 0x7a, 0xf9, 0xce, 0x00, 0x38, 0x3a,
0xf3, 0x84, 0xfe, 0x8d, 0xd7, 0xd3, 0xff, 0x2d, 0x68, 0x85, 0xdc, 0x27, 0x67, 0xf5, 0xb1, 0xfb,
0xdc, 0x27, 0x79, 0x1f, 0x0b, 0xf5, 0xea, 0x05, 0xdd, 0x9b, 0x2f, 0xea, 0xbe, 0xf7, 0xac, 0x0a,
0xcd, 0xc2, 0x05, 0xbd, 0x07, 0x0d, 0x41, 0x59, 0x30, 0x21, 0x9a, 0x53, 0x6f, 0x46, 0x7c, 0x6b,
0x5b, 0x21, 0xb7, 0x2a, 0x8e, 0xf6, 0x41, 0xef, 0x42, 0x5d, 0x0d, 0x14, 0x4d, 0xee, 0x8d, 0x59,
0xce, 0xf7, 0x33, 0xe0, 0x56, 0xc5, 0xc9, 0x3d, 0x3a, 0x03, 0x68, 0xe4, 0xe1, 0xd0, 0x3b, 0x50,
0xcb, 0x78, 0x2b, 0x02, 0xe7, 0xd7, 0xaf, 0x1c, 0x8b, 0x51, 0x8c, 0x98, 0xe3, 0x6f, 0x98, 0xc5,
0x73, 0x94, 0x43, 0x67, 0xcf, 0x80, 0xba, 0x8a, 0x8a, 0xee, 0x41, 0x73, 0x44, 0x25, 0x8e, 0x63,
0x5c, 0xdc, 0xad, 0x5d, 0x84, 0xc9, 0x07, 0xa1, 0x55, 0xce, 0xbd, 0x22, 0xd6, 0x1d, 0x1e, 0x46,
0xd8, 0x93, 0x43, 0x2a, 0x07, 0x99, 0x9b, 0x53, 0x06, 0x40, 0xb7, 0x01, 0xca, 0x5b, 0xcf, 0x7a,
0xa8, 0x79, 0xd6, 0xb5, 0xb7, 0x8a, 0x6b, 0x17, 0xc3, 0x3a, 0x98, 0x22, 0x09, 0x7b, 0x5f, 0x55,
0xc1, 0xdc, 0x24, 0x04, 0xa5, 0xd0, 0xc0, 0x61, 0xd6, 0x8e, 0xb4, 0x30, 0xcb, 0xc9, 0x95, 0xcd,
0xdb, 0x63, 0x54, 0x28, 0x1b, 0x6e, 0xee, 0x3f, 0x59, 0xa9, 0xfc, 0xf4, 0x74, 0xa5, 0x1f, 0x50,
0x39, 0x4e, 0x46, 0x96, 0xc7, 0x43, 0xbb, 0x98, 0xe5, 0xea, 0x6f, 0x4d, 0xf8, 0x0f, 0x6d, 0x99,
0x46, 0x44, 0x28, 0x07, 0xf1, 0xfd, 0xf3, 0x47, 0xd7, 0xe6, 0x27, 0x24, 0xc0, 0x5e, 0xea, 0x66,
0x13, 0x5b, 0xfc, 0xf8, 0xfc, 0xd1, 0x35, 0xc3, 0xd1, 0x07, 0xa2, 0x65, 0x68, 0x05, 0x58, 0xb8,
0x13, 0x1a, 0x52, 0xa9, 0x9e, 0xa7, 0xe6, 0x34, 0x03, 0x2c, 0x3e, 0xce, 0xbe, 0x91, 0x05, 0xf5,
0x08, 0xa7, 0x24, 0xce, 0xbb, 0xea, 0xb0, 0xfd, 0xdb, 0xcf, 0x6b, 0x17, 0x35, 0xb3, 0x81, 0xef,
0xc7, 0x44, 0x88, 0x6d, 0x19, 0x53, 0x16, 0x38, 0x39, 0x0c, 0xad, 0xc3, 0x5c, 0x10, 0x63, 0x26,
0x75, 0x9b, 0x9d, 0xe5, 0x51, 0x00, 0x7b, 0xbf, 0x18, 0x60, 0xee, 0xd0, 0xe8, 0xbf, 0xbc, 0x83,
0xeb, 0xd0, 0x90, 0x34, 0x8a, 0x48, 0x9c, 0x37, 0xde, 0x19, 0xac, 0x35, 0xee, 0x76, 0xb5, 0x6d,
0xf4, 0x7e, 0x35, 0x60, 0x61, 0x90, 0x4c, 0xf3, 0xe2, 0xdd, 0xc0, 0x12, 0x67, 0xe9, 0xe3, 0x1c,
0xae, 0xd4, 0x35, 0x33, 0x7d, 0x0d, 0x44, 0xef, 0x43, 0x33, 0x93, 0xaf, 0xeb, 0x73, 0x4f, 0x57,
0xc7, 0x95, 0x57, 0x74, 0xa5, 0xe3, 0x63, 0xd4, 0x99, 0x13, 0x7a, 0xda, 0x17, 0x55, 0x61, 0xfe,
0xcd, 0xaa, 0x40, 0x8b, 0x60, 0x0a, 0x1a, 0xa8, 0x77, 0x9a, 0x77, 0xb2, 0xe5, 0xf0, 0x83, 0xfd,
0x83, 0xae, 0xf1, 0xf8, 0xa0, 0x6b, 0x3c, 0x3b, 0xe8, 0x1a, 0x7b, 0x87, 0xdd, 0xca, 0xe3, 0xc3,
0x6e, 0xe5, 0xf7, 0xc3, 0x6e, 0xe5, 0xc1, 0xd5, 0xb3, 0x2f, 0xda, 0x96, 0xd3, 0x51, 0x43, 0x35,
0xa8, 0x9b, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0xc4, 0xae, 0x24, 0xf8, 0xb5, 0x0a, 0x00, 0x00,
}
func (m *Tx) Marshal() (dAtA []byte, err error) {
@ -1364,6 +1405,26 @@ func (m *TxBody) MarshalToSizedBuffer(dAtA []byte) (int, error) {
dAtA[i] = 0xfa
}
}
if m.TimeoutTimestamp != nil {
n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(*m.TimeoutTimestamp, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.TimeoutTimestamp):])
if err5 != nil {
return 0, err5
}
i -= n5
i = encodeVarintTx(dAtA, i, uint64(n5))
i--
dAtA[i] = 0x2a
}
if m.Unordered {
i--
if m.Unordered {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if m.TimeoutHeight != 0 {
i = encodeVarintTx(dAtA, i, uint64(m.TimeoutHeight))
i--
@ -1942,6 +2003,13 @@ func (m *TxBody) Size() (n int) {
if m.TimeoutHeight != 0 {
n += 1 + sovTx(uint64(m.TimeoutHeight))
}
if m.Unordered {
n += 2
}
if m.TimeoutTimestamp != nil {
l = github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.TimeoutTimestamp)
n += 1 + l + sovTx(uint64(l))
}
if len(m.ExtensionOptions) > 0 {
for _, e := range m.ExtensionOptions {
l = e.Size()
@ -2955,6 +3023,62 @@ func (m *TxBody) Unmarshal(dAtA []byte) error {
break
}
}
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Unordered", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.Unordered = bool(v != 0)
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowTx
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthTx
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthTx
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.TimeoutTimestamp == nil {
m.TimeoutTimestamp = new(time.Time)
}
if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(m.TimeoutTimestamp, dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 1023:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ExtensionOptions", wireType)

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
fmt "fmt"
strings "strings"
"time"
"github.com/cosmos/gogoproto/proto"
protov2 "google.golang.org/protobuf/proto"
@ -71,6 +72,14 @@ type (
GetMemo() string
}
// TxWithTimeoutTimeStamp extends the Tx interface by allowing a transaction to
// set a timeout timestamp.
TxWithTimeoutTimeStamp interface {
Tx
GetTimeoutTimeStamp() time.Time
}
// TxWithTimeoutHeight extends the Tx interface by allowing a transaction to
// set a height timeout.
TxWithTimeoutHeight interface {
@ -79,6 +88,14 @@ type (
GetTimeoutHeight() uint64
}
// TxWithUnordered extends the Tx interface by allowing a transaction to set
// the unordered field, which implicitly relies on TxWithTimeoutTimeStamp.
TxWithUnordered interface {
TxWithTimeoutTimeStamp
GetUnordered() bool
}
// HasValidateBasic defines a type that has a ValidateBasic method.
// ValidateBasic is deprecated and now facultative.
// Prefer validating messages directly in the msg server.

View File

@ -8,6 +8,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
"github.com/cosmos/cosmos-sdk/x/auth/types"
)
@ -20,6 +21,7 @@ type HandlerOptions struct {
SignModeHandler *txsigning.HandlerMap
SigGasConsumer func(meter storetypes.GasMeter, sig signing.SignatureV2, params types.Params) error
TxFeeChecker TxFeeChecker
UnorderedTxManager *unorderedtx.Manager
}
// NewAnteHandler returns an AnteHandler that checks and increments sequence
@ -53,5 +55,9 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
NewIncrementSequenceDecorator(options.AccountKeeper),
}
if options.UnorderedTxManager != nil {
anteDecorators = append(anteDecorators, NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, options.UnorderedTxManager, DefaultSha256GasCost))
}
return sdk.ChainAnteDecorators(anteDecorators...), nil
}

View File

@ -6,6 +6,7 @@ import (
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
@ -1447,3 +1448,34 @@ func TestAnteHandlerReCheck(t *testing.T) {
_, err = suite.anteHandler(suite.ctx, tx, false)
require.NotNil(t, err, "antehandler on recheck did not fail once feePayer no longer has sufficient funds")
}
func TestAnteHandlerUnorderedTx(t *testing.T) {
suite := SetupTestSuite(t, false)
accs := suite.CreateTestAccounts(1)
msg := testdata.NewTestMsg(accs[0].acc.GetAddress())
// First send a normal sequential tx with sequence 0
suite.bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), accs[0].acc.GetAddress(), authtypes.FeeCollectorName, testdata.NewTestFeeAmount()).Return(nil).AnyTimes()
privs, accNums, accSeqs := []cryptotypes.PrivKey{accs[0].priv}, []uint64{1000}, []uint64{0}
_, err := suite.DeliverMsgs(t, privs, []sdk.Msg{msg}, testdata.NewTestFeeAmount(), testdata.NewTestGasLimit(), accNums, accSeqs, suite.ctx.ChainID(), false)
require.NoError(t, err)
// we try to send another tx with the same sequence, it will fail
_, err = suite.DeliverMsgs(t, privs, []sdk.Msg{msg}, testdata.NewTestFeeAmount(), testdata.NewTestGasLimit(), accNums, accSeqs, suite.ctx.ChainID(), false)
require.Error(t, err)
// now we'll still use the same sequence but because it's unordered, it will be ignored and accepted anyway
msgs := []sdk.Msg{msg}
require.NoError(t, suite.txBuilder.SetMsgs(msgs...))
suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit())
tx, txErr := suite.CreateTestUnorderedTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT, true, time.Now().Add(time.Minute))
require.NoError(t, txErr)
txBytes, err := suite.clientCtx.TxConfig.TxEncoder()(tx)
bytesCtx := suite.ctx.WithTxBytes(txBytes)
require.NoError(t, err)
_, err = suite.anteHandler(bytesCtx, tx, false)
require.NoError(t, err)
}

View File

@ -1,6 +1,8 @@
package ante
import (
"time"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
@ -187,6 +189,7 @@ type (
sdk.Tx
GetTimeoutHeight() uint64
GetTimeoutTimeStamp() time.Time
}
)
@ -213,5 +216,13 @@ func (txh TxTimeoutHeightDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
)
}
timeoutTimestamp := timeoutTx.GetTimeoutTimeStamp()
blockTime := ctx.BlockHeader().Time
if !timeoutTimestamp.IsZero() && timeoutTimestamp.Unix() != 0 && timeoutTimestamp.Before(blockTime) {
return ctx, errorsmod.Wrapf(
sdkerrors.ErrTxTimeout, "block time: %s, timeout timestamp: %s", blockTime, timeoutTimestamp.String(),
)
}
return next(ctx, tx, simulate)
}

View File

@ -3,6 +3,7 @@ package ante_test
import (
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
@ -186,21 +187,30 @@ func TestTxHeightTimeoutDecorator(t *testing.T) {
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
currentTime := time.Now()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
testCases := []struct {
name string
timeout uint64
height int64
expectedErr error
name string
timeout uint64
height int64
timeoutTimestamp time.Time
timestamp time.Time
expectedErr error
}{
{"default value", 0, 10, nil},
{"no timeout (greater height)", 15, 10, nil},
{"no timeout (same height)", 10, 10, nil},
{"timeout (smaller height)", 9, 10, sdkerrors.ErrTxTimeoutHeight},
{"default value", 0, 10, time.Time{}, time.Time{}, nil},
{"no timeout (greater height)", 15, 10, time.Time{}, time.Time{}, nil},
{"no timeout (same height)", 10, 10, time.Time{}, time.Time{}, nil},
{"timeout (smaller height)", 9, 10, time.Time{}, time.Time{}, sdkerrors.ErrTxTimeoutHeight},
{"no timeout (timeout after timestamp)", 0, 20, currentTime.Add(time.Minute), currentTime, nil},
{"no timeout (current time)", 0, 20, currentTime, currentTime, nil},
{"timeout before timestamp", 0, 20, currentTime, currentTime.Add(time.Minute), sdkerrors.ErrTxTimeout},
{"tx contain both timeouts, timeout (timeout before timestamp)", 15, 10, currentTime, currentTime.Add(time.Minute), sdkerrors.ErrTxTimeout},
{"tx contain both timeout, no timeout", 15, 10, currentTime.Add(time.Minute), currentTime, nil},
}
for _, tc := range testCases {
@ -215,12 +225,13 @@ func TestTxHeightTimeoutDecorator(t *testing.T) {
suite.txBuilder.SetGasLimit(gasLimit)
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
suite.txBuilder.SetTimeoutHeight(tc.timeout)
suite.txBuilder.SetTimeoutTimestamp(tc.timeoutTimestamp)
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
ctx := suite.ctx.WithBlockHeight(tc.height)
ctx := suite.ctx.WithBlockHeight(tc.height).WithBlockTime(tc.timestamp)
_, err = antehandler(ctx, tx, true)
require.ErrorIs(t, err, tc.expectedErr)
})

View File

@ -256,6 +256,9 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
utx, ok := tx.(sdk.TxWithUnordered)
isUnordered := ok && utx.GetUnordered()
// stdSigs contains the sequence number, account number, and signatures.
// When simulating, this would just be a 0-length slice.
sigs, err := sigTx.GetSignaturesV2()
@ -286,11 +289,13 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
}
// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
if !isUnordered {
if sig.Sequence != acc.GetSequence() {
return ctx, errorsmod.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
}
}
// retrieve signer data
@ -309,7 +314,7 @@ func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
Address: acc.GetAddress().String(),
ChainID: chainID,
AccountNumber: accNum,
Sequence: acc.GetSequence(),
Sequence: sig.Sequence,
PubKey: &anypb.Any{
TypeUrl: anyPk.TypeUrl,
Value: anyPk.Value,
@ -359,6 +364,9 @@ func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator
}
func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
if utx, ok := tx.(sdk.TxWithUnordered); ok && utx.GetUnordered() {
return next(ctx, tx, simulate)
}
sigTx, ok := tx.(authsigning.SigVerifiableTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")

View File

@ -3,6 +3,7 @@ package ante_test
import (
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
@ -335,27 +336,76 @@ func TestIncrementSequenceDecorator(t *testing.T) {
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)
tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
isd := ante.NewIncrementSequenceDecorator(suite.accountKeeper)
antehandler := sdk.ChainAnteDecorators(isd)
testCases := []struct {
ctx sdk.Context
simulate bool
expectedSeq uint64
name string
ctx sdk.Context
simulate bool
createTx func() sdk.Tx
expectSeqInc bool
}{
{suite.ctx.WithIsReCheckTx(true), false, 1},
{suite.ctx.WithIsCheckTx(true).WithIsReCheckTx(false), false, 2},
{suite.ctx.WithIsReCheckTx(true), false, 3},
{suite.ctx.WithIsReCheckTx(true), false, 4},
{suite.ctx.WithIsReCheckTx(true), true, 5},
{
"inc on recheck no sim",
suite.ctx.WithIsReCheckTx(true),
false,
func() sdk.Tx {
tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
return tx
},
true,
},
{
"inc on no recheck, no sim",
suite.ctx.WithIsReCheckTx(false),
false,
func() sdk.Tx {
tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
return tx
},
true,
},
{
"inc on recheck and sim",
suite.ctx.WithIsReCheckTx(true),
true,
func() sdk.Tx {
tx, err := suite.CreateTestTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
return tx
},
true,
},
{
"no inc on unordered",
suite.ctx.WithIsReCheckTx(true),
true,
func() sdk.Tx {
tx, err := suite.CreateTestUnorderedTx(suite.ctx, privs, accNums, accSeqs, suite.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT, true, time.Now().Add(time.Hour))
require.NoError(t, err)
return tx
},
false,
},
}
for i, tc := range testCases {
_, err := antehandler(tc.ctx, tx, tc.simulate)
require.NoError(t, err, "unexpected error; tc #%d, %v", i, tc)
require.Equal(t, tc.expectedSeq, suite.accountKeeper.GetAccount(suite.ctx, addr).GetSequence())
t.Run(tc.name, func(t *testing.T) {
beforeSeq := suite.accountKeeper.GetAccount(suite.ctx, addr).GetSequence()
_, err := antehandler(tc.ctx, tc.createTx(), tc.simulate)
require.NoError(t, err, "unexpected error; tc #%d, %v", i, tc)
afterSeq := suite.accountKeeper.GetAccount(suite.ctx, addr).GetSequence()
if tc.expectSeqInc {
require.Equal(t, beforeSeq+1, afterSeq)
} else {
require.Equal(t, beforeSeq, afterSeq)
}
})
}
}

View File

@ -2,6 +2,7 @@ package ante_test
import (
"testing"
"time"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/stretchr/testify/require"
@ -257,3 +258,59 @@ func (suite *AnteTestSuite) CreateTestTx(
return suite.txBuilder.GetTx(), nil
}
func (suite *AnteTestSuite) CreateTestUnorderedTx(
ctx sdk.Context, privs []cryptotypes.PrivKey,
accNums, accSeqs []uint64,
chainID string, signMode signing.SignMode,
unordered bool, unorderedTimeout time.Time,
) (xauthsigning.Tx, error) {
suite.txBuilder.SetUnordered(unordered)
suite.txBuilder.SetTimeoutTimestamp(unorderedTimeout)
// First round: we gather all the signer infos. We use the "set empty
// signature" hack to do that.
var sigsV2 []signing.SignatureV2
for i, priv := range privs {
sigV2 := signing.SignatureV2{
PubKey: priv.PubKey(),
Data: &signing.SingleSignatureData{
SignMode: signMode,
Signature: nil,
},
Sequence: accSeqs[i],
}
sigsV2 = append(sigsV2, sigV2)
}
err := suite.txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, err
}
// Second round: all signer infos are set, so each signer can sign.
sigsV2 = []signing.SignatureV2{}
for i, priv := range privs {
signerData := xauthsigning.SignerData{
Address: sdk.AccAddress(priv.PubKey().Address()).String(),
ChainID: chainID,
AccountNumber: accNums[i],
Sequence: accSeqs[i],
PubKey: priv.PubKey(),
}
sigV2, err := tx.SignWithPrivKey(
ctx, signMode, signerData,
suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i])
if err != nil {
return nil, err
}
sigsV2 = append(sigsV2, sigV2)
}
err = suite.txBuilder.SetSignatures(sigsV2...)
if err != nil {
return nil, err
}
return suite.txBuilder.GetTx(), nil
}

233
x/auth/ante/unordered.go Normal file
View File

@ -0,0 +1,233 @@
package ante
import (
"bytes"
"crypto/sha256"
"encoding/binary"
"fmt"
"sync"
"time"
"github.com/cosmos/gogoproto/proto"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
)
// bufPool is a pool of bytes.Buffer objects to reduce memory allocations.
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
// DefaultSha256GasCost is the suggested default gas cost for Sha256 operations in unordered transaction handling.
const DefaultSha256GasCost = 25
var _ sdk.AnteDecorator = (*UnorderedTxDecorator)(nil)
// UnorderedTxDecorator defines an AnteHandler decorator that is responsible for
// checking if a transaction is intended to be unordered and if so, evaluates
// the transaction accordingly. An unordered transaction will bypass having its
// nonce incremented, which allows fire-and-forget along with possible parallel
// transaction processing, without having to deal with nonces.
//
// The transaction sender must ensure that unordered=true and a timeout_height
// is appropriately set. The AnteHandler will check that the transaction is not
// a duplicate and will evict it from memory when the timeout is reached.
//
// The UnorderedTxDecorator should be placed as early as possible in the AnteHandler
// chain to ensure that during DeliverTx, the transaction is added to the UnorderedTxManager.
type UnorderedTxDecorator struct {
// maxUnOrderedTTL defines the maximum TTL a transaction can define.
maxTimeoutDuration time.Duration
txManager *unorderedtx.Manager
sha256GasCost uint64
}
func NewUnorderedTxDecorator(
maxDuration time.Duration,
m *unorderedtx.Manager,
sha256GasCost uint64,
) *UnorderedTxDecorator {
return &UnorderedTxDecorator{
maxTimeoutDuration: maxDuration,
txManager: m,
sha256GasCost: sha256GasCost,
}
}
func (d *UnorderedTxDecorator) AnteHandle(
ctx sdk.Context,
tx sdk.Tx,
_ bool,
next sdk.AnteHandler,
) (sdk.Context, error) {
if err := d.ValidateTx(ctx, tx); err != nil {
return ctx, err
}
return next(ctx, tx, false)
}
func (d *UnorderedTxDecorator) ValidateTx(ctx sdk.Context, tx sdk.Tx) error {
unorderedTx, ok := tx.(sdk.TxWithUnordered)
if !ok || !unorderedTx.GetUnordered() {
// If the transaction does not implement unordered capabilities or has the
// unordered value as false, we bypass.
return nil
}
blockTime := ctx.BlockTime()
timeoutTimestamp := unorderedTx.GetTimeoutTimeStamp()
if timeoutTimestamp.IsZero() || timeoutTimestamp.Unix() == 0 {
return errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"unordered transaction must have timeout_timestamp set",
)
}
if timeoutTimestamp.Before(blockTime) {
return errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"unordered transaction has a timeout_timestamp that has already passed",
)
}
if timeoutTimestamp.After(blockTime.Add(d.maxTimeoutDuration)) {
return errorsmod.Wrapf(
sdkerrors.ErrInvalidRequest,
"unordered tx ttl exceeds %s",
d.maxTimeoutDuration.String(),
)
}
// consume gas in all exec modes to avoid gas estimation discrepancies
ctx.GasMeter().ConsumeGas(d.sha256GasCost, "consume gas for calculating tx hash")
// Avoid checking for duplicates and creating the identifier in simulation mode
// This is done to avoid sha256 computation in simulation mode
if ctx.ExecMode() == sdk.ExecModeSimulate {
return nil
}
// calculate the tx hash
txHash, err := TxHashFromTimeout(uint64(timeoutTimestamp.Unix()), tx)
if err != nil {
return err
}
// check for duplicates
if d.txManager.Contains(txHash) {
return errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"tx %X is duplicated",
)
}
if ctx.ExecMode() == sdk.ExecModeFinalize {
// a new tx included in the block, add the hash to the unordered tx manager
d.txManager.Add(txHash, timeoutTimestamp)
}
return nil
}
// TxHashFromTimeout returns a TxHash for an unordered transaction.
func TxHashFromTimeout(timeout uint64, tx sdk.Tx) (unorderedtx.TxHash, error) {
sigTx, ok := tx.(authsigning.Tx)
if !ok {
return unorderedtx.TxHash{}, errorsmod.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
}
if sigTx.GetFee().IsZero() {
return unorderedtx.TxHash{}, errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"unordered transaction must have a fee",
)
}
buf := bufPool.Get().(*bytes.Buffer)
// Make sure to reset the buffer
buf.Reset()
defer bufPool.Put(buf)
// Add signatures to the transaction identifier
signatures, err := sigTx.GetSignaturesV2()
if err != nil {
return unorderedtx.TxHash{}, err
}
for _, sig := range signatures {
if err := addSignatures(sig.Data, buf); err != nil {
return unorderedtx.TxHash{}, err
}
}
// Use the buffer
for _, msg := range tx.GetMsgs() {
// loop through the messages and write them to the buffer
// encoding the msg to bytes makes it deterministic within the state machine.
// Malleability is not a concern here because the state machine will encode the transaction deterministically.
bz, err := proto.Marshal(msg)
if err != nil {
return unorderedtx.TxHash{}, errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"failed to marshal message",
)
}
if _, err := buf.Write(bz); err != nil {
return unorderedtx.TxHash{}, errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"failed to write message to buffer",
)
}
}
// write the timeout height to the buffer
if err := binary.Write(buf, binary.LittleEndian, timeout); err != nil {
return unorderedtx.TxHash{}, errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"failed to write timeout_height to buffer",
)
}
// write gas to the buffer
if err := binary.Write(buf, binary.LittleEndian, sigTx.GetGas()); err != nil {
return unorderedtx.TxHash{}, errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"failed to write unordered to buffer",
)
}
txHash := sha256.Sum256(buf.Bytes())
// Return the Buffer to the pool
return txHash, nil
}
func addSignatures(sig signing.SignatureData, buf *bytes.Buffer) error {
switch data := sig.(type) {
case *signing.SingleSignatureData:
if _, err := buf.Write(data.Signature); err != nil {
return errorsmod.Wrap(
sdkerrors.ErrInvalidRequest,
"failed to write single signature to buffer",
)
}
return nil
case *signing.MultiSignatureData:
for _, sigdata := range data.Signatures {
if err := addSignatures(sigdata, buf); err != nil {
return err
}
}
default:
return fmt.Errorf("unexpected SignatureData %T", data)
}
return nil
}

View File

@ -0,0 +1,172 @@
package ante_test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
storetypes "cosmossdk.io/store/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
)
const gasConsumed = uint64(25)
func TestUnorderedTxDecorator_OrderedTx(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, false, time.Time{})
ctx := sdk.Context{}.WithTxBytes(txBz)
_, err := chain(ctx, tx, false)
require.NoError(t, err)
}
func TestUnorderedTxDecorator_UnorderedTx_NoTTL(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, true, time.Time{})
ctx := sdk.Context{}.WithTxBytes(txBz)
_, err := chain(ctx, tx, false)
require.Error(t, err)
}
func TestUnorderedTxDecorator_UnorderedTx_InvalidTTL(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, true, time.Now().Add(unorderedtx.DefaultMaxTimeoutDuration+time.Second))
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockTime(time.Now())
_, err := chain(ctx, tx, false)
require.Error(t, err)
}
func TestUnorderedTxDecorator_UnorderedTx_AlreadyExists(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute))
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockTime(time.Now()).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
bz := [32]byte{}
copy(bz[:], txBz[:32])
txm.Add(bz, time.Now().Add(time.Minute))
_, err := chain(ctx, tx, false)
require.Error(t, err)
}
func TestUnorderedTxDecorator_UnorderedTx_ValidCheckTx(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute))
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockTime(time.Now()).WithExecMode(sdk.ExecModeCheck).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
_, err := chain(ctx, tx, false)
require.NoError(t, err)
}
func TestUnorderedTxDecorator_UnorderedTx_ValidDeliverTx(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
SetupTestSuite(t, false)
chain := sdk.ChainAnteDecorators(ante.NewUnorderedTxDecorator(unorderedtx.DefaultMaxTimeoutDuration, txm, ante.DefaultSha256GasCost))
tx, txBz := genUnorderedTx(t, true, time.Now().Add(time.Minute))
ctx := sdk.Context{}.WithTxBytes(txBz).WithBlockTime(time.Now()).WithExecMode(sdk.ExecModeFinalize).WithGasMeter(storetypes.NewGasMeter(gasConsumed))
_, err := chain(ctx, tx, false)
require.NoError(t, err)
bz := [32]byte{}
copy(bz[:], txBz[:32])
require.True(t, txm.Contains(bz))
}
func genUnorderedTx(t *testing.T, unordered bool, timestamp time.Time) (sdk.Tx, []byte) {
t.Helper()
s := SetupTestSuite(t, true)
s.txBuilder = s.clientCtx.TxConfig.NewTxBuilder()
// keys and addresses
priv1, _, addr1 := testdata.KeyTestPubAddr()
// msg and signatures
msg := testdata.NewTestMsg(addr1)
feeAmount := testdata.NewTestFeeAmount()
gasLimit := testdata.NewTestGasLimit()
require.NoError(t, s.txBuilder.SetMsgs(msg))
s.txBuilder.SetFeeAmount(feeAmount)
s.txBuilder.SetGasLimit(gasLimit)
s.txBuilder.SetUnordered(unordered)
s.txBuilder.SetTimeoutTimestamp(timestamp)
privKeys, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
tx, err := s.CreateTestTx(s.ctx, privKeys, accNums, accSeqs, s.ctx.ChainID(), signing.SignMode_SIGN_MODE_DIRECT)
require.NoError(t, err)
txBz, err := ante.TxHashFromTimeout(uint64(timestamp.Unix()), tx)
require.NoError(t, err)
return tx, txBz[:]
}

View File

@ -0,0 +1,286 @@
package unorderedtx
import (
"bufio"
"bytes"
"context"
"encoding/binary"
"errors"
"fmt"
"io"
"maps"
"os"
"path/filepath"
"slices"
"sync"
"time"
)
const (
// DefaultMaxTimeoutDuration defines the default maximum duration an un-ordered transaction
// can set.
DefaultMaxTimeoutDuration = time.Minute * 40
dirName = "unordered_txs"
fileName = "data"
)
// TxHash defines a transaction hash type alias, which is a fixed array of 32 bytes.
type TxHash [32]byte
// Manager contains the tx hash dictionary for duplicates checking, and expire
// them when block production progresses.
type Manager struct {
// blockTimeCh defines a channel to receive newly committed block time
blockTimeCh chan time.Time
// doneCh allows us to ensure the purgeLoop has gracefully terminated prior to closing
doneCh chan struct{}
// dataDir defines the directory to store unexpired unordered transactions
//
// XXX: Note, ideally we avoid the need to store unexpired unordered transactions
// directly to file. However, store v1 does not allow such a primitive. But,
// once store v2 is fully integrated, we can remove manual file handling and
// store the unexpired unordered transactions directly to SS.
//
// Ref: https://github.com/cosmos/cosmos-sdk/issues/18467
dataDir string
mu sync.RWMutex
// txHashes defines a map from tx hash -> TTL value defined as block time, which is used for duplicate
// checking and replay protection, as well as purging the map when the TTL is
// expired.
txHashes map[TxHash]time.Time
}
func NewManager(dataDir string) *Manager {
path := filepath.Join(dataDir, dirName)
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
if err = os.MkdirAll(path, os.ModePerm); err != nil {
panic(fmt.Errorf("failed to create unordered txs directory: %w", err))
}
}
m := &Manager{
dataDir: dataDir,
blockTimeCh: make(chan time.Time, 16),
doneCh: make(chan struct{}),
txHashes: make(map[TxHash]time.Time),
}
return m
}
func (m *Manager) Start() {
go m.purgeLoop()
}
// Close must be called when a node gracefully shuts down. Typically, this should
// be called in an application's Close() function, which is called by the server.
// Note, Start() must be called in order for Close() to not hang.
//
// It will free all necessary resources as well as writing all unexpired unordered
// transactions along with their TTL values to file.
func (m *Manager) Close() error {
close(m.blockTimeCh)
<-m.doneCh
m.blockTimeCh = nil
return m.flushToFile()
}
func (m *Manager) Contains(hash TxHash) bool {
m.mu.RLock()
defer m.mu.RUnlock()
_, ok := m.txHashes[hash]
return ok
}
func (m *Manager) Size() int {
m.mu.RLock()
defer m.mu.RUnlock()
return len(m.txHashes)
}
func (m *Manager) Add(txHash TxHash, timestamp time.Time) {
m.mu.Lock()
defer m.mu.Unlock()
m.txHashes[txHash] = timestamp
}
// OnInit must be called when a node starts up. Typically, this should be called
// in an application's constructor, which is called by the server.
func (m *Manager) OnInit() error {
f, err := os.Open(filepath.Join(m.dataDir, dirName, fileName))
if err != nil {
if errors.Is(err, os.ErrNotExist) {
// File does not exist, which we can assume that there are no unexpired
// unordered transactions.
return nil
}
return fmt.Errorf("failed to open unconfirmed txs file: %w", err)
}
defer f.Close()
var (
r = bufio.NewReader(f)
buf = make([]byte, chunkSize)
)
for {
n, err := io.ReadFull(r, buf)
if err != nil {
if errors.Is(err, io.EOF) {
break
} else {
return fmt.Errorf("failed to read unconfirmed txs file: %w", err)
}
}
if n != 32+8 {
return fmt.Errorf("read unexpected number of bytes from unconfirmed txs file: %d", n)
}
var txHash TxHash
copy(txHash[:], buf[:txHashSize])
timeStamp := binary.BigEndian.Uint64(buf[txHashSize:])
m.Add(txHash, time.Unix(int64(timeStamp), 0))
}
return nil
}
// OnNewBlock sends the latest block time to the background purge loop, which
// should be called in ABCI Commit event.
func (m *Manager) OnNewBlock(blockTime time.Time) {
m.blockTimeCh <- blockTime
}
func (m *Manager) exportSnapshot(_ uint64, snapshotWriter func([]byte) error) error {
var buf bytes.Buffer
w := bufio.NewWriter(&buf)
keys := slices.SortedFunc(maps.Keys(m.txHashes), func(i, j TxHash) int { return bytes.Compare(i[:], j[:]) })
for _, txHash := range keys {
timeoutTime := m.txHashes[txHash]
// right now we dont have access block time at this flow, so we would just include the expired txs
// and let it be purge during purge loop
chunk := unorderedTxToBytes(txHash, uint64(timeoutTime.Unix()))
if _, err := w.Write(chunk); err != nil {
return fmt.Errorf("failed to write unordered tx to buffer: %w", err)
}
}
if err := w.Flush(); err != nil {
return fmt.Errorf("failed to flush unordered txs buffer: %w", err)
}
return snapshotWriter(buf.Bytes())
}
// flushToFile writes all unordered transactions (including expired if not pruned yet)
// along with their TTL to file, overwriting the existing file if it exists.
func (m *Manager) flushToFile() error {
f, err := os.Create(filepath.Join(m.dataDir, dirName, fileName))
if err != nil {
return fmt.Errorf("failed to create unordered txs file: %w", err)
}
defer f.Close()
w := bufio.NewWriter(f)
for txHash, timestamp := range m.txHashes {
chunk := unorderedTxToBytes(txHash, uint64(timestamp.Unix()))
if _, err = w.Write(chunk); err != nil {
return fmt.Errorf("failed to write unordered tx to buffer: %w", err)
}
}
if err = w.Flush(); err != nil {
return fmt.Errorf("failed to flush unordered txs buffer: %w", err)
}
return nil
}
// expiredTxs returns expired tx hashes based on the provided block time.
func (m *Manager) expiredTxs(blockTime time.Time) []TxHash {
m.mu.RLock()
defer m.mu.RUnlock()
var result []TxHash
for txHash, timestamp := range m.txHashes {
if blockTime.After(timestamp) {
result = append(result, txHash)
}
}
return result
}
func (m *Manager) purge(txHashes []TxHash) {
m.mu.Lock()
defer m.mu.Unlock()
for _, txHash := range txHashes {
delete(m.txHashes, txHash)
}
}
// purgeLoop removes expired tx hashes in the background
func (m *Manager) purgeLoop() {
for {
latestTime, ok := m.batchReceive()
if !ok {
// channel closed
m.doneCh <- struct{}{}
return
}
hashes := m.expiredTxs(latestTime)
if len(hashes) > 0 {
m.purge(hashes)
}
}
}
// batchReceive receives block time from the channel until the context is done
// or the channel is closed.
func (m *Manager) batchReceive() (time.Time, bool) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var latestTime time.Time
for {
select {
case <-ctx.Done():
return latestTime, true
case blockTime, ok := <-m.blockTimeCh:
if !ok {
// channel is closed
return time.Time{}, false
}
if blockTime.After(latestTime) {
latestTime = blockTime
}
}
}
}
func unorderedTxToBytes(txHash TxHash, ttl uint64) []byte {
chunk := make([]byte, chunkSize)
copy(chunk[:txHashSize], txHash[:])
ttlBz := make([]byte, timeoutSize)
binary.BigEndian.PutUint64(ttlBz, ttl)
copy(chunk[txHashSize:], ttlBz)
return chunk
}

View File

@ -0,0 +1,145 @@
package unorderedtx_test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
)
func TestUnorderedTxManager_Close(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
txm.Start()
require.NoError(t, txm.Close())
require.Panics(t, func() { txm.Close() })
}
func TestUnorderedTxManager_SimpleSize(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
txm.Add(unorderedtx.TxHash{0xFF}, time.Now())
txm.Add(unorderedtx.TxHash{0xAA}, time.Now())
txm.Add(unorderedtx.TxHash{0xCC}, time.Now())
require.Equal(t, 3, txm.Size())
}
func TestUnorderedTxManager_SimpleContains(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
for i := 0; i < 10; i++ {
txHash := unorderedtx.TxHash{byte(i)}
txm.Add(txHash, time.Now())
require.True(t, txm.Contains(txHash))
}
for i := 10; i < 20; i++ {
txHash := unorderedtx.TxHash{byte(i)}
require.False(t, txm.Contains(txHash))
}
}
func TestUnorderedTxManager_InitEmpty(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
require.NoError(t, txm.OnInit())
}
func TestUnorderedTxManager_CloseInit(t *testing.T) {
dataDir := t.TempDir()
txm := unorderedtx.NewManager(dataDir)
txm.Start()
// add a handful of unordered txs
for i := 0; i < 100; i++ {
txm.Add(unorderedtx.TxHash{byte(i)}, time.Now())
}
// close the manager, which should flush all unexpired txs to file
require.NoError(t, txm.Close())
// create a new manager, start it
txm2 := unorderedtx.NewManager(dataDir)
defer func() {
require.NoError(t, txm2.Close())
}()
// start and execute OnInit, which should load the unexpired txs from file
txm2.Start()
require.NoError(t, txm2.OnInit())
require.Equal(t, 100, txm2.Size())
for i := 0; i < 100; i++ {
require.True(t, txm2.Contains(unorderedtx.TxHash{byte(i)}))
}
}
func TestUnorderedTxManager_Flow(t *testing.T) {
txm := unorderedtx.NewManager(t.TempDir())
defer func() {
require.NoError(t, txm.Close())
}()
txm.Start()
currentTime := time.Now()
// Seed the manager with a txs, some of which should eventually be purged and
// the others will remain. Txs with TTL less than or equal to 50 should be purged.
for i := 1; i <= 100; i++ {
txHash := unorderedtx.TxHash{byte(i)}
if i <= 50 {
txm.Add(txHash, currentTime.Add(time.Millisecond*500*time.Duration(i)))
} else {
txm.Add(txHash, currentTime.Add(time.Hour))
}
}
// start a goroutine that mimics new blocks being made every 500ms
doneBlockCh := make(chan bool)
go func() {
ticker := time.NewTicker(time.Millisecond * 500)
defer ticker.Stop()
for t := range ticker.C {
txm.OnNewBlock(t)
if t.After(currentTime.Add(time.Millisecond * 500 * time.Duration(50))) {
doneBlockCh <- true
return
}
}
}()
// Eventually all the txs that should be expired by block 50 should be purged.
// The remaining txs should remain.
require.Eventually(
t,
func() bool {
return txm.Size() == 50
},
2*time.Minute,
5*time.Second,
)
<-doneBlockCh
}

View File

@ -0,0 +1,94 @@
package unorderedtx
import (
"encoding/binary"
"errors"
"io"
"time"
snapshot "cosmossdk.io/store/snapshots/types"
)
const (
txHashSize = 32
timeoutSize = 8
chunkSize = txHashSize + timeoutSize
)
var _ snapshot.ExtensionSnapshotter = &Snapshotter{}
const (
// SnapshotFormat defines the snapshot format of exported unordered transactions.
// No protobuf envelope, no metadata.
SnapshotFormat = 1
// SnapshotName defines the snapshot name of exported unordered transactions.
SnapshotName = "unordered_txs"
)
type Snapshotter struct {
m *Manager
}
func NewSnapshotter(m *Manager) *Snapshotter {
return &Snapshotter{m: m}
}
func (s *Snapshotter) SnapshotName() string {
return SnapshotName
}
func (s *Snapshotter) SnapshotFormat() uint32 {
return SnapshotFormat
}
func (s *Snapshotter) SupportedFormats() []uint32 {
return []uint32{SnapshotFormat}
}
func (s *Snapshotter) SnapshotExtension(height uint64, payloadWriter snapshot.ExtensionPayloadWriter) error {
// export all unordered transactions as a single blob
return s.m.exportSnapshot(height, payloadWriter)
}
func (s *Snapshotter) RestoreExtension(height uint64, format uint32, payloadReader snapshot.ExtensionPayloadReader) error {
if format == SnapshotFormat {
return s.restore(height, payloadReader)
}
return snapshot.ErrUnknownFormat
}
func (s *Snapshotter) restore(height uint64, payloadReader snapshot.ExtensionPayloadReader) error {
// the payload should be the entire set of unordered transactions
payload, err := payloadReader()
if err != nil {
if errors.Is(err, io.EOF) {
return io.ErrUnexpectedEOF
}
return err
}
if len(payload)%chunkSize != 0 {
return errors.New("invalid unordered txs payload length")
}
var i int
for i < len(payload) {
var txHash TxHash
copy(txHash[:], payload[i:i+txHashSize])
timestamp := binary.BigEndian.Uint64(payload[i+txHashSize : i+chunkSize])
// add all txs, we don't care at this point if they are expired,
// we'll let the purge loop handle that
if timestamp != 0 {
s.m.Add(txHash, time.Unix(int64(timestamp), 0))
}
i += chunkSize
}
return nil
}

View File

@ -0,0 +1,66 @@
package unorderedtx_test
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/auth/ante/unorderedtx"
)
func TestSnapshotter(t *testing.T) {
dataDir := t.TempDir()
txm := unorderedtx.NewManager(dataDir)
currentTime := time.Now()
// add a handful of unordered txs
for i := 0; i < 100; i++ {
txm.Add(unorderedtx.TxHash{byte(i)}, currentTime.Add(time.Second*100))
}
var unorderedTxBz []byte
s := unorderedtx.NewSnapshotter(txm)
w := func(bz []byte) error {
unorderedTxBz = bz
return nil
}
err := s.SnapshotExtension(50, w)
require.NoError(t, err)
require.NotEmpty(t, unorderedTxBz)
pr := func() ([]byte, error) {
return unorderedTxBz, nil
}
// restore with an invalid format which should result in an error
err = s.RestoreExtension(50, 2, pr)
require.Error(t, err)
// restore with timestamp > timeout time which should result in all unordered txs synced,
// even the ones that have timed out.
txm2 := unorderedtx.NewManager(dataDir)
s2 := unorderedtx.NewSnapshotter(txm2)
err = s2.RestoreExtension(1, unorderedtx.SnapshotFormat, pr)
require.NoError(t, err)
require.Equal(t, 100, txm2.Size())
// start the manager and wait a bit for the background purge loop to run
txm2.Start()
txm2.OnNewBlock(currentTime.Add(time.Second * 200)) // blocks until channel is read in purge loop
// the loop runs every 5 seconds, so we need to wait for that
require.Eventually(t, func() bool { return txm2.Size() == 0 }, 6*time.Second, 500*time.Millisecond)
// restore with timestamp < timeout time which should result in all unordered txs synced
txm3 := unorderedtx.NewManager(dataDir)
s3 := unorderedtx.NewSnapshotter(txm3)
err = s3.RestoreExtension(uint64(currentTime.Add(time.Second*50).Unix()), unorderedtx.SnapshotFormat, pr)
require.NoError(t, err)
require.Equal(t, 100, txm3.Size())
for i := 0; i < 100; i++ {
require.True(t, txm3.Contains(unorderedtx.TxHash{byte(i)}))
}
}

View File

@ -22,6 +22,6 @@ type Tx interface {
types.TxWithMemo
types.FeeTx
types.TxWithTimeoutHeight
types.TxWithUnordered
types.HasValidateBasic
}

View File

@ -3,6 +3,7 @@ package tx
import (
"bytes"
"fmt"
"time"
"github.com/cosmos/gogoproto/proto"
protov2 "google.golang.org/protobuf/proto"
@ -85,6 +86,18 @@ func (w *wrapper) GetMsgsV2() ([]protov2.Message, error) {
return w.msgsV2, nil
}
func (w *wrapper) SetTimeoutTimestamp(timestamp time.Time) {
w.tx.Body.TimeoutTimestamp = &timestamp
}
func (w *wrapper) GetTimeoutTimeStamp() time.Time {
t := w.tx.Body.TimeoutTimestamp
if t == nil {
return time.Time{}
}
return *t
}
func (w *wrapper) ValidateBasic() error {
if w.tx == nil {
return fmt.Errorf("bad Tx")
@ -221,6 +234,11 @@ func (w *wrapper) GetTimeoutHeight() uint64 {
return w.tx.Body.TimeoutHeight
}
// GetUnordered returns the transaction's unordered field (if set).
func (w *wrapper) GetUnordered() bool {
return w.tx.Body.Unordered
}
func (w *wrapper) GetSignaturesV2() ([]signing.SignatureV2, error) {
signerInfos := w.tx.AuthInfo.SignerInfos
sigs := w.tx.Signatures
@ -283,6 +301,13 @@ func (w *wrapper) SetTimeoutHeight(height uint64) {
w.bodyBz = nil
}
func (w *wrapper) SetUnordered(v bool) {
w.tx.Body.Unordered = v
// set bodyBz to nil because the cached bodyBz no longer matches tx.Body
w.bodyBz = nil
}
func (w *wrapper) SetMemo(memo string) {
w.tx.Body.Memo = memo

View File

@ -70,6 +70,8 @@ func TestUnknownFields(t *testing.T) {
shouldAminoErr: fmt.Sprintf("%s: %s", aminoNonCriticalFieldsError, sdkerrors.ErrInvalidRequest.Error()),
},
{
// If new fields are added to TxBody the number for some_new_field in the proto definition must be set to
// one that it's not used in TxBody.
name: "critical fields in TxBody should error on decode",
body: &testdata.TestUpdatedTxBody{
Memo: "foo",

View File

@ -28,12 +28,14 @@ require (
golang.org/x/net v0.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
google.golang.org/grpc v1.70.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace cosmossdk.io/api => ../../api
// NOTE: we do not want to replace to the development version of cosmossdk.io/api yet
// Until https://github.com/cosmos/cosmos-sdk/issues/19228 is resolved
// We are tagging x/tx v0.14+ from main and v0.13 from release/v0.50.x and must keep using released versions of x/tx dependencies

View File

@ -1,5 +1,3 @@
cosmossdk.io/api v0.7.4 h1:sPo8wKwCty1lht8kgL3J7YL1voJywP3YWuA5JKkBz30=
cosmossdk.io/api v0.7.4/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38=
cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo=
cosmossdk.io/core v0.11.0/go.mod h1:LaTtayWBSoacF5xNzoF8tmLhehqlA9z1SWiPuNC6X1w=
cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0=
@ -73,10 +71,10 @@ golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a h1:OAiGFfOiA0v9MRYsSidp3ubZaBnteRUyn3xB2ZQ5G/E=
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a/go.mod h1:jehYqy3+AhJU9ve55aNOaSml7wUXjF9x6z2LcCfpAhY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:hgh8P4EuoxpsuKMXX/To36nOFD7vixReXgn8lPGnt+o=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk=
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=

View File

@ -88,7 +88,6 @@ func TestDynamicpb(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
any, err := anyutil.New(tc.msg)
require.NoError(t, err)

View File

@ -27,7 +27,6 @@ func TestDecJSONTestcases(t *testing.T) {
require.NoError(t, err)
for _, tc := range testcases {
tc := tc
t.Run(tc[0], func(t *testing.T) {
r, err := textual.GetFieldValueRenderer(fieldDescriptorFromName("SDKDEC"))
require.NoError(t, err)

View File

@ -32,7 +32,6 @@ func TestDispatcher(t *testing.T) {
}
for _, tc := range testcases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
textual, err := textual.NewSignModeHandler(textual.SignModeOptions{CoinMetadataQuerier: EmptyCoinMetadataQuerier})
require.NoError(t, err)

View File

@ -232,6 +232,8 @@
],
"memo": "> ⚛️\\u269B⚛ ",
"timeout_height": 20,
"unordered": true,
"timeout_timestamp": "2042-01-01T00:00:20Z",
"extension_options": [
{
"@type": "/cosmos.base.v1beta1.Coin",
@ -385,7 +387,9 @@
{ "title": "Non critical extension options (1/1)", "content": "/cosmos.auth.v1beta1.Params", "indent": 1, "expert": true },
{ "title": "Max memo characters", "content": "10", "indent": 2, "expert": true },
{ "content": "End of Non critical extension options", "expert": true },
{ "title": "Hash of raw bytes", "content": "e7be7808de4985bd609811d2a32805cb233c168c7d247d61d37f4a6dd4cf3a2a", "expert": true }
{ "title": "Hash of raw bytes", "content": "9c8e99e281e501bb8778b0361dd574c764e54d96ba354a8abc9ccd2ea18e3e06", "expert": true },
{ "title": "Unordered", "content": "True", "expert": true },
{"title": "Timeout timestamp", "content": "2042-01-01T00:00:20Z", "expert": true}
]
}
]

View File

@ -4,8 +4,30 @@ deps:
- remote: buf.build
owner: cosmos
repository: cosmos-proto
commit: 1935555c206d4afb9e94615dfd0fad31
commit: 04467658e59e44bbb22fe568206e1f70
digest: shake256:73a640bd60e0c523b0f8237ff34eab67c45a38b64bbbde1d80224819d272dbf316ac183526bd245f994af6608b025f5130483d0133c5edd385531326b5990466
- remote: buf.build
owner: cosmos
repository: cosmos-sdk
commit: 05419252bcc241ea8023acf1ed4cadc5
digest: shake256:1e54a48c19a8b59d35e0a7efa76402939f515f2d8005df099856f24c37c20a52800308f025abb8cffcd014d437b49707388aaca4865d9d063d8f25d5d4eb77d5
- remote: buf.build
owner: cosmos
repository: gogo-proto
commit: 6652e3443c3b4504bb3bf82e73a7e409
commit: 88ef6483f90f478fb938c37dde52ece3
digest: shake256:89c45df2aa11e0cff97b0d695436713db3d993d76792e9f8dc1ae90e6ab9a9bec55503d48ceedd6b86069ab07d3041b32001b2bfe0227fa725dd515ff381e5ba
- remote: buf.build
owner: googleapis
repository: googleapis
commit: 7e6f6e774e29406da95bd61cdcdbc8bc
digest: shake256:fe43dd2265ea0c07d76bd925eeba612667cf4c948d2ce53d6e367e1b4b3cb5fa69a51e6acb1a6a50d32f894f054a35e6c0406f6808a483f2752e10c866ffbf73
- remote: buf.build
owner: protocolbuffers
repository: wellknowntypes
commit: 657250e6a39648cbb169d079a60bd9ba
digest: shake256:00de25001b8dd2e29d85fc4bcc3ede7aed886d76d67f5e0f7a9b320b90f871d3eb73507d50818d823a0512f3f8db77a11c043685528403e31ff3fef18323a9fb
- remote: buf.build
owner: tendermint
repository: tendermint
commit: 33ed361a90514289beabf3189e1d7665
digest: shake256:038267e06294714fd883610626554b04a127b576b4e253befb4206cb72d5d3c1eeccacd4b9ec8e3fb891f7c14e1cb0f770c077d2989638995b0a61c85afedb1d

View File

@ -1,7 +1,9 @@
version: v1
deps:
- buf.build/cosmos/cosmos-sdk
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/gogo-proto
- buf.build/protocolbuffers/wellknowntypes:v23.4
lint:
use:
- DEFAULT

View File

@ -4,6 +4,7 @@ import "cosmos/base/v1beta1/coin.proto";
import "cosmos/tx/v1beta1/tx.proto";
import "cosmos_proto/cosmos.proto";
import "google/protobuf/any.proto";
import "google/protobuf/timestamp.proto";
// TextualData represents all the information needed to generate
// the textual SignDoc (which is []Screen encoded to CBOR). It is meant to be
@ -83,4 +84,6 @@ message Envelope {
repeated google.protobuf.Any extension_options = 16;
repeated google.protobuf.Any non_critical_extension_options = 17;
string hash_of_raw_bytes = 18;
bool unordered = 19;
google.protobuf.Timestamp timeout_timestamp = 20;
}

View File

@ -11,6 +11,7 @@ import (
protoiface "google.golang.org/protobuf/runtime/protoiface"
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"
@ -1344,57 +1345,6 @@ func (x *_Envelope_8_list) IsValid() bool {
return x.list != nil
}
var _ protoreflect.List = (*_Envelope_11_list)(nil)
type _Envelope_11_list struct {
list *[]*v1beta1.Coin
}
func (x *_Envelope_11_list) Len() int {
if x.list == nil {
return 0
}
return len(*x.list)
}
func (x *_Envelope_11_list) Get(i int) protoreflect.Value {
return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect())
}
func (x *_Envelope_11_list) Set(i int, value protoreflect.Value) {
valueUnwrapped := value.Message()
concreteValue := valueUnwrapped.Interface().(*v1beta1.Coin)
(*x.list)[i] = concreteValue
}
func (x *_Envelope_11_list) Append(value protoreflect.Value) {
valueUnwrapped := value.Message()
concreteValue := valueUnwrapped.Interface().(*v1beta1.Coin)
*x.list = append(*x.list, concreteValue)
}
func (x *_Envelope_11_list) AppendMutable() protoreflect.Value {
v := new(v1beta1.Coin)
*x.list = append(*x.list, v)
return protoreflect.ValueOfMessage(v.ProtoReflect())
}
func (x *_Envelope_11_list) Truncate(n int) {
for i := n; i < len(*x.list); i++ {
(*x.list)[i] = nil
}
*x.list = (*x.list)[:n]
}
func (x *_Envelope_11_list) NewElement() protoreflect.Value {
v := new(v1beta1.Coin)
return protoreflect.ValueOfMessage(v.ProtoReflect())
}
func (x *_Envelope_11_list) IsValid() bool {
return x.list != nil
}
var _ protoreflect.List = (*_Envelope_15_list)(nil)
type _Envelope_15_list struct {
@ -1560,14 +1510,14 @@ var (
fd_Envelope_fees protoreflect.FieldDescriptor
fd_Envelope_fee_payer protoreflect.FieldDescriptor
fd_Envelope_fee_granter protoreflect.FieldDescriptor
fd_Envelope_tip protoreflect.FieldDescriptor
fd_Envelope_tipper protoreflect.FieldDescriptor
fd_Envelope_gas_limit protoreflect.FieldDescriptor
fd_Envelope_timeout_height protoreflect.FieldDescriptor
fd_Envelope_other_signer protoreflect.FieldDescriptor
fd_Envelope_extension_options protoreflect.FieldDescriptor
fd_Envelope_non_critical_extension_options protoreflect.FieldDescriptor
fd_Envelope_hash_of_raw_bytes protoreflect.FieldDescriptor
fd_Envelope_unordered protoreflect.FieldDescriptor
fd_Envelope_timeout_timestamp protoreflect.FieldDescriptor
)
func init() {
@ -1583,14 +1533,14 @@ func init() {
fd_Envelope_fees = md_Envelope.Fields().ByName("fees")
fd_Envelope_fee_payer = md_Envelope.Fields().ByName("fee_payer")
fd_Envelope_fee_granter = md_Envelope.Fields().ByName("fee_granter")
fd_Envelope_tip = md_Envelope.Fields().ByName("tip")
fd_Envelope_tipper = md_Envelope.Fields().ByName("tipper")
fd_Envelope_gas_limit = md_Envelope.Fields().ByName("gas_limit")
fd_Envelope_timeout_height = md_Envelope.Fields().ByName("timeout_height")
fd_Envelope_other_signer = md_Envelope.Fields().ByName("other_signer")
fd_Envelope_extension_options = md_Envelope.Fields().ByName("extension_options")
fd_Envelope_non_critical_extension_options = md_Envelope.Fields().ByName("non_critical_extension_options")
fd_Envelope_hash_of_raw_bytes = md_Envelope.Fields().ByName("hash_of_raw_bytes")
fd_Envelope_unordered = md_Envelope.Fields().ByName("unordered")
fd_Envelope_timeout_timestamp = md_Envelope.Fields().ByName("timeout_timestamp")
}
var _ protoreflect.Message = (*fastReflection_Envelope)(nil)
@ -1718,18 +1668,6 @@ func (x *fastReflection_Envelope) Range(f func(protoreflect.FieldDescriptor, pro
return
}
}
if len(x.Tip) != 0 {
value := protoreflect.ValueOfList(&_Envelope_11_list{list: &x.Tip})
if !f(fd_Envelope_tip, value) {
return
}
}
if x.Tipper != "" {
value := protoreflect.ValueOfString(x.Tipper)
if !f(fd_Envelope_tipper, value) {
return
}
}
if x.GasLimit != uint64(0) {
value := protoreflect.ValueOfUint64(x.GasLimit)
if !f(fd_Envelope_gas_limit, value) {
@ -1766,6 +1704,18 @@ func (x *fastReflection_Envelope) Range(f func(protoreflect.FieldDescriptor, pro
return
}
}
if x.Unordered != false {
value := protoreflect.ValueOfBool(x.Unordered)
if !f(fd_Envelope_unordered, value) {
return
}
}
if x.TimeoutTimestamp != nil {
value := protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect())
if !f(fd_Envelope_timeout_timestamp, value) {
return
}
}
}
// Has reports whether a field is populated.
@ -1801,10 +1751,6 @@ func (x *fastReflection_Envelope) Has(fd protoreflect.FieldDescriptor) bool {
return x.FeePayer != ""
case "Envelope.fee_granter":
return x.FeeGranter != ""
case "Envelope.tip":
return len(x.Tip) != 0
case "Envelope.tipper":
return x.Tipper != ""
case "Envelope.gas_limit":
return x.GasLimit != uint64(0)
case "Envelope.timeout_height":
@ -1817,6 +1763,10 @@ func (x *fastReflection_Envelope) Has(fd protoreflect.FieldDescriptor) bool {
return len(x.NonCriticalExtensionOptions) != 0
case "Envelope.hash_of_raw_bytes":
return x.HashOfRawBytes != ""
case "Envelope.unordered":
return x.Unordered != false
case "Envelope.timeout_timestamp":
return x.TimeoutTimestamp != nil
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -1853,10 +1803,6 @@ func (x *fastReflection_Envelope) Clear(fd protoreflect.FieldDescriptor) {
x.FeePayer = ""
case "Envelope.fee_granter":
x.FeeGranter = ""
case "Envelope.tip":
x.Tip = nil
case "Envelope.tipper":
x.Tipper = ""
case "Envelope.gas_limit":
x.GasLimit = uint64(0)
case "Envelope.timeout_height":
@ -1869,6 +1815,10 @@ func (x *fastReflection_Envelope) Clear(fd protoreflect.FieldDescriptor) {
x.NonCriticalExtensionOptions = nil
case "Envelope.hash_of_raw_bytes":
x.HashOfRawBytes = ""
case "Envelope.unordered":
x.Unordered = false
case "Envelope.timeout_timestamp":
x.TimeoutTimestamp = nil
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -1921,15 +1871,6 @@ func (x *fastReflection_Envelope) Get(descriptor protoreflect.FieldDescriptor) p
case "Envelope.fee_granter":
value := x.FeeGranter
return protoreflect.ValueOfString(value)
case "Envelope.tip":
if len(x.Tip) == 0 {
return protoreflect.ValueOfList(&_Envelope_11_list{})
}
listValue := &_Envelope_11_list{list: &x.Tip}
return protoreflect.ValueOfList(listValue)
case "Envelope.tipper":
value := x.Tipper
return protoreflect.ValueOfString(value)
case "Envelope.gas_limit":
value := x.GasLimit
return protoreflect.ValueOfUint64(value)
@ -1957,6 +1898,12 @@ func (x *fastReflection_Envelope) Get(descriptor protoreflect.FieldDescriptor) p
case "Envelope.hash_of_raw_bytes":
value := x.HashOfRawBytes
return protoreflect.ValueOfString(value)
case "Envelope.unordered":
value := x.Unordered
return protoreflect.ValueOfBool(value)
case "Envelope.timeout_timestamp":
value := x.TimeoutTimestamp
return protoreflect.ValueOfMessage(value.ProtoReflect())
default:
if descriptor.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -2001,12 +1948,6 @@ func (x *fastReflection_Envelope) Set(fd protoreflect.FieldDescriptor, value pro
x.FeePayer = value.Interface().(string)
case "Envelope.fee_granter":
x.FeeGranter = value.Interface().(string)
case "Envelope.tip":
lv := value.List()
clv := lv.(*_Envelope_11_list)
x.Tip = *clv.list
case "Envelope.tipper":
x.Tipper = value.Interface().(string)
case "Envelope.gas_limit":
x.GasLimit = value.Uint()
case "Envelope.timeout_height":
@ -2025,6 +1966,10 @@ func (x *fastReflection_Envelope) Set(fd protoreflect.FieldDescriptor, value pro
x.NonCriticalExtensionOptions = *clv.list
case "Envelope.hash_of_raw_bytes":
x.HashOfRawBytes = value.Interface().(string)
case "Envelope.unordered":
x.Unordered = value.Bool()
case "Envelope.timeout_timestamp":
x.TimeoutTimestamp = value.Message().Interface().(*timestamppb.Timestamp)
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -2062,12 +2007,6 @@ func (x *fastReflection_Envelope) Mutable(fd protoreflect.FieldDescriptor) proto
}
value := &_Envelope_8_list{list: &x.Fees}
return protoreflect.ValueOfList(value)
case "Envelope.tip":
if x.Tip == nil {
x.Tip = []*v1beta1.Coin{}
}
value := &_Envelope_11_list{list: &x.Tip}
return protoreflect.ValueOfList(value)
case "Envelope.other_signer":
if x.OtherSigner == nil {
x.OtherSigner = []*v1beta11.SignerInfo{}
@ -2086,6 +2025,11 @@ func (x *fastReflection_Envelope) Mutable(fd protoreflect.FieldDescriptor) proto
}
value := &_Envelope_17_list{list: &x.NonCriticalExtensionOptions}
return protoreflect.ValueOfList(value)
case "Envelope.timeout_timestamp":
if x.TimeoutTimestamp == nil {
x.TimeoutTimestamp = new(timestamppb.Timestamp)
}
return protoreflect.ValueOfMessage(x.TimeoutTimestamp.ProtoReflect())
case "Envelope.chain_id":
panic(fmt.Errorf("field chain_id of message Envelope is not mutable"))
case "Envelope.account_number":
@ -2100,14 +2044,14 @@ func (x *fastReflection_Envelope) Mutable(fd protoreflect.FieldDescriptor) proto
panic(fmt.Errorf("field fee_payer of message Envelope is not mutable"))
case "Envelope.fee_granter":
panic(fmt.Errorf("field fee_granter of message Envelope is not mutable"))
case "Envelope.tipper":
panic(fmt.Errorf("field tipper of message Envelope is not mutable"))
case "Envelope.gas_limit":
panic(fmt.Errorf("field gas_limit of message Envelope is not mutable"))
case "Envelope.timeout_height":
panic(fmt.Errorf("field timeout_height of message Envelope is not mutable"))
case "Envelope.hash_of_raw_bytes":
panic(fmt.Errorf("field hash_of_raw_bytes of message Envelope is not mutable"))
case "Envelope.unordered":
panic(fmt.Errorf("field unordered of message Envelope is not mutable"))
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -2144,11 +2088,6 @@ func (x *fastReflection_Envelope) NewField(fd protoreflect.FieldDescriptor) prot
return protoreflect.ValueOfString("")
case "Envelope.fee_granter":
return protoreflect.ValueOfString("")
case "Envelope.tip":
list := []*v1beta1.Coin{}
return protoreflect.ValueOfList(&_Envelope_11_list{list: &list})
case "Envelope.tipper":
return protoreflect.ValueOfString("")
case "Envelope.gas_limit":
return protoreflect.ValueOfUint64(uint64(0))
case "Envelope.timeout_height":
@ -2164,6 +2103,11 @@ func (x *fastReflection_Envelope) NewField(fd protoreflect.FieldDescriptor) prot
return protoreflect.ValueOfList(&_Envelope_17_list{list: &list})
case "Envelope.hash_of_raw_bytes":
return protoreflect.ValueOfString("")
case "Envelope.unordered":
return protoreflect.ValueOfBool(false)
case "Envelope.timeout_timestamp":
m := new(timestamppb.Timestamp)
return protoreflect.ValueOfMessage(m.ProtoReflect())
default:
if fd.IsExtension() {
panic(fmt.Errorf("proto3 declared messages do not support extensions: Envelope"))
@ -2275,16 +2219,6 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
if len(x.Tip) > 0 {
for _, e := range x.Tip {
l = options.Size(e)
n += 1 + l + runtime.Sov(uint64(l))
}
}
l = len(x.Tipper)
if l > 0 {
n += 1 + l + runtime.Sov(uint64(l))
}
if x.GasLimit != 0 {
n += 1 + runtime.Sov(uint64(x.GasLimit))
}
@ -2313,6 +2247,13 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
if l > 0 {
n += 2 + l + runtime.Sov(uint64(l))
}
if x.Unordered {
n += 3
}
if x.TimeoutTimestamp != nil {
l = options.Size(x.TimeoutTimestamp)
n += 2 + l + runtime.Sov(uint64(l))
}
if x.unknownFields != nil {
n += len(x.unknownFields)
}
@ -2342,6 +2283,34 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
i -= len(x.unknownFields)
copy(dAtA[i:], x.unknownFields)
}
if x.TimeoutTimestamp != nil {
encoded, err := options.Marshal(x.TimeoutTimestamp)
if err != nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded)))
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0xa2
}
if x.Unordered {
i--
if x.Unordered {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x1
i--
dAtA[i] = 0x98
}
if len(x.HashOfRawBytes) > 0 {
i -= len(x.HashOfRawBytes)
copy(dAtA[i:], x.HashOfRawBytes)
@ -2413,29 +2382,6 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
i--
dAtA[i] = 0x68
}
if len(x.Tipper) > 0 {
i -= len(x.Tipper)
copy(dAtA[i:], x.Tipper)
i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Tipper)))
i--
dAtA[i] = 0x62
}
if len(x.Tip) > 0 {
for iNdEx := len(x.Tip) - 1; iNdEx >= 0; iNdEx-- {
encoded, err := options.Marshal(x.Tip[iNdEx])
if err != nil {
return protoiface.MarshalOutput{
NoUnkeyedLiterals: input.NoUnkeyedLiterals,
Buf: input.Buf,
}, err
}
i -= len(encoded)
copy(dAtA[i:], encoded)
i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded)))
i--
dAtA[i] = 0x5a
}
}
if len(x.FeeGranter) > 0 {
i -= len(x.FeeGranter)
copy(dAtA[i:], x.FeeGranter)
@ -2878,72 +2824,6 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
}
x.FeeGranter = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 11:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Tip", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Tip = append(x.Tip, &v1beta1.Coin{})
if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Tip[len(x.Tip)-1]); err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
case 12:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Tipper", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
x.Tipper = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 13:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field GasLimit", wireType)
@ -3116,6 +2996,62 @@ func (x *fastReflection_Envelope) ProtoMethods() *protoiface.Methods {
}
x.HashOfRawBytes = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 19:
if wireType != 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Unordered", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
x.Unordered = bool(v != 0)
case 20:
if wireType != 2 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field TimeoutTimestamp", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow
}
if iNdEx >= l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength
}
if postIndex > l {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF
}
if x.TimeoutTimestamp == nil {
x.TimeoutTimestamp = &timestamppb.Timestamp{}
}
if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.TimeoutTimestamp); err != nil {
return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := runtime.Skip(dAtA[iNdEx:])
@ -3165,7 +3101,7 @@ const (
)
// TextualData represents all the information needed to generate
// the textual SignDoc (which is []Screen encoded to XBOR). It is meant to be
// the textual SignDoc (which is []Screen encoded to CBOR). It is meant to be
// used as an internal type in Textual's implementations.
type TextualData struct {
state protoimpl.MessageState
@ -3228,7 +3164,8 @@ func (x *TextualData) GetSignerData() *SignerData {
// isn't included in the transaction body itself.
//
// It is the same struct as signing.SignerData, but only used internally
// in Textual because we need it as a proto.Message.
// in Textual because we need it as a proto.Message. If that struct is updated,
// then this proto SignerData also needs to be modified.
type SignerData struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -3337,14 +3274,14 @@ type Envelope struct {
Fees []*v1beta1.Coin `protobuf:"bytes,8,rep,name=fees,proto3" json:"fees,omitempty"`
FeePayer string `protobuf:"bytes,9,opt,name=fee_payer,json=feePayer,proto3" json:"fee_payer,omitempty"`
FeeGranter string `protobuf:"bytes,10,opt,name=fee_granter,json=feeGranter,proto3" json:"fee_granter,omitempty"`
Tip []*v1beta1.Coin `protobuf:"bytes,11,rep,name=tip,proto3" json:"tip,omitempty"`
Tipper string `protobuf:"bytes,12,opt,name=tipper,proto3" json:"tipper,omitempty"`
GasLimit uint64 `protobuf:"varint,13,opt,name=gas_limit,json=gasLimit,proto3" json:"gas_limit,omitempty"`
TimeoutHeight uint64 `protobuf:"varint,14,opt,name=timeout_height,json=timeoutHeight,proto3" json:"timeout_height,omitempty"`
OtherSigner []*v1beta11.SignerInfo `protobuf:"bytes,15,rep,name=other_signer,json=otherSigner,proto3" json:"other_signer,omitempty"`
ExtensionOptions []*anypb.Any `protobuf:"bytes,16,rep,name=extension_options,json=extensionOptions,proto3" json:"extension_options,omitempty"`
NonCriticalExtensionOptions []*anypb.Any `protobuf:"bytes,17,rep,name=non_critical_extension_options,json=nonCriticalExtensionOptions,proto3" json:"non_critical_extension_options,omitempty"`
HashOfRawBytes string `protobuf:"bytes,18,opt,name=hash_of_raw_bytes,json=hashOfRawBytes,proto3" json:"hash_of_raw_bytes,omitempty"`
Unordered bool `protobuf:"varint,19,opt,name=unordered,proto3" json:"unordered,omitempty"`
TimeoutTimestamp *timestamppb.Timestamp `protobuf:"bytes,20,opt,name=timeout_timestamp,json=timeoutTimestamp,proto3" json:"timeout_timestamp,omitempty"`
}
func (x *Envelope) Reset() {
@ -3437,20 +3374,6 @@ func (x *Envelope) GetFeeGranter() string {
return ""
}
func (x *Envelope) GetTip() []*v1beta1.Coin {
if x != nil {
return x.Tip
}
return nil
}
func (x *Envelope) GetTipper() string {
if x != nil {
return x.Tipper
}
return ""
}
func (x *Envelope) GetGasLimit() uint64 {
if x != nil {
return x.GasLimit
@ -3493,6 +3416,20 @@ func (x *Envelope) GetHashOfRawBytes() string {
return ""
}
func (x *Envelope) GetUnordered() bool {
if x != nil {
return x.Unordered
}
return false
}
func (x *Envelope) GetTimeoutTimestamp() *timestamppb.Timestamp {
if x != nil {
return x.TimeoutTimestamp
}
return nil
}
var File_textual_proto protoreflect.FileDescriptor
var file_textual_proto_rawDesc = []byte{
@ -3504,80 +3441,84 @@ var file_textual_proto_rawDesc = []byte{
0x6d, 0x6f, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0x82, 0x01, 0x0a, 0x0b, 0x54, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61, 0x74,
0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65, 0x73,
0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62, 0x79,
0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x49,
0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x0b, 0x73, 0x69, 0x67, 0x6e,
0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e,
0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x73, 0x69, 0x67, 0x6e,
0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x22, 0xc6, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e, 0x65,
0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x11, 0xd2, 0xb4, 0x2d, 0x0d, 0x41, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65,
0x73, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x02,
0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a,
0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18,
0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75,
0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65,
0x12, 0x2d, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79, 0x22,
0xfc, 0x05, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x08,
0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75,
0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52,
0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a,
0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04,
0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b,
0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x09,
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79,
0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65, 0x6d,
0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x2d, 0x0a,
0x04, 0x66, 0x65, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f,
0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61,
0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x04, 0x66, 0x65, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09,
0x66, 0x65, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x66, 0x65, 0x65, 0x50, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x65, 0x65,
0x5f, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x66, 0x65, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x2b, 0x0a, 0x03, 0x74, 0x69,
0x70, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73,
0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f,
0x69, 0x6e, 0x52, 0x03, 0x74, 0x69, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65,
0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x69, 0x70, 0x70, 0x65, 0x72, 0x12,
0x1b, 0x0a, 0x09, 0x67, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0d, 0x20, 0x01,
0x28, 0x04, 0x52, 0x08, 0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x25, 0x0a, 0x0e,
0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0e,
0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69,
0x67, 0x68, 0x74, 0x12, 0x40, 0x0a, 0x0c, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67,
0x6e, 0x65, 0x72, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d,
0x6f, 0x73, 0x2e, 0x74, 0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69,
0x67, 0x6e, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x53,
0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x10, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f,
0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x59, 0x0a, 0x1e, 0x6e, 0x6f, 0x6e, 0x5f,
0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69,
0x6f, 0x6e, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x1b, 0x6e, 0x6f, 0x6e, 0x43, 0x72, 0x69, 0x74, 0x69,
0x63, 0x61, 0x6c, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x11, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x6f, 0x66, 0x5f, 0x72,
0x61, 0x77, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e,
0x68, 0x61, 0x73, 0x68, 0x4f, 0x66, 0x52, 0x61, 0x77, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x3c,
0x42, 0x0c, 0x54, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
0x5a, 0x2a, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x74,
0x78, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x0b, 0x54, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x44, 0x61,
0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x6f, 0x64, 0x79, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x62, 0x6f, 0x64, 0x79, 0x42, 0x79, 0x74, 0x65,
0x73, 0x12, 0x26, 0x0a, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x5f, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x68,
0x49, 0x6e, 0x66, 0x6f, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x0b, 0x73, 0x69, 0x67,
0x6e, 0x65, 0x72, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b,
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0a, 0x73, 0x69, 0x67,
0x6e, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x22, 0xc6, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x67, 0x6e,
0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2b, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73,
0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x11, 0xd2, 0xb4, 0x2d, 0x0d, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72,
0x65, 0x73, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25,
0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72,
0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e,
0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63,
0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63,
0x65, 0x12, 0x2d, 0x0a, 0x07, 0x70, 0x75, 0x62, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x06, 0x70, 0x75, 0x62, 0x4b, 0x65, 0x79,
0x22, 0x9e, 0x06, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x12, 0x19, 0x0a,
0x08, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x63, 0x63, 0x6f,
0x75, 0x6e, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0d, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12,
0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x61,
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x61, 0x64,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
0x6b, 0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52,
0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x2e, 0x0a, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e,
0x79, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x65,
0x6d, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x65, 0x6d, 0x6f, 0x12, 0x2d,
0x0a, 0x04, 0x66, 0x65, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x63,
0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74,
0x61, 0x31, 0x2e, 0x43, 0x6f, 0x69, 0x6e, 0x52, 0x04, 0x66, 0x65, 0x65, 0x73, 0x12, 0x1b, 0x0a,
0x09, 0x66, 0x65, 0x65, 0x5f, 0x70, 0x61, 0x79, 0x65, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
0x52, 0x08, 0x66, 0x65, 0x65, 0x50, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x65,
0x65, 0x5f, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x66, 0x65, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x67,
0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08,
0x67, 0x61, 0x73, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04,
0x52, 0x0d, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12,
0x40, 0x0a, 0x0c, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x18,
0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x74,
0x78, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x65,
0x72, 0x12, 0x41, 0x0a, 0x11, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41,
0x6e, 0x79, 0x52, 0x10, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74,
0x69, 0x6f, 0x6e, 0x73, 0x12, 0x59, 0x0a, 0x1e, 0x6e, 0x6f, 0x6e, 0x5f, 0x63, 0x72, 0x69, 0x74,
0x69, 0x63, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x6f,
0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41,
0x6e, 0x79, 0x52, 0x1b, 0x6e, 0x6f, 0x6e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x45,
0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12,
0x29, 0x0a, 0x11, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x6f, 0x66, 0x5f, 0x72, 0x61, 0x77, 0x5f, 0x62,
0x79, 0x74, 0x65, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x68, 0x61, 0x73, 0x68,
0x4f, 0x66, 0x52, 0x61, 0x77, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x75, 0x6e,
0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x75,
0x6e, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65, 0x64, 0x12, 0x47, 0x0a, 0x11, 0x74, 0x69, 0x6d, 0x65,
0x6f, 0x75, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x14, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x10, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x42, 0x3e, 0x42, 0x0c, 0x54, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x50, 0x01, 0x5a, 0x2c, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69,
0x6f, 0x2f, 0x78, 0x2f, 0x74, 0x78, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x78, 0x74, 0x75, 0x61, 0x6c, 0x70,
0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -3594,12 +3535,13 @@ func file_textual_proto_rawDescGZIP() []byte {
var file_textual_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_textual_proto_goTypes = []interface{}{
(*TextualData)(nil), // 0: TextualData
(*SignerData)(nil), // 1: SignerData
(*Envelope)(nil), // 2: Envelope
(*anypb.Any)(nil), // 3: google.protobuf.Any
(*v1beta1.Coin)(nil), // 4: cosmos.base.v1beta1.Coin
(*v1beta11.SignerInfo)(nil), // 5: cosmos.tx.v1beta1.SignerInfo
(*TextualData)(nil), // 0: TextualData
(*SignerData)(nil), // 1: SignerData
(*Envelope)(nil), // 2: Envelope
(*anypb.Any)(nil), // 3: google.protobuf.Any
(*v1beta1.Coin)(nil), // 4: cosmos.base.v1beta1.Coin
(*v1beta11.SignerInfo)(nil), // 5: cosmos.tx.v1beta1.SignerInfo
(*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
}
var file_textual_proto_depIdxs = []int32{
1, // 0: TextualData.signer_data:type_name -> SignerData
@ -3607,10 +3549,10 @@ var file_textual_proto_depIdxs = []int32{
3, // 2: Envelope.public_key:type_name -> google.protobuf.Any
3, // 3: Envelope.message:type_name -> google.protobuf.Any
4, // 4: Envelope.fees:type_name -> cosmos.base.v1beta1.Coin
4, // 5: Envelope.tip:type_name -> cosmos.base.v1beta1.Coin
5, // 6: Envelope.other_signer:type_name -> cosmos.tx.v1beta1.SignerInfo
3, // 7: Envelope.extension_options:type_name -> google.protobuf.Any
3, // 8: Envelope.non_critical_extension_options:type_name -> google.protobuf.Any
5, // 5: Envelope.other_signer:type_name -> cosmos.tx.v1beta1.SignerInfo
3, // 6: Envelope.extension_options:type_name -> google.protobuf.Any
3, // 7: Envelope.non_critical_extension_options:type_name -> google.protobuf.Any
6, // 8: Envelope.timeout_timestamp:type_name -> google.protobuf.Timestamp
9, // [9:9] is the sub-list for method output_type
9, // [9:9] is the sub-list for method input_type
9, // [9:9] is the sub-list for extension type_name

View File

@ -79,6 +79,8 @@ func (vr txValueRenderer) Format(ctx context.Context, v protoreflect.Value) ([]S
FeeGranter: txAuthInfo.Fee.Granter,
GasLimit: txAuthInfo.Fee.GasLimit,
TimeoutHeight: txBody.TimeoutHeight,
TimeoutTimestamp: txBody.TimeoutTimestamp,
Unordered: txBody.Unordered,
ExtensionOptions: txBody.ExtensionOptions,
NonCriticalExtensionOptions: txBody.NonCriticalExtensionOptions,
HashOfRawBytes: getHash(textualData.BodyBytes, textualData.AuthInfoBytes),
@ -125,6 +127,8 @@ func (vr txValueRenderer) Format(ctx context.Context, v protoreflect.Value) ([]S
"Fee granter": {},
"Gas limit": {},
"Timeout height": {},
"Timeout timestamp": {},
"Unordered": {},
"Other signer": {},
"Extension options": {},
"Non critical extension options": {},
@ -229,6 +233,8 @@ func (vr txValueRenderer) Parse(ctx context.Context, screens []Screen) (protoref
Messages: envelope.Message,
Memo: envelope.Memo,
TimeoutHeight: envelope.TimeoutHeight,
TimeoutTimestamp: envelope.TimeoutTimestamp,
Unordered: envelope.Unordered,
ExtensionOptions: envelope.ExtensionOptions,
NonCriticalExtensionOptions: envelope.NonCriticalExtensionOptions,
}