From b36d9ca2c16d8b91947a47c1584cbd24601df5e6 Mon Sep 17 00:00:00 2001 From: swelf Date: Thu, 25 Jul 2024 19:04:11 +0300 Subject: [PATCH 01/60] icq MaxKvQueryKeysCount and MaxTransactionsFilters gov gated --- app/app.go | 8 +- proto/neutron/interchainqueries/params.proto | 6 + x/interchainqueries/keeper/migrations.go | 25 ++++ x/interchainqueries/keeper/msg_server.go | 19 ++- x/interchainqueries/keeper/msg_server_test.go | 4 +- .../migrations/v3/migration.go | 28 ++++ .../migrations/v3/migration_test.go | 83 ++++++++++++ x/interchainqueries/module.go | 11 ++ x/interchainqueries/types/constants.go | 2 +- x/interchainqueries/types/genesis.go | 4 +- x/interchainqueries/types/params.go | 26 ++-- x/interchainqueries/types/params.pb.go | 120 ++++++++++++++---- x/interchainqueries/types/tx.go | 22 ++-- x/interchainqueries/types/types.go | 7 +- x/interchainqueries/types/types_test.go | 44 +++---- 15 files changed, 320 insertions(+), 89 deletions(-) create mode 100644 x/interchainqueries/keeper/migrations.go create mode 100644 x/interchainqueries/migrations/v3/migration.go create mode 100644 x/interchainqueries/migrations/v3/migration_test.go diff --git a/app/app.go b/app/app.go index 87293d3f7..4ddaf0718 100644 --- a/app/app.go +++ b/app/app.go @@ -904,7 +904,13 @@ func New( icaHostIBCModule := icahost.NewIBCModule(app.ICAHostKeeper) - interchainQueriesModule := interchainqueries.NewAppModule(appCodec, app.InterchainQueriesKeeper, app.AccountKeeper, app.BankKeeper) + interchainQueriesModule := interchainqueries.NewAppModule( + appCodec, + keys[interchainqueriesmoduletypes.StoreKey], + app.InterchainQueriesKeeper, + app.AccountKeeper, + app.BankKeeper, + ) interchainTxsModule := interchaintxs.NewAppModule(appCodec, app.InterchainTxsKeeper, app.AccountKeeper, app.BankKeeper) contractManagerModule := contractmanager.NewAppModule(appCodec, app.ContractManagerKeeper) ibcHooksModule := ibchooks.NewAppModule(app.AccountKeeper) diff --git a/proto/neutron/interchainqueries/params.proto b/proto/neutron/interchainqueries/params.proto index 0dca4a206..7b05c1f58 100644 --- a/proto/neutron/interchainqueries/params.proto +++ b/proto/neutron/interchainqueries/params.proto @@ -23,4 +23,10 @@ message Params { // balance between network cleaning speed and EndBlock duration. A zero value // means no limit. uint64 tx_query_removal_limit = 3; + + // Maximum amount of keys in a registered key value query + uint64 max_kv_query_keys_count = 4; + + // max_transactions_filters defines maximum allowed amount of tx filters in msgRegisterInterchainQuery + uint64 max_transactions_filters = 5; } diff --git a/x/interchainqueries/keeper/migrations.go b/x/interchainqueries/keeper/migrations.go new file mode 100644 index 000000000..a036ea33e --- /dev/null +++ b/x/interchainqueries/keeper/migrations.go @@ -0,0 +1,25 @@ +package keeper + +import ( + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + v3 "github.com/neutron-org/neutron/v4/x/interchainqueries/migrations/v3" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey +} + +// NewMigrator returns a new Migrator. +func NewMigrator(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Migrator { + return Migrator{storeKey: storeKey, cdc: cdc} +} + +// Migrate2to3 migrates from version 2 to 3. +func (m Migrator) Migrate2to3(ctx sdk.Context) error { + return v3.MigrateParams(ctx, m.cdc, m.storeKey) +} diff --git a/x/interchainqueries/keeper/msg_server.go b/x/interchainqueries/keeper/msg_server.go index 384c9d6b1..9845c8455 100644 --- a/x/interchainqueries/keeper/msg_server.go +++ b/x/interchainqueries/keeper/msg_server.go @@ -35,14 +35,14 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { func (m msgServer) RegisterInterchainQuery(goCtx context.Context, msg *types.MsgRegisterInterchainQuery) (*types.MsgRegisterInterchainQueryResponse, error) { defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelRegisterInterchainQuery) + ctx := sdk.UnwrapSDKContext(goCtx) + ctx.Logger().Debug("RegisterInterchainQuery", "msg", msg) + params := m.GetParams(ctx) - if err := msg.Validate(); err != nil { + if err := msg.Validate(params); err != nil { return nil, errors.Wrap(err, "failed to validate MsgRegisterInterchainQuery") } - ctx := sdk.UnwrapSDKContext(goCtx) - ctx.Logger().Debug("RegisterInterchainQuery", "msg", msg) - senderAddr, err := sdk.AccAddressFromBech32(msg.Sender) if err != nil { m.Logger(ctx).Debug("RegisterInterchainQuery: failed to parse sender address", "sender_address", msg.Sender) @@ -62,8 +62,6 @@ func (m msgServer) RegisterInterchainQuery(goCtx context.Context, msg *types.Msg lastID := m.GetLastRegisteredQueryKey(ctx) lastID++ - params := m.GetParams(ctx) - registeredQuery := &types.RegisteredQuery{ Id: lastID, Owner: msg.Sender, @@ -122,12 +120,13 @@ func (m msgServer) RemoveInterchainQuery(goCtx context.Context, msg *types.MsgRe } func (m msgServer) UpdateInterchainQuery(goCtx context.Context, msg *types.MsgUpdateInterchainQueryRequest) (*types.MsgUpdateInterchainQueryResponse, error) { - if err := msg.Validate(); err != nil { - return nil, errors.Wrap(err, "failed to validate MsgUpdateInterchainQueryRequest") - } - ctx := sdk.UnwrapSDKContext(goCtx) ctx.Logger().Debug("UpdateInterchainQuery", "msg", msg) + params := m.GetParams(ctx) + + if err := msg.Validate(params); err != nil { + return nil, errors.Wrap(err, "failed to validate MsgUpdateInterchainQueryRequest") + } query, err := m.GetQueryByID(ctx, msg.GetQueryId()) if err != nil { diff --git a/x/interchainqueries/keeper/msg_server_test.go b/x/interchainqueries/keeper/msg_server_test.go index a92a7f6d8..efdc36bbf 100644 --- a/x/interchainqueries/keeper/msg_server_test.go +++ b/x/interchainqueries/keeper/msg_server_test.go @@ -99,7 +99,7 @@ func TestMsgRegisterInterchainQueryValidate(t *testing.T) { "too many keys", types.MsgRegisterInterchainQuery{ QueryType: string(types.InterchainQueryTypeKV), - Keys: make([]*types.KVKey, types.MaxKVQueryKeysCount+1), + Keys: make([]*types.KVKey, types.DefaultMaxKvQueryKeysCount+1), TransactionsFilter: "[]", ConnectionId: "connection-0", UpdatePeriod: 1, @@ -418,7 +418,7 @@ func TestMsgUpdateInterchainQueryRequestValidate(t *testing.T) { "too many keys", types.MsgUpdateInterchainQueryRequest{ QueryId: 1, - NewKeys: make([]*types.KVKey, types.MaxKVQueryKeysCount+1), + NewKeys: make([]*types.KVKey, types.DefaultMaxKvQueryKeysCount+1), NewUpdatePeriod: 0, Sender: testutil.TestOwnerAddress, }, diff --git a/x/interchainqueries/migrations/v3/migration.go b/x/interchainqueries/migrations/v3/migration.go new file mode 100644 index 000000000..a77e4bed8 --- /dev/null +++ b/x/interchainqueries/migrations/v3/migration.go @@ -0,0 +1,28 @@ +package v3 + +import ( + "fmt" + + store "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v4/x/interchainqueries/types" +) + +func MigrateParams(ctx sdk.Context, cdc codec.BinaryCodec, storeKey store.StoreKey) error { + var params types.Params + st := ctx.KVStore(storeKey) + bz := st.Get(types.ParamsKey) + if bz == nil { + return fmt.Errorf("no params stored in %s", types.ParamsKey) + } + + cdc.MustUnmarshal(bz, ¶ms) + params.MaxTransactionsFilters = types.DefaultMaxTransactionsFilters + params.MaxKvQueryKeysCount = types.DefaultMaxKvQueryKeysCount + bz = cdc.MustMarshal(¶ms) + st.Set(types.ParamsKey, bz) + return nil +} diff --git a/x/interchainqueries/migrations/v3/migration_test.go b/x/interchainqueries/migrations/v3/migration_test.go new file mode 100644 index 000000000..c36014df8 --- /dev/null +++ b/x/interchainqueries/migrations/v3/migration_test.go @@ -0,0 +1,83 @@ +package v3_test + +import ( + "testing" + + github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + "gopkg.in/yaml.v2" + + "github.com/neutron-org/neutron/v4/testutil" + v3 "github.com/neutron-org/neutron/v4/x/interchainqueries/migrations/v3" + "github.com/neutron-org/neutron/v4/x/interchainqueries/types" +) + +type V3ICQMigrationTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(V3ICQMigrationTestSuite)) +} + +// ParamsV2 defines the parameters for the module v2. +type ParamsV2 struct { + // Defines amount of blocks required before query becomes available for + // removal by anybody + QuerySubmitTimeout uint64 `protobuf:"varint,1,opt,name=query_submit_timeout,json=querySubmitTimeout,proto3" json:"query_submit_timeout,omitempty"` + // Amount of coins deposited for the query. + QueryDeposit github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,2,rep,name=query_deposit,json=queryDeposit,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"query_deposit"` + // Amount of tx hashes to be removed during a single EndBlock. Can vary to + // balance between network cleaning speed and EndBlock duration. A zero value + // means no limit. + TxQueryRemovalLimit uint64 `protobuf:"varint,3,opt,name=tx_query_removal_limit,json=txQueryRemovalLimit,proto3" json:"tx_query_removal_limit,omitempty"` +} + +func (p *ParamsV2) Reset() { *p = ParamsV2{} } +func (p *ParamsV2) ProtoMessage() {} + +// String implements the Stringer interface. +func (p ParamsV2) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} + +func (suite *V3ICQMigrationTestSuite) TestParamsMigration() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + storeKey = app.GetKey(types.StoreKey) + ctx = suite.ChainA.GetContext() + cdc = app.AppCodec() + ) + + // preinitialize v2 params + p := ParamsV2{ + QuerySubmitTimeout: types.DefaultQuerySubmitTimeout, + QueryDeposit: types.DefaultQueryDeposit, + TxQueryRemovalLimit: types.DefaultTxQueryRemovalLimit, + } + store := ctx.KVStore(storeKey) + bz, err := cdc.Marshal(&p) + suite.Require().NoError(err) + store.Set(types.ParamsKey, bz) + + paramsOld := app.InterchainQueriesKeeper.GetParams(ctx) + suite.Require().Equal(paramsOld.TxQueryRemovalLimit, p.TxQueryRemovalLimit) + suite.Require().Equal(paramsOld.QuerySubmitTimeout, p.QuerySubmitTimeout) + suite.Require().Equal(paramsOld.QueryDeposit, p.QueryDeposit) + suite.Require().Equal(paramsOld.MaxTransactionsFilters, uint64(0)) + suite.Require().Equal(paramsOld.MaxKvQueryKeysCount, uint64(0)) + + err = v3.MigrateParams(ctx, cdc, storeKey) + suite.Require().NoError(err) + + paramsNew := app.InterchainQueriesKeeper.GetParams(ctx) + params := types.Params{ + QuerySubmitTimeout: types.DefaultQuerySubmitTimeout, + QueryDeposit: types.DefaultQueryDeposit, + TxQueryRemovalLimit: types.DefaultTxQueryRemovalLimit, + MaxKvQueryKeysCount: types.DefaultMaxKvQueryKeysCount, + MaxTransactionsFilters: types.DefaultMaxTransactionsFilters, + } + suite.Require().Equal(params, paramsNew) +} diff --git a/x/interchainqueries/module.go b/x/interchainqueries/module.go index 4f9910975..cf1572bd7 100644 --- a/x/interchainqueries/module.go +++ b/x/interchainqueries/module.go @@ -5,6 +5,8 @@ import ( "encoding/json" "fmt" + storetypes "cosmossdk.io/store/types" + "cosmossdk.io/core/appmodule" abci "github.com/cometbft/cometbft/abci/types" @@ -103,6 +105,7 @@ var _ appmodule.AppModule = AppModule{} type AppModule struct { AppModuleBasic + storeKey storetypes.StoreKey keeper keeper.Keeper accountKeeper types.AccountKeeper bankKeeper types.BankKeeper @@ -110,12 +113,14 @@ type AppModule struct { func NewAppModule( cdc codec.Codec, + storeKey storetypes.StoreKey, keeper keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), + storeKey: storeKey, keeper: keeper, accountKeeper: accountKeeper, bankKeeper: bankKeeper, @@ -141,6 +146,12 @@ func (AppModule) QuerierRoute() string { return types.QuerierRoute } // RegisterServices registers a GRPC query service to respond to the // module-specific GRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { + m := keeper.NewMigrator(am.cdc, am.storeKey) + + if err := cfg.RegisterMigration(types.ModuleName, 2, m.Migrate2to3); err != nil { + panic(fmt.Sprintf("failed to migrate x/interchainqueries from version 2 to 3: %v", err)) + } + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) } diff --git a/x/interchainqueries/types/constants.go b/x/interchainqueries/types/constants.go index 4c93fbeff..fef80f236 100644 --- a/x/interchainqueries/types/constants.go +++ b/x/interchainqueries/types/constants.go @@ -1,3 +1,3 @@ package types -const ConsensusVersion = 2 +const ConsensusVersion = 3 diff --git a/x/interchainqueries/types/genesis.go b/x/interchainqueries/types/genesis.go index c00668e58..29cc30ae1 100644 --- a/x/interchainqueries/types/genesis.go +++ b/x/interchainqueries/types/genesis.go @@ -34,14 +34,14 @@ func (gs GenesisState) Validate() error { switch val.QueryType { case string(InterchainQueryTypeTX): - if err := ValidateTransactionsFilter(val.TransactionsFilter); err != nil { + if err := ValidateTransactionsFilter(val.TransactionsFilter, gs.Params.MaxTransactionsFilters); err != nil { return errors.Wrap(ErrInvalidTransactionsFilter, err.Error()) } case string(InterchainQueryTypeKV): if len(val.Keys) == 0 { return errors.Wrap(ErrEmptyKeys, "keys cannot be empty") } - if err := validateKeys(val.GetKeys()); err != nil { + if err := validateKeys(val.GetKeys(), gs.Params.MaxKvQueryKeysCount); err != nil { return err } default: diff --git a/x/interchainqueries/types/params.go b/x/interchainqueries/types/params.go index ce52e3689..063cefc28 100644 --- a/x/interchainqueries/types/params.go +++ b/x/interchainqueries/types/params.go @@ -14,12 +14,14 @@ import ( var _ paramtypes.ParamSet = (*Params)(nil) var ( - KeyQuerySubmitTimeout = []byte("QuerySubmitTimeout") - DefaultQuerySubmitTimeout = uint64(1036800) // One month, with block_time = 2.5s - KeyQueryDeposit = []byte("QueryDeposit") - DefaultQueryDeposit = sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(int64(1_000_000)))) - KeyTxQueryRemovalLimit = []byte("TxQueryRemovalLimit") - DefaultTxQueryRemovalLimit = uint64(10_000) + KeyQuerySubmitTimeout = []byte("QuerySubmitTimeout") + DefaultQuerySubmitTimeout = uint64(1036800) // One month, with block_time = 2.5s + KeyQueryDeposit = []byte("QueryDeposit") + DefaultQueryDeposit = sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(int64(1_000_000)))) + KeyTxQueryRemovalLimit = []byte("TxQueryRemovalLimit") + DefaultTxQueryRemovalLimit = uint64(10_000) + DefaultMaxKvQueryKeysCount = uint64(32) + DefaultMaxTransactionsFilters = uint64(32) ) // ParamKeyTable the param key table for launch module @@ -32,17 +34,19 @@ func ParamKeyTable() paramtypes.KeyTable { } // NewParams creates a new Params instance -func NewParams(querySubmitTimeout uint64, queryDeposit sdk.Coins, txQueryRemovalLimit uint64) Params { +func NewParams(querySubmitTimeout uint64, queryDeposit sdk.Coins, txQueryRemovalLimit, maxKvQueryKeysCount, maxTransactionsFilters uint64) Params { return Params{ - QuerySubmitTimeout: querySubmitTimeout, - QueryDeposit: queryDeposit, - TxQueryRemovalLimit: txQueryRemovalLimit, + QuerySubmitTimeout: querySubmitTimeout, + QueryDeposit: queryDeposit, + TxQueryRemovalLimit: txQueryRemovalLimit, + MaxKvQueryKeysCount: maxKvQueryKeysCount, + MaxTransactionsFilters: maxTransactionsFilters, } } // DefaultParams returns a default set of parameters func DefaultParams() Params { - return NewParams(DefaultQuerySubmitTimeout, DefaultQueryDeposit, DefaultTxQueryRemovalLimit) + return NewParams(DefaultQuerySubmitTimeout, DefaultQueryDeposit, DefaultTxQueryRemovalLimit, DefaultMaxKvQueryKeysCount, DefaultMaxTransactionsFilters) } // ParamSetPairs get the params.ParamSet diff --git a/x/interchainqueries/types/params.pb.go b/x/interchainqueries/types/params.pb.go index 5afc785e0..18d044b6f 100644 --- a/x/interchainqueries/types/params.pb.go +++ b/x/interchainqueries/types/params.pb.go @@ -36,6 +36,10 @@ type Params struct { // balance between network cleaning speed and EndBlock duration. A zero value // means no limit. TxQueryRemovalLimit uint64 `protobuf:"varint,3,opt,name=tx_query_removal_limit,json=txQueryRemovalLimit,proto3" json:"tx_query_removal_limit,omitempty"` + // Maximum amount of keys in a registered key value query + MaxKvQueryKeysCount uint64 `protobuf:"varint,4,opt,name=max_kv_query_keys_count,json=maxKvQueryKeysCount,proto3" json:"max_kv_query_keys_count,omitempty"` + // max_transactions_filters defines maximum allowed amount of tx filters in msgRegisterInterchainQuery + MaxTransactionsFilters uint64 `protobuf:"varint,5,opt,name=max_transactions_filters,json=maxTransactionsFilters,proto3" json:"max_transactions_filters,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -91,6 +95,20 @@ func (m *Params) GetTxQueryRemovalLimit() uint64 { return 0 } +func (m *Params) GetMaxKvQueryKeysCount() uint64 { + if m != nil { + return m.MaxKvQueryKeysCount + } + return 0 +} + +func (m *Params) GetMaxTransactionsFilters() uint64 { + if m != nil { + return m.MaxTransactionsFilters + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "neutron.interchainqueries.Params") } @@ -100,28 +118,32 @@ func init() { } var fileDescriptor_752a5f3346da64b1 = []byte{ - // 331 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x91, 0xb1, 0x4e, 0xf3, 0x30, - 0x10, 0xc7, 0x93, 0xaf, 0x55, 0x87, 0x7c, 0xb0, 0x84, 0x0a, 0xb5, 0x1d, 0xdc, 0x8a, 0x01, 0x75, - 0xa9, 0xdd, 0x52, 0x26, 0xd8, 0x0a, 0x23, 0x03, 0x14, 0x58, 0x58, 0xa2, 0x24, 0xb5, 0x52, 0x8b, - 0x3a, 0x17, 0xec, 0x4b, 0xd5, 0xbe, 0x05, 0x23, 0x23, 0x33, 0x4f, 0xd2, 0xb1, 0x23, 0x13, 0xa0, - 0x76, 0xe0, 0x35, 0x50, 0xec, 0x20, 0x21, 0xc1, 0xe4, 0x93, 0x7f, 0x77, 0xfe, 0xff, 0x74, 0xf6, - 0x0e, 0x53, 0x9e, 0xa3, 0x82, 0x94, 0x89, 0x14, 0xb9, 0x8a, 0xa7, 0xa1, 0x48, 0x1f, 0x72, 0xae, - 0x04, 0xd7, 0x2c, 0x0b, 0x55, 0x28, 0x35, 0xcd, 0x14, 0x20, 0xf8, 0xcd, 0xb2, 0x8f, 0xfe, 0xea, - 0x6b, 0x91, 0x18, 0xb4, 0x04, 0xcd, 0xa2, 0x50, 0x73, 0x36, 0x1f, 0x44, 0x1c, 0xc3, 0x01, 0x8b, - 0x41, 0xa4, 0x76, 0xb4, 0x55, 0x4f, 0x20, 0x01, 0x53, 0xb2, 0xa2, 0xb2, 0xb7, 0x07, 0x9f, 0xae, - 0x57, 0xbb, 0x34, 0x09, 0x7e, 0xdf, 0xab, 0x17, 0x6f, 0x2d, 0x03, 0x9d, 0x47, 0x52, 0x60, 0x80, - 0x42, 0x72, 0xc8, 0xb1, 0xe1, 0x76, 0xdc, 0x6e, 0x75, 0xec, 0x1b, 0x76, 0x6d, 0xd0, 0x8d, 0x25, - 0x7e, 0xe6, 0xed, 0xda, 0x89, 0x09, 0xcf, 0x40, 0x0b, 0x6c, 0xfc, 0xeb, 0x54, 0xba, 0xff, 0x8f, - 0x9a, 0xd4, 0xaa, 0xd0, 0x42, 0x85, 0x96, 0x2a, 0xf4, 0x0c, 0x44, 0x3a, 0xea, 0xaf, 0xde, 0xda, - 0xce, 0xcb, 0x7b, 0xbb, 0x9b, 0x08, 0x9c, 0xe6, 0x11, 0x8d, 0x41, 0xb2, 0xd2, 0xdb, 0x1e, 0x3d, - 0x3d, 0xb9, 0x67, 0xb8, 0xcc, 0xb8, 0x36, 0x03, 0x7a, 0xbc, 0x63, 0x12, 0xce, 0x6d, 0x80, 0x3f, - 0xf4, 0xf6, 0x71, 0x11, 0xd8, 0x50, 0xc5, 0x25, 0xcc, 0xc3, 0x59, 0x30, 0x13, 0x52, 0x60, 0xa3, - 0x62, 0x2c, 0xf7, 0x70, 0x71, 0x55, 0xc0, 0xb1, 0x65, 0x17, 0x05, 0x3a, 0xa9, 0x3e, 0x3d, 0xb7, - 0x9d, 0xd1, 0xed, 0x6a, 0x43, 0xdc, 0xf5, 0x86, 0xb8, 0x1f, 0x1b, 0xe2, 0x3e, 0x6e, 0x89, 0xb3, - 0xde, 0x12, 0xe7, 0x75, 0x4b, 0x9c, 0xbb, 0xd3, 0x1f, 0x32, 0xe5, 0x7e, 0x7b, 0xa0, 0x92, 0xef, - 0x9a, 0xcd, 0x8f, 0xd9, 0xe2, 0x8f, 0x8f, 0x31, 0x96, 0x51, 0xcd, 0xec, 0x71, 0xf8, 0x15, 0x00, - 0x00, 0xff, 0xff, 0xc7, 0x61, 0x00, 0x43, 0xc2, 0x01, 0x00, 0x00, + // 397 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x31, 0x8f, 0xd3, 0x30, + 0x14, 0xc7, 0x93, 0xbb, 0x72, 0x43, 0x80, 0x25, 0x9c, 0x8e, 0x5c, 0x87, 0xb4, 0x62, 0x40, 0x5d, + 0x1a, 0xb7, 0xb4, 0x03, 0x82, 0xad, 0x45, 0x2c, 0x65, 0x80, 0x52, 0x16, 0x96, 0xc8, 0x49, 0x4d, + 0x6a, 0xb5, 0xf6, 0x0b, 0xf6, 0x4b, 0x94, 0x7c, 0x0b, 0x46, 0x46, 0x66, 0x3e, 0x49, 0xc7, 0x6e, + 0x30, 0x01, 0x6a, 0xbf, 0x08, 0x8a, 0x1d, 0xa4, 0x4a, 0xdc, 0x94, 0xa7, 0xfc, 0xfc, 0xcb, 0xff, + 0x9f, 0xbc, 0x78, 0x4f, 0x25, 0x2b, 0x50, 0x81, 0x24, 0x5c, 0x22, 0x53, 0xe9, 0x86, 0x72, 0xf9, + 0xb9, 0x60, 0x8a, 0x33, 0x4d, 0x72, 0xaa, 0xa8, 0xd0, 0x51, 0xae, 0x00, 0xc1, 0xbf, 0x6d, 0xcf, + 0x45, 0xff, 0x9d, 0xeb, 0x86, 0x29, 0x68, 0x01, 0x9a, 0x24, 0x54, 0x33, 0x52, 0x8e, 0x13, 0x86, + 0x74, 0x4c, 0x52, 0xe0, 0xd2, 0xaa, 0xdd, 0xeb, 0x0c, 0x32, 0x30, 0x23, 0x69, 0x26, 0x7b, 0xf7, + 0xc9, 0x8f, 0x0b, 0xef, 0xea, 0xad, 0x49, 0xf0, 0x47, 0xde, 0x75, 0xf3, 0xac, 0x3a, 0xd6, 0x45, + 0x22, 0x38, 0xc6, 0xc8, 0x05, 0x83, 0x02, 0x03, 0xb7, 0xef, 0x0e, 0x3a, 0x4b, 0xdf, 0xb0, 0xf7, + 0x06, 0xad, 0x2c, 0xf1, 0x73, 0xef, 0xa1, 0x35, 0xd6, 0x2c, 0x07, 0xcd, 0x31, 0xb8, 0xe8, 0x5f, + 0x0e, 0xee, 0x3f, 0xbb, 0x8d, 0x6c, 0x95, 0xa8, 0xa9, 0x12, 0xb5, 0x55, 0xa2, 0x39, 0x70, 0x39, + 0x1b, 0xed, 0x7f, 0xf5, 0x9c, 0xef, 0xbf, 0x7b, 0x83, 0x8c, 0xe3, 0xa6, 0x48, 0xa2, 0x14, 0x04, + 0x69, 0x7b, 0xdb, 0xcb, 0x50, 0xaf, 0xb7, 0x04, 0xeb, 0x9c, 0x69, 0x23, 0xe8, 0xe5, 0x03, 0x93, + 0xf0, 0xca, 0x06, 0xf8, 0x13, 0xef, 0x06, 0xab, 0xd8, 0x86, 0x2a, 0x26, 0xa0, 0xa4, 0xbb, 0x78, + 0xc7, 0x05, 0xc7, 0xe0, 0xd2, 0xb4, 0x7c, 0x84, 0xd5, 0xbb, 0x06, 0x2e, 0x2d, 0x7b, 0xd3, 0x20, + 0x7f, 0xea, 0x3d, 0x16, 0xb4, 0x8a, 0xb7, 0x65, 0x2b, 0x6e, 0x59, 0xad, 0xe3, 0x14, 0x0a, 0x89, + 0x41, 0xc7, 0x5a, 0x82, 0x56, 0x8b, 0xd2, 0x88, 0x0b, 0x56, 0xeb, 0x79, 0x83, 0xfc, 0xe7, 0x5e, + 0xd0, 0x58, 0xa8, 0xa8, 0xd4, 0x34, 0x45, 0x0e, 0x52, 0xc7, 0x9f, 0xf8, 0x0e, 0x99, 0xd2, 0xc1, + 0x3d, 0xa3, 0xdd, 0x08, 0x5a, 0xad, 0xce, 0xf0, 0x6b, 0x4b, 0x5f, 0x74, 0xbe, 0x7e, 0xeb, 0x39, + 0xb3, 0x0f, 0xfb, 0x63, 0xe8, 0x1e, 0x8e, 0xa1, 0xfb, 0xe7, 0x18, 0xba, 0x5f, 0x4e, 0xa1, 0x73, + 0x38, 0x85, 0xce, 0xcf, 0x53, 0xe8, 0x7c, 0x7c, 0x79, 0xf6, 0xf2, 0xed, 0x3e, 0x87, 0xa0, 0xb2, + 0x7f, 0x33, 0x29, 0xa7, 0xa4, 0xba, 0xe3, 0x47, 0x30, 0x5f, 0x25, 0xb9, 0x32, 0x7b, 0x9b, 0xfc, + 0x0d, 0x00, 0x00, 0xff, 0xff, 0x8f, 0x38, 0x73, 0xdc, 0x32, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -144,6 +166,16 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.MaxTransactionsFilters != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.MaxTransactionsFilters)) + i-- + dAtA[i] = 0x28 + } + if m.MaxKvQueryKeysCount != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.MaxKvQueryKeysCount)) + i-- + dAtA[i] = 0x20 + } if m.TxQueryRemovalLimit != 0 { i = encodeVarintParams(dAtA, i, uint64(m.TxQueryRemovalLimit)) i-- @@ -200,6 +232,12 @@ func (m *Params) Size() (n int) { if m.TxQueryRemovalLimit != 0 { n += 1 + sovParams(uint64(m.TxQueryRemovalLimit)) } + if m.MaxKvQueryKeysCount != 0 { + n += 1 + sovParams(uint64(m.MaxKvQueryKeysCount)) + } + if m.MaxTransactionsFilters != 0 { + n += 1 + sovParams(uint64(m.MaxTransactionsFilters)) + } return n } @@ -310,6 +348,44 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxKvQueryKeysCount", wireType) + } + m.MaxKvQueryKeysCount = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxKvQueryKeysCount |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxTransactionsFilters", wireType) + } + m.MaxTransactionsFilters = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxTransactionsFilters |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) diff --git a/x/interchainqueries/types/tx.go b/x/interchainqueries/types/tx.go index 6bce76392..7353125b1 100644 --- a/x/interchainqueries/types/tx.go +++ b/x/interchainqueries/types/tx.go @@ -11,10 +11,6 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -const ( - MaxKVQueryKeysCount = 32 -) - var ( _ sdk.Msg = &MsgSubmitQueryResult{} _ codectypes.UnpackInterfacesMessage = MsgSubmitQueryResult{} @@ -90,7 +86,7 @@ func (msg MsgRegisterInterchainQuery) Type() string { return "register-interchain-query" } -func (msg MsgRegisterInterchainQuery) Validate() error { +func (msg MsgRegisterInterchainQuery) Validate(params Params) error { if msg.UpdatePeriod == 0 { return errors.Wrap(ErrInvalidUpdatePeriod, "update period can not be equal to zero") } @@ -115,13 +111,13 @@ func (msg MsgRegisterInterchainQuery) Validate() error { if len(msg.Keys) == 0 { return errors.Wrap(ErrEmptyKeys, "keys cannot be empty") } - if err := validateKeys(msg.GetKeys()); err != nil { + if err := validateKeys(msg.GetKeys(), params.MaxKvQueryKeysCount); err != nil { return err } } if InterchainQueryType(msg.QueryType).IsTX() { - if err := ValidateTransactionsFilter(msg.TransactionsFilter); err != nil { + if err := ValidateTransactionsFilter(msg.TransactionsFilter, params.MaxTransactionsFilters); err != nil { return errors.Wrap(ErrInvalidTransactionsFilter, err.Error()) } } @@ -144,7 +140,7 @@ func (msg MsgRegisterInterchainQuery) GetSigners() []sdk.AccAddress { var _ sdk.Msg = &MsgUpdateInterchainQueryRequest{} -func (msg MsgUpdateInterchainQueryRequest) Validate() error { +func (msg MsgUpdateInterchainQueryRequest) Validate(params Params) error { if msg.GetQueryId() == 0 { return errors.Wrap(ErrInvalidQueryID, "query_id cannot be empty or equal to 0") } @@ -167,13 +163,13 @@ func (msg MsgUpdateInterchainQueryRequest) Validate() error { } if len(newKeys) != 0 { - if err := validateKeys(newKeys); err != nil { + if err := validateKeys(newKeys, params.MaxKvQueryKeysCount); err != nil { return err } } if newTxFilter != "" { - if err := ValidateTransactionsFilter(newTxFilter); err != nil { + if err := ValidateTransactionsFilter(newTxFilter, params.MaxTransactionsFilters); err != nil { return errors.Wrap(ErrInvalidTransactionsFilter, err.Error()) } } @@ -230,9 +226,9 @@ func (msg *MsgUpdateParams) Validate() error { return nil } -func validateKeys(keys []*KVKey) error { - if uint64(len(keys)) > MaxKVQueryKeysCount { - return errors.Wrapf(ErrTooManyKVQueryKeys, "keys count cannot be more than %d", MaxKVQueryKeysCount) +func validateKeys(keys []*KVKey, maxKVQueryKeysCount uint64) error { + if uint64(len(keys)) > maxKVQueryKeysCount { + return errors.Wrapf(ErrTooManyKVQueryKeys, "keys count cannot be more than %d", maxKVQueryKeysCount) } duplicates := make(map[string]struct{}) diff --git a/x/interchainqueries/types/types.go b/x/interchainqueries/types/types.go index dafa661f3..be94cc357 100644 --- a/x/interchainqueries/types/types.go +++ b/x/interchainqueries/types/types.go @@ -43,9 +43,6 @@ const ( // AttributeValueQueryRemoved represents the value for the 'action' event attribute. AttributeValueQueryRemoved = "query_removed" - - // maxTransactionsFilters defines maximum allowed amount of tx filters in msgRegisterInterchainQuery - maxTransactionsFilters = 32 ) const ( @@ -107,13 +104,13 @@ type TransactionsFilterItem struct { } // ValidateTransactionsFilter checks if the passed string is a valid TransactionsFilter value. -func ValidateTransactionsFilter(s string) error { +func ValidateTransactionsFilter(s string, maxTransactionsFilters uint64) error { const forbiddenCharacters = "\t\n\r\\()\"'=><" filters := TransactionsFilter{} if err := json.Unmarshal([]byte(s), &filters); err != nil { return fmt.Errorf("failed to unmarshal transactions filter: %w", err) } - if len(filters) > maxTransactionsFilters { + if uint64(len(filters)) > maxTransactionsFilters { return fmt.Errorf("too many transactions filters, provided=%d, max=%d", len(filters), maxTransactionsFilters) } diff --git a/x/interchainqueries/types/types_test.go b/x/interchainqueries/types/types_test.go index 202c8c531..f062a310e 100644 --- a/x/interchainqueries/types/types_test.go +++ b/x/interchainqueries/types/types_test.go @@ -10,37 +10,37 @@ import ( func TestTransactionFilterValidation(t *testing.T) { t.Run("Valid", func(t *testing.T) { // several conditions - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"},{"field":"tx.height","op":"Gte","value":100}]`)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"},{"field":"tx.height","op":"Gte","value":100}]`, DefaultMaxTransactionsFilters)) // all supported operations with a whole operand - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Eq","value":1000}]`)) - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gt","value":1000}]`)) - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gte","value":1000}]`)) - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Lt","value":1000}]`)) - assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Lte","value":1000}]`)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Eq","value":1000}]`, DefaultMaxTransactionsFilters)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gt","value":1000}]`, DefaultMaxTransactionsFilters)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gte","value":1000}]`, DefaultMaxTransactionsFilters)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Lt","value":1000}]`, DefaultMaxTransactionsFilters)) + assert.NoError(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Lte","value":1000}]`, DefaultMaxTransactionsFilters)) }) t.Run("Invalid", func(t *testing.T) { // invalid json - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"Eq","value":`), "unexpected end of JSON input") + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"Eq","value":`, DefaultMaxTransactionsFilters), "unexpected end of JSON input") // empty operation - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), "op '' is expected to be one of: eq, gt, gte, lt, lte") + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.recipient","op":"","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), "op '' is expected to be one of: eq, gt, gte, lt, lte") // empty field - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), "field couldn't be empty") + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), "field couldn't be empty") // field with forbidden symbols const specialSymbolsAreNotAllowed = "special symbols \t\n\r\\()\"'=>< are not allowed" - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\t","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\n","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\r","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\\","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.(","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.)","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\"","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.'","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.=","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.>","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.<","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\t","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\n","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\r","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\\","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.(","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.)","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.\"","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.'","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.=","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.>","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"transfer.<","op":"Eq","value":"neutron1mjk79fjjgpplak5wq838w0yd982gzkyf8fxu8u"}]`, DefaultMaxTransactionsFilters), specialSymbolsAreNotAllowed) // decimal number - assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gte","value":15.5}]`), "can't be a decimal number") - assert.ErrorContains(t, ValidateTransactionsFilter(lotsOfTxFilters(t, 40)), "too many transactions filters") + assert.ErrorContains(t, ValidateTransactionsFilter(`[{"field":"tx.height","op":"Gte","value":15.5}]`, DefaultMaxTransactionsFilters), "can't be a decimal number") + assert.ErrorContains(t, ValidateTransactionsFilter(lotsOfTxFilters(t, 40), DefaultMaxTransactionsFilters), "too many transactions filters") }) } From ba1b1d6dc91370d81e7125962e02aee01274eac9 Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 7 Aug 2024 13:44:08 +0400 Subject: [PATCH 02/60] feat: add possibility for unordered ica channels --- proto/neutron/interchaintxs/v1/tx.proto | 2 + x/dex/types/limit_order_tranche_user.pb.go | 5 +- x/interchaintxs/keeper/msg_server.go | 3 +- x/interchaintxs/types/tx.pb.go | 150 +++++++++++++-------- 4 files changed, 98 insertions(+), 62 deletions(-) diff --git a/proto/neutron/interchaintxs/v1/tx.proto b/proto/neutron/interchaintxs/v1/tx.proto index ef59d3075..32148ce7b 100644 --- a/proto/neutron/interchaintxs/v1/tx.proto +++ b/proto/neutron/interchaintxs/v1/tx.proto @@ -11,6 +11,7 @@ import "google/api/http.proto"; import "google/protobuf/any.proto"; import "neutron/feerefunder/fee.proto"; import "neutron/interchaintxs/v1/params.proto"; +import "ibc/core/channel/v1/channel.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/interchaintxs/types"; @@ -36,6 +37,7 @@ message MsgRegisterInterchainAccount { (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; + ibc.core.channel.v1.Order ordering = 5; } // MsgRegisterInterchainAccountResponse is the response type for diff --git a/x/dex/types/limit_order_tranche_user.pb.go b/x/dex/types/limit_order_tranche_user.pb.go index b0e65087b..6e52c57d5 100644 --- a/x/dex/types/limit_order_tranche_user.pb.go +++ b/x/dex/types/limit_order_tranche_user.pb.go @@ -31,8 +31,9 @@ type LimitOrderTrancheUser struct { Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` SharesOwned cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=shares_owned,json=sharesOwned,proto3,customtype=cosmossdk.io/math.Int" json:"shares_owned" yaml:"shares_owned"` SharesWithdrawn cosmossdk_io_math.Int `protobuf:"bytes,6,opt,name=shares_withdrawn,json=sharesWithdrawn,proto3,customtype=cosmossdk.io/math.Int" json:"shares_withdrawn" yaml:"shares_withdrawn"` - SharesCancelled cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=shares_cancelled,json=sharesCancelled,proto3,customtype=cosmossdk.io/math.Int" json:"shares_cancelled" yaml:"shares_cancelled"` - OrderType LimitOrderType `protobuf:"varint,8,opt,name=order_type,json=orderType,proto3,enum=neutron.dex.LimitOrderType" json:"order_type,omitempty"` + // TODO: remove this in next release. It is no longer used + SharesCancelled cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=shares_cancelled,json=sharesCancelled,proto3,customtype=cosmossdk.io/math.Int" json:"shares_cancelled" yaml:"shares_cancelled"` + OrderType LimitOrderType `protobuf:"varint,8,opt,name=order_type,json=orderType,proto3,enum=neutron.dex.LimitOrderType" json:"order_type,omitempty"` } func (m *LimitOrderTrancheUser) Reset() { *m = LimitOrderTrancheUser{} } diff --git a/x/interchaintxs/keeper/msg_server.go b/x/interchaintxs/keeper/msg_server.go index ed1dcc9ed..54c64e9e8 100644 --- a/x/interchaintxs/keeper/msg_server.go +++ b/x/interchaintxs/keeper/msg_server.go @@ -66,7 +66,8 @@ func (k Keeper) RegisterInterchainAccount(goCtx context.Context, msg *ictxtypes. Owner: icaOwner, ConnectionId: msg.ConnectionId, Version: "", // FIXME: empty version string doesn't look good - Ordering: channeltypes.ORDERED, + // underlying controller uses ORDER_ORDERED as default in case msg's ordering is NONE + Ordering: msg.Ordering, }) if err != nil { k.Logger(ctx).Debug("RegisterInterchainAccount: failed to RegisterInterchainAccount:", "error", err, "owner", icaOwner, "msg", &msg) diff --git a/x/interchaintxs/types/tx.pb.go b/x/interchaintxs/types/tx.pb.go index 8b7fb7755..4b18fd1a1 100644 --- a/x/interchaintxs/types/tx.pb.go +++ b/x/interchaintxs/types/tx.pb.go @@ -7,7 +7,7 @@ import ( context "context" fmt "fmt" _ "github.com/cosmos/cosmos-proto" - types1 "github.com/cosmos/cosmos-sdk/codec/types" + types2 "github.com/cosmos/cosmos-sdk/codec/types" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" _ "github.com/cosmos/cosmos-sdk/types/msgservice" @@ -15,7 +15,8 @@ import ( _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" - types2 "github.com/neutron-org/neutron/v4/x/feerefunder/types" + types1 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + types3 "github.com/neutron-org/neutron/v4/x/feerefunder/types" _ "google.golang.org/genproto/googleapis/api/annotations" grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" @@ -42,6 +43,7 @@ type MsgRegisterInterchainAccount struct { ConnectionId string `protobuf:"bytes,2,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty" yaml:"connection_id"` InterchainAccountId string `protobuf:"bytes,3,opt,name=interchain_account_id,json=interchainAccountId,proto3" json:"interchain_account_id,omitempty" yaml:"interchain_account_id"` RegisterFee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=register_fee,json=registerFee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"register_fee"` + Ordering types1.Order `protobuf:"varint,5,opt,name=ordering,proto3,enum=ibc.core.channel.v1.Order" json:"ordering,omitempty"` } func (m *MsgRegisterInterchainAccount) Reset() { *m = MsgRegisterInterchainAccount{} } @@ -126,11 +128,11 @@ type MsgSubmitTx struct { // claim our capability for. InterchainAccountId string `protobuf:"bytes,2,opt,name=interchain_account_id,json=interchainAccountId,proto3" json:"interchain_account_id,omitempty"` ConnectionId string `protobuf:"bytes,3,opt,name=connection_id,json=connectionId,proto3" json:"connection_id,omitempty"` - Msgs []*types1.Any `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs,omitempty"` + Msgs []*types2.Any `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs,omitempty"` Memo string `protobuf:"bytes,5,opt,name=memo,proto3" json:"memo,omitempty"` // timeout in seconds after which the packet times out Timeout uint64 `protobuf:"varint,6,opt,name=timeout,proto3" json:"timeout,omitempty"` - Fee types2.Fee `protobuf:"bytes,7,opt,name=fee,proto3" json:"fee"` + Fee types3.Fee `protobuf:"bytes,7,opt,name=fee,proto3" json:"fee"` } func (m *MsgSubmitTx) Reset() { *m = MsgSubmitTx{} } @@ -332,60 +334,63 @@ func init() { func init() { proto.RegisterFile("neutron/interchaintxs/v1/tx.proto", fileDescriptor_50f087790e59c806) } var fileDescriptor_50f087790e59c806 = []byte{ - // 839 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xbf, 0x6f, 0xfb, 0x44, - 0x14, 0x8f, 0x93, 0x7c, 0x53, 0x72, 0x09, 0x42, 0xb8, 0xa9, 0xea, 0x44, 0x6d, 0x92, 0x1a, 0x2a, - 0x85, 0x4a, 0xb1, 0x9b, 0x80, 0x8a, 0x14, 0x09, 0xa4, 0xa6, 0x52, 0xa5, 0x0c, 0x91, 0x8a, 0x5b, - 0x16, 0x96, 0xe8, 0x62, 0x5f, 0x1c, 0x8b, 0xf8, 0xce, 0xf8, 0xce, 0x51, 0xb2, 0x21, 0x26, 0xc4, - 0xc4, 0xc2, 0xde, 0x11, 0x31, 0xa0, 0x0e, 0xfc, 0x01, 0x8c, 0x1d, 0x2b, 0x26, 0xa6, 0x02, 0xed, - 0x50, 0xe6, 0x0e, 0xcc, 0xe8, 0xec, 0x73, 0x7e, 0xa9, 0x89, 0xaa, 0xef, 0x92, 0xdc, 0x7b, 0xef, - 0x73, 0xef, 0xbd, 0xfb, 0x7c, 0xee, 0x9d, 0xc1, 0x01, 0x46, 0x01, 0xf3, 0x09, 0xd6, 0x1d, 0xcc, - 0x90, 0x6f, 0x0e, 0xa1, 0x83, 0xd9, 0x84, 0xea, 0xe3, 0x86, 0xce, 0x26, 0x9a, 0xe7, 0x13, 0x46, - 0x64, 0x45, 0x40, 0xb4, 0x25, 0x88, 0x36, 0x6e, 0x94, 0xde, 0x87, 0xae, 0x83, 0x89, 0x1e, 0xfe, - 0x46, 0xe0, 0x52, 0xd9, 0x24, 0xd4, 0x25, 0x54, 0xef, 0x43, 0x8a, 0xf4, 0x71, 0xa3, 0x8f, 0x18, - 0x6c, 0xe8, 0x26, 0x71, 0xb0, 0x88, 0xef, 0x8a, 0xb8, 0x4b, 0x6d, 0x5e, 0xc4, 0xa5, 0xb6, 0x08, - 0x14, 0xa3, 0x40, 0x2f, 0xb4, 0xf4, 0xc8, 0x10, 0xa1, 0x82, 0x4d, 0x6c, 0x12, 0xf9, 0xf9, 0x4a, - 0x78, 0xf7, 0x6c, 0x42, 0xec, 0x11, 0xd2, 0xa1, 0xe7, 0xe8, 0x10, 0x63, 0xc2, 0x20, 0x73, 0x08, - 0x8e, 0xf7, 0xec, 0x2c, 0x44, 0x87, 0x8c, 0x79, 0x71, 0x15, 0xe1, 0x0e, 0xad, 0x7e, 0x30, 0xd0, - 0x21, 0x9e, 0x8a, 0xd0, 0x7e, 0xcc, 0xc4, 0x00, 0x21, 0x1f, 0x0d, 0x02, 0x6c, 0x21, 0x9f, 0xaf, - 0x45, 0xf8, 0x70, 0x2d, 0x51, 0x1e, 0xf4, 0xa1, 0x2b, 0xea, 0xaa, 0xff, 0x24, 0xc1, 0x5e, 0x97, - 0xda, 0x06, 0xb2, 0x1d, 0xca, 0x90, 0xdf, 0x99, 0x81, 0x4f, 0x4d, 0x93, 0x04, 0x98, 0xc9, 0x07, - 0x20, 0x3f, 0xf0, 0x89, 0xdb, 0x83, 0x96, 0xe5, 0x23, 0x4a, 0x15, 0xa9, 0x2a, 0xd5, 0xb2, 0x46, - 0x8e, 0xfb, 0x4e, 0x23, 0x97, 0xfc, 0x19, 0x78, 0xd7, 0x24, 0x18, 0x23, 0x93, 0x1f, 0xa8, 0xe7, - 0x58, 0x4a, 0x92, 0x63, 0xda, 0xca, 0xf3, 0x7d, 0xa5, 0x30, 0x85, 0xee, 0xa8, 0xa5, 0x2e, 0x85, - 0x55, 0x23, 0x3f, 0xb7, 0x3b, 0x96, 0x7c, 0x05, 0x76, 0xe6, 0x3d, 0xf6, 0x60, 0x54, 0x97, 0xa7, - 0x49, 0x85, 0x69, 0xaa, 0xcf, 0xf7, 0x95, 0xbd, 0x28, 0xcd, 0x8b, 0x30, 0xd5, 0xd8, 0x76, 0x56, - 0xbb, 0xee, 0x58, 0x32, 0x06, 0x79, 0x5f, 0x1c, 0xaa, 0x37, 0x40, 0x48, 0x49, 0x57, 0x53, 0xb5, - 0x5c, 0xb3, 0xa8, 0x09, 0xa5, 0xb8, 0xde, 0x9a, 0xd0, 0x5b, 0x3b, 0x23, 0x0e, 0x6e, 0x1f, 0xdf, - 0xde, 0x57, 0x12, 0xbf, 0xfc, 0x55, 0xa9, 0xd9, 0x0e, 0x1b, 0x06, 0x7d, 0xcd, 0x24, 0xae, 0x90, - 0x55, 0xfc, 0xd5, 0xa9, 0xf5, 0xb5, 0xce, 0xa6, 0x1e, 0xa2, 0xe1, 0x06, 0x6a, 0xe4, 0xe2, 0x02, - 0xe7, 0x08, 0xb5, 0x8a, 0xdf, 0x5f, 0x57, 0x12, 0xff, 0x5e, 0x57, 0x12, 0xdf, 0x3d, 0xdd, 0x1c, - 0x2d, 0x51, 0xa6, 0x5a, 0xe0, 0xc3, 0x4d, 0x14, 0x1b, 0x88, 0x7a, 0x04, 0x53, 0x24, 0xef, 0x03, - 0x60, 0x0e, 0x21, 0xc6, 0x68, 0xc4, 0x4f, 0x1f, 0x11, 0x9d, 0x15, 0x9e, 0x8e, 0x25, 0xef, 0x82, - 0x2d, 0x8f, 0xf8, 0x6c, 0x46, 0xb0, 0x91, 0xe1, 0x66, 0xc7, 0x6a, 0xa5, 0x79, 0x69, 0xf5, 0xd7, - 0x24, 0xc8, 0x75, 0xa9, 0x7d, 0x19, 0xf4, 0x5d, 0x87, 0x5d, 0x4d, 0x5e, 0x23, 0x5c, 0x73, 0x1d, - 0xf3, 0x51, 0xfe, 0x17, 0x79, 0xfd, 0x60, 0x55, 0xec, 0x50, 0xa5, 0x15, 0x49, 0x6b, 0x20, 0xed, - 0x52, 0x9b, 0x0a, 0xd2, 0x0b, 0x5a, 0x74, 0x8b, 0xb5, 0xf8, 0x16, 0x6b, 0xa7, 0x78, 0x6a, 0x84, - 0x08, 0x59, 0x06, 0x69, 0x17, 0xb9, 0x44, 0x79, 0x13, 0x66, 0x09, 0xd7, 0xb2, 0x02, 0xb6, 0x98, - 0xe3, 0x22, 0x12, 0x30, 0x25, 0x53, 0x95, 0x6a, 0x69, 0x23, 0x36, 0xe5, 0x63, 0x90, 0xe2, 0x5a, - 0x6e, 0x55, 0xa5, 0x5a, 0xae, 0xa9, 0x68, 0xf1, 0xa0, 0x2f, 0x4c, 0x80, 0x76, 0x8e, 0x50, 0x3b, - 0xcd, 0xa5, 0x34, 0x38, 0x74, 0x93, 0x2c, 0x17, 0x60, 0x7b, 0x81, 0xaf, 0x99, 0x0a, 0x15, 0x90, - 0xa3, 0xe8, 0x9b, 0x00, 0x61, 0x13, 0xc5, 0x32, 0xa4, 0x0d, 0x10, 0xbb, 0x3a, 0x16, 0x6f, 0x4f, - 0x88, 0x22, 0x78, 0x8a, 0x4d, 0xf5, 0x77, 0x09, 0xbc, 0xd7, 0xa5, 0xf6, 0x97, 0x9e, 0x05, 0x19, - 0xba, 0x08, 0xc7, 0x4c, 0x3e, 0x01, 0x59, 0x18, 0xb0, 0x21, 0xf1, 0x1d, 0x36, 0x8d, 0x34, 0x68, - 0x2b, 0x7f, 0xfc, 0x56, 0x2f, 0x88, 0x7b, 0x28, 0xa4, 0xb8, 0x64, 0xbe, 0x83, 0x6d, 0x63, 0x0e, - 0x95, 0xcf, 0x40, 0x26, 0x1a, 0xd4, 0xb0, 0x48, 0xae, 0x59, 0xd5, 0xd6, 0x3d, 0x6b, 0x5a, 0x54, - 0xa9, 0x9d, 0xe5, 0xa7, 0xfe, 0xf9, 0xe9, 0xe6, 0x48, 0x32, 0xc4, 0xd6, 0xd6, 0x31, 0x3f, 0xf5, - 0x3c, 0xe9, 0x0f, 0x4f, 0x37, 0x47, 0xfb, 0xcb, 0xef, 0xc1, 0x4a, 0xbb, 0x6a, 0x11, 0xec, 0xae, - 0xb8, 0x62, 0x62, 0x9a, 0xff, 0x25, 0x41, 0xaa, 0x4b, 0x6d, 0xf9, 0x27, 0x09, 0x14, 0xd7, 0xbf, - 0x17, 0x27, 0xeb, 0xfb, 0xdc, 0x34, 0x04, 0xa5, 0xcf, 0xdf, 0x6e, 0x5f, 0xdc, 0x9d, 0x9a, 0x90, - 0xfb, 0xe0, 0x9d, 0xd9, 0xe5, 0x3f, 0xdc, 0x98, 0x2d, 0x86, 0x95, 0xea, 0xaf, 0x82, 0x2d, 0xd4, - 0x18, 0x81, 0xfc, 0x92, 0xba, 0x1f, 0x6d, 0x4c, 0xb0, 0x08, 0x2d, 0x35, 0x5e, 0x0d, 0x8d, 0xeb, - 0x95, 0xde, 0x7c, 0xcb, 0xd5, 0x6c, 0x7f, 0x71, 0xfb, 0x50, 0x96, 0xee, 0x1e, 0xca, 0xd2, 0xdf, - 0x0f, 0x65, 0xe9, 0xc7, 0xc7, 0x72, 0xe2, 0xee, 0xb1, 0x9c, 0xf8, 0xf3, 0xb1, 0x9c, 0xf8, 0xea, - 0xd3, 0x85, 0xb7, 0x4a, 0x64, 0xaf, 0x13, 0xdf, 0x8e, 0xd7, 0xfa, 0xf8, 0x13, 0x7d, 0xb2, 0xf2, - 0x01, 0x08, 0x1f, 0xb0, 0x7e, 0x26, 0x1c, 0xc5, 0x8f, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0xd9, - 0x95, 0xf0, 0x9e, 0x4f, 0x07, 0x00, 0x00, + // 891 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x31, 0x6f, 0x23, 0x45, + 0x14, 0xf6, 0xc6, 0xbe, 0xe4, 0x3c, 0x0e, 0x20, 0xf6, 0x72, 0xca, 0xda, 0x4a, 0x6c, 0x67, 0xe1, + 0x24, 0x13, 0x29, 0xb3, 0xb1, 0x41, 0x41, 0x8a, 0x04, 0x52, 0x7c, 0xd2, 0x49, 0x2e, 0x22, 0x8e, + 0xbd, 0xa3, 0xa1, 0xb1, 0x66, 0x77, 0xc7, 0xeb, 0x11, 0xd9, 0x19, 0x33, 0x33, 0x6b, 0xc5, 0x1d, + 0xa2, 0x42, 0x54, 0x34, 0x14, 0x74, 0x57, 0x22, 0x0a, 0x94, 0x82, 0x1f, 0x40, 0x79, 0xe5, 0x89, + 0x8a, 0x2a, 0xa0, 0xa4, 0x08, 0xf5, 0x15, 0xd4, 0x68, 0x76, 0x67, 0x1c, 0xdb, 0x3a, 0x5b, 0x11, + 0x8d, 0x3d, 0xef, 0xbd, 0x6f, 0xde, 0x37, 0xf3, 0xbe, 0x37, 0x6f, 0xc1, 0x1e, 0xc5, 0xa9, 0xe4, + 0x8c, 0x7a, 0x84, 0x4a, 0xcc, 0xc3, 0x21, 0x22, 0x54, 0x9e, 0x0b, 0x6f, 0xdc, 0xf6, 0xe4, 0x39, + 0x1c, 0x71, 0x26, 0x99, 0xed, 0x68, 0x08, 0x9c, 0x83, 0xc0, 0x71, 0xbb, 0xf6, 0x2e, 0x4a, 0x08, + 0x65, 0x5e, 0xf6, 0x9b, 0x83, 0x6b, 0xf5, 0x90, 0x89, 0x84, 0x09, 0x2f, 0x40, 0x02, 0x7b, 0xe3, + 0x76, 0x80, 0x25, 0x6a, 0x7b, 0x21, 0x23, 0x54, 0xc7, 0xb7, 0x75, 0x3c, 0x11, 0xb1, 0x22, 0x49, + 0x44, 0xac, 0x03, 0xd5, 0x3c, 0xd0, 0xcf, 0x2c, 0x2f, 0x37, 0x74, 0x68, 0x2b, 0x66, 0x31, 0xcb, + 0xfd, 0x6a, 0xa5, 0xbd, 0x3b, 0x31, 0x63, 0xf1, 0x19, 0xf6, 0xd0, 0x88, 0x78, 0x88, 0x52, 0x26, + 0x91, 0x24, 0x8c, 0x9a, 0x3d, 0x0f, 0x67, 0xa2, 0x43, 0x29, 0x47, 0x86, 0x45, 0xbb, 0x33, 0x2b, + 0x48, 0x07, 0x1e, 0xa2, 0x13, 0x1d, 0xda, 0x35, 0x95, 0x18, 0x60, 0xcc, 0xf1, 0x20, 0xa5, 0x11, + 0xe6, 0x6a, 0xad, 0xc3, 0x8f, 0x96, 0x16, 0x6a, 0x84, 0x38, 0x4a, 0x0c, 0xef, 0x1e, 0x09, 0x42, + 0x2f, 0x64, 0x1c, 0x7b, 0xe1, 0x10, 0x51, 0x8a, 0xcf, 0x14, 0x42, 0x2f, 0x73, 0x88, 0xfb, 0x53, + 0x11, 0xec, 0x9c, 0x8a, 0xd8, 0xc7, 0x31, 0x11, 0x12, 0xf3, 0xde, 0x34, 0xdf, 0x49, 0x18, 0xb2, + 0x94, 0x4a, 0x7b, 0x0f, 0x6c, 0x0e, 0x38, 0x4b, 0xfa, 0x28, 0x8a, 0x38, 0x16, 0xc2, 0xb1, 0x9a, + 0x56, 0xab, 0xec, 0x57, 0x94, 0xef, 0x24, 0x77, 0xd9, 0x9f, 0x80, 0xb7, 0x42, 0x46, 0x29, 0x0e, + 0xd5, 0x9d, 0xfb, 0x24, 0x72, 0xd6, 0x14, 0xa6, 0xeb, 0xbc, 0xbe, 0x6c, 0x6c, 0x4d, 0x50, 0x72, + 0x76, 0xec, 0xce, 0x85, 0x5d, 0x7f, 0xf3, 0xd6, 0xee, 0x45, 0xf6, 0x73, 0xf0, 0xf0, 0xf6, 0x1a, + 0x7d, 0x94, 0xf3, 0xaa, 0x34, 0xc5, 0x2c, 0x4d, 0xf3, 0xf5, 0x65, 0x63, 0x27, 0x4f, 0xf3, 0x46, + 0x98, 0xeb, 0x3f, 0x20, 0x8b, 0xa7, 0xee, 0x45, 0x36, 0x05, 0x9b, 0x5c, 0x5f, 0xaa, 0x3f, 0xc0, + 0xd8, 0x29, 0x35, 0x8b, 0xad, 0x4a, 0xa7, 0x0a, 0xb5, 0x98, 0xaa, 0x25, 0xa0, 0x6e, 0x09, 0xf8, + 0x98, 0x11, 0xda, 0x3d, 0x7c, 0x79, 0xd9, 0x28, 0xfc, 0xf2, 0x57, 0xa3, 0x15, 0x13, 0x39, 0x4c, + 0x03, 0x18, 0xb2, 0x44, 0x2b, 0xaf, 0xff, 0x0e, 0x44, 0xf4, 0x95, 0x27, 0x27, 0x23, 0x2c, 0xb2, + 0x0d, 0xc2, 0xaf, 0x18, 0x82, 0x27, 0x18, 0xdb, 0x47, 0xe0, 0x3e, 0xe3, 0x11, 0xe6, 0x84, 0xc6, + 0xce, 0xbd, 0xa6, 0xd5, 0x7a, 0xbb, 0x53, 0x83, 0x24, 0x08, 0xa1, 0x2a, 0x3f, 0x34, 0x35, 0x1f, + 0xb7, 0xe1, 0x67, 0x0a, 0xe4, 0x4f, 0xb1, 0xc7, 0xd5, 0xef, 0x5e, 0x34, 0x0a, 0xff, 0xbc, 0x68, + 0x14, 0xbe, 0xbd, 0xb9, 0xd8, 0x9f, 0x2b, 0xb5, 0x1b, 0x81, 0xf7, 0x57, 0x49, 0xe3, 0x63, 0x31, + 0x62, 0x54, 0x60, 0x7b, 0x17, 0x00, 0x4d, 0xa0, 0xaa, 0x96, 0x0b, 0x54, 0xd6, 0x9e, 0x5e, 0x64, + 0x6f, 0x83, 0x8d, 0x11, 0xe3, 0x72, 0x2a, 0x8c, 0xbf, 0xae, 0xcc, 0x5e, 0x74, 0x5c, 0x52, 0xd4, + 0xee, 0xaf, 0x6b, 0xa0, 0x72, 0x2a, 0xe2, 0x67, 0x69, 0x90, 0x10, 0xf9, 0xfc, 0xfc, 0x2e, 0x82, + 0x77, 0x96, 0x29, 0x96, 0xe7, 0x7f, 0xa3, 0x1e, 0xef, 0x2d, 0x36, 0x49, 0xa6, 0xee, 0x42, 0x2b, + 0xb4, 0x40, 0x29, 0x11, 0xb1, 0xd0, 0x62, 0x6d, 0xc1, 0xfc, 0x81, 0x40, 0xf3, 0x40, 0xe0, 0x09, + 0x9d, 0xf8, 0x19, 0xc2, 0xb6, 0x41, 0x29, 0xc1, 0x09, 0xcb, 0x4a, 0x5d, 0xf6, 0xb3, 0xb5, 0xed, + 0x80, 0x0d, 0x49, 0x12, 0xcc, 0x52, 0xe9, 0xac, 0x37, 0xad, 0x56, 0xc9, 0x37, 0xa6, 0x7d, 0x08, + 0x8a, 0xaa, 0x07, 0x36, 0x9a, 0x56, 0xab, 0xd2, 0x71, 0xa0, 0x99, 0x21, 0x33, 0x8f, 0x0b, 0x3e, + 0xc1, 0xb8, 0x5b, 0x52, 0x2d, 0xe0, 0x2b, 0xe8, 0x2a, 0x59, 0x9e, 0x82, 0x07, 0x33, 0xf5, 0x9a, + 0xaa, 0xd0, 0x00, 0x15, 0x81, 0xbf, 0x4e, 0x31, 0x0d, 0xb1, 0x91, 0xa1, 0xe4, 0x03, 0xe3, 0xea, + 0x45, 0xea, 0x78, 0x5a, 0x14, 0x5d, 0x27, 0x63, 0xba, 0xbf, 0x5b, 0xe0, 0x9d, 0x53, 0x11, 0x7f, + 0x31, 0x8a, 0x90, 0xc4, 0x4f, 0xb3, 0x17, 0x6c, 0x1f, 0x81, 0x32, 0x4a, 0xe5, 0x90, 0x71, 0x22, + 0x27, 0xb9, 0x06, 0x5d, 0xe7, 0x8f, 0xdf, 0x0e, 0xb6, 0x74, 0xff, 0x6a, 0x29, 0x9e, 0x49, 0xd5, + 0x44, 0xfe, 0x2d, 0xd4, 0x7e, 0x0c, 0xd6, 0xf3, 0x19, 0x90, 0x91, 0x54, 0x3a, 0x4d, 0xb8, 0x6c, + 0x62, 0xc2, 0x9c, 0xa9, 0x5b, 0x56, 0xb7, 0xfe, 0xf9, 0xe6, 0x62, 0xdf, 0xf2, 0xf5, 0xd6, 0xe3, + 0x43, 0x75, 0xeb, 0xdb, 0xa4, 0xdf, 0xdf, 0x5c, 0xec, 0xef, 0xce, 0x8f, 0x9a, 0x85, 0xe3, 0xba, + 0x55, 0xb0, 0xbd, 0xe0, 0x32, 0x85, 0xe9, 0xfc, 0xbb, 0x06, 0x8a, 0xa7, 0x22, 0xb6, 0x7f, 0xb4, + 0x40, 0x75, 0xf9, 0x9c, 0x39, 0x5a, 0x7e, 0xce, 0x55, 0x8f, 0xa0, 0xf6, 0xe9, 0xff, 0xdb, 0x67, + 0x4e, 0xe7, 0x16, 0xec, 0x00, 0xdc, 0x9f, 0x36, 0xff, 0xa3, 0x95, 0xd9, 0x0c, 0xac, 0x76, 0x70, + 0x27, 0xd8, 0x0c, 0xc7, 0x19, 0xd8, 0x9c, 0x53, 0xf7, 0x83, 0x95, 0x09, 0x66, 0xa1, 0xb5, 0xf6, + 0x9d, 0xa1, 0x86, 0xaf, 0x76, 0xef, 0x1b, 0xa5, 0x66, 0xf7, 0xf3, 0x97, 0x57, 0x75, 0xeb, 0xd5, + 0x55, 0xdd, 0xfa, 0xfb, 0xaa, 0x6e, 0xfd, 0x70, 0x5d, 0x2f, 0xbc, 0xba, 0xae, 0x17, 0xfe, 0xbc, + 0xae, 0x17, 0xbe, 0xfc, 0x78, 0x66, 0xc6, 0xe9, 0xec, 0x07, 0x8c, 0xc7, 0x66, 0xed, 0x8d, 0x3f, + 0xf2, 0xce, 0x17, 0xbe, 0x2d, 0xd9, 0xe0, 0x0b, 0xd6, 0xb3, 0xa7, 0xf8, 0xe1, 0x7f, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x03, 0x83, 0x36, 0x64, 0xaa, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -560,6 +565,11 @@ func (m *MsgRegisterInterchainAccount) MarshalToSizedBuffer(dAtA []byte) (int, e _ = i var l int _ = l + if m.Ordering != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Ordering)) + i-- + dAtA[i] = 0x28 + } if len(m.RegisterFee) > 0 { for iNdEx := len(m.RegisterFee) - 1; iNdEx >= 0; iNdEx-- { { @@ -848,6 +858,9 @@ func (m *MsgRegisterInterchainAccount) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } + if m.Ordering != 0 { + n += 1 + sovTx(uint64(m.Ordering)) + } return n } @@ -1109,6 +1122,25 @@ func (m *MsgRegisterInterchainAccount) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ordering", wireType) + } + m.Ordering = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Ordering |= types1.Order(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -1398,7 +1430,7 @@ func (m *MsgSubmitTx) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Msgs = append(m.Msgs, &types1.Any{}) + m.Msgs = append(m.Msgs, &types2.Any{}) if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } From 53590d875852bef9a44c5affab1ef3e8a4907da8 Mon Sep 17 00:00:00 2001 From: nhpd Date: Wed, 7 Aug 2024 18:55:05 +0400 Subject: [PATCH 03/60] feat: add bindings for ordering in ica channels --- wasmbinding/bindings/msg.go | 1 + wasmbinding/message_plugin.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 03fc3640b..dad007622 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -81,6 +81,7 @@ type RegisterInterchainAccount struct { ConnectionId string `json:"connection_id"` InterchainAccountId string `json:"interchain_account_id"` RegisterFee sdk.Coins `json:"register_fee,omitempty"` + Ordering string `json:"ordering"` } // RegisterInterchainAccountResponse holds response for RegisterInterchainAccount. diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index a22c5e78d..37086aee2 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + types1 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "strings" "time" @@ -865,11 +866,24 @@ func (m *CustomMessenger) registerInterchainAccount(ctx sdk.Context, contractAdd } func (m *CustomMessenger) performRegisterInterchainAccount(ctx sdk.Context, contractAddr sdk.AccAddress, reg *bindings.RegisterInterchainAccount) (*ictxtypes.MsgRegisterInterchainAccountResponse, error) { + // parse incoming ordering. If nothing passed, use ORDERED by default + var orderValue types1.Order + if reg.Ordering == "" { + orderValueInt, ok := types1.Order_value[reg.Ordering] + if !ok { + return nil, fmt.Errorf("failed to register interchain account: incorrect order value passed: %s", reg.Ordering) + } + orderValue = types1.Order(orderValueInt) + } else { + orderValue = types1.ORDERED + } + msg := ictxtypes.MsgRegisterInterchainAccount{ FromAddress: contractAddr.String(), ConnectionId: reg.ConnectionId, InterchainAccountId: reg.InterchainAccountId, RegisterFee: getRegisterFee(reg.RegisterFee), + Ordering: orderValue, } response, err := m.Ictxmsgserver.RegisterInterchainAccount(ctx, &msg) From b7016c130d97d7675d85309ccff2e9b371a7f859 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 8 Aug 2024 06:58:52 -0300 Subject: [PATCH 04/60] intro new request & modify old one --- proto/neutron/contractmanager/query.proto | 9 +- .../keeper/grpc_query_failure.go | 2 +- x/contractmanager/types/query.pb.go | 320 +++++++++++++++--- x/contractmanager/types/query.pb.gw.go | 4 +- 4 files changed, 287 insertions(+), 48 deletions(-) diff --git a/proto/neutron/contractmanager/query.proto b/proto/neutron/contractmanager/query.proto index ca7f08d24..f0e597fa1 100644 --- a/proto/neutron/contractmanager/query.proto +++ b/proto/neutron/contractmanager/query.proto @@ -18,7 +18,7 @@ service Query { } // Queries a Failure by contract address and failure ID. - rpc AddressFailure(QueryFailuresRequest) returns (QueryFailuresResponse) { + rpc AddressFailure(QueryFailureRequest) returns (QueryFailuresResponse) { option (google.api.http).get = "/neutron/contractmanager/failures/{address}/{failure_id}"; } @@ -46,6 +46,13 @@ message QueryParamsResponse { // QueryFailuresRequest is request type for the Query/Failures RPC method. message QueryFailuresRequest { + // address of the contract which Sudo call failed. + string address = 1; + cosmos.base.query.v1beta1.PageRequest pagination = 3; +} + +// QueryFailureRequest is request type for the Query/Failures RPC method. +message QueryFailureRequest { // address of the contract which Sudo call failed. string address = 1; // ID of the failure for the given contract. diff --git a/x/contractmanager/keeper/grpc_query_failure.go b/x/contractmanager/keeper/grpc_query_failure.go index 70f92bf5a..d4c6cb99b 100644 --- a/x/contractmanager/keeper/grpc_query_failure.go +++ b/x/contractmanager/keeper/grpc_query_failure.go @@ -59,7 +59,7 @@ func (k Keeper) AddressFailures(c context.Context, req *types.QueryFailuresReque return &types.QueryFailuresResponse{Failures: failures, Pagination: pageRes}, nil } -func (k Keeper) AddressFailure(c context.Context, req *types.QueryFailuresRequest) (*types.QueryFailuresResponse, error) { +func (k Keeper) AddressFailure(c context.Context, req *types.QueryFailureRequest) (*types.QueryFailuresResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "request field must not be empty") } diff --git a/x/contractmanager/types/query.pb.go b/x/contractmanager/types/query.pb.go index b5b0f5543..3ea9720d0 100644 --- a/x/contractmanager/types/query.pb.go +++ b/x/contractmanager/types/query.pb.go @@ -116,9 +116,7 @@ func (m *QueryParamsResponse) GetParams() Params { // QueryFailuresRequest is request type for the Query/Failures RPC method. type QueryFailuresRequest struct { // address of the contract which Sudo call failed. - Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // ID of the failure for the given contract. - FailureId uint64 `protobuf:"varint,2,opt,name=failure_id,json=failureId,proto3" json:"failure_id,omitempty"` + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -162,14 +160,70 @@ func (m *QueryFailuresRequest) GetAddress() string { return "" } -func (m *QueryFailuresRequest) GetFailureId() uint64 { +func (m *QueryFailuresRequest) GetPagination() *query.PageRequest { + if m != nil { + return m.Pagination + } + return nil +} + +// QueryFailureRequest is request type for the Query/Failures RPC method. +type QueryFailureRequest struct { + // address of the contract which Sudo call failed. + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // ID of the failure for the given contract. + FailureId uint64 `protobuf:"varint,2,opt,name=failure_id,json=failureId,proto3" json:"failure_id,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` +} + +func (m *QueryFailureRequest) Reset() { *m = QueryFailureRequest{} } +func (m *QueryFailureRequest) String() string { return proto.CompactTextString(m) } +func (*QueryFailureRequest) ProtoMessage() {} +func (*QueryFailureRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f9524a427f219917, []int{3} +} +func (m *QueryFailureRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFailureRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFailureRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFailureRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFailureRequest.Merge(m, src) +} +func (m *QueryFailureRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryFailureRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFailureRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFailureRequest proto.InternalMessageInfo + +func (m *QueryFailureRequest) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *QueryFailureRequest) GetFailureId() uint64 { if m != nil { return m.FailureId } return 0 } -func (m *QueryFailuresRequest) GetPagination() *query.PageRequest { +func (m *QueryFailureRequest) GetPagination() *query.PageRequest { if m != nil { return m.Pagination } @@ -186,7 +240,7 @@ func (m *QueryFailuresResponse) Reset() { *m = QueryFailuresResponse{} } func (m *QueryFailuresResponse) String() string { return proto.CompactTextString(m) } func (*QueryFailuresResponse) ProtoMessage() {} func (*QueryFailuresResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f9524a427f219917, []int{3} + return fileDescriptor_f9524a427f219917, []int{4} } func (m *QueryFailuresResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -233,6 +287,7 @@ func init() { proto.RegisterType((*QueryParamsRequest)(nil), "neutron.contractmanager.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "neutron.contractmanager.QueryParamsResponse") proto.RegisterType((*QueryFailuresRequest)(nil), "neutron.contractmanager.QueryFailuresRequest") + proto.RegisterType((*QueryFailureRequest)(nil), "neutron.contractmanager.QueryFailureRequest") proto.RegisterType((*QueryFailuresResponse)(nil), "neutron.contractmanager.QueryFailuresResponse") } @@ -241,41 +296,41 @@ func init() { } var fileDescriptor_f9524a427f219917 = []byte{ - // 531 bytes of a gzipped FileDescriptorProto + // 542 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x41, 0x6b, 0x13, 0x41, 0x14, 0xc7, 0x33, 0x69, 0x1b, 0xdb, 0x29, 0x28, 0x8c, 0x11, 0x43, 0xd0, 0x4d, 0xba, 0x55, 0x1b, 0xad, 0x99, 0xa1, 0xa9, 0x07, 0x15, 0x04, 0xcd, 0xa1, 0xe2, 0xad, 0xae, 0x9e, 0xbc, 0xc8, 0x24, - 0x19, 0xc7, 0x85, 0x66, 0x66, 0x3b, 0x33, 0x5b, 0x2c, 0xa5, 0x17, 0x6f, 0x82, 0x07, 0x41, 0xc1, - 0x2f, 0xa0, 0x1f, 0xc0, 0x6f, 0xd1, 0x63, 0xc1, 0x8b, 0x27, 0x91, 0xc4, 0x0f, 0x22, 0x99, 0x99, - 0xb4, 0x4d, 0xca, 0x36, 0xf1, 0xa0, 0xb7, 0xd9, 0xb7, 0xef, 0xff, 0xde, 0xef, 0xfd, 0xe7, 0xed, - 0xc2, 0x65, 0xc1, 0x52, 0xa3, 0xa4, 0x20, 0x6d, 0x29, 0x8c, 0xa2, 0x6d, 0xd3, 0xa5, 0x82, 0x72, - 0xa6, 0xc8, 0x76, 0xca, 0xd4, 0x2e, 0x4e, 0x94, 0x34, 0x12, 0x5d, 0xf6, 0x49, 0x78, 0x2c, 0xa9, - 0x7c, 0xab, 0x2d, 0x75, 0x57, 0x6a, 0xd2, 0xa2, 0x9a, 0x39, 0x05, 0xd9, 0x59, 0x6b, 0x31, 0x43, - 0xd7, 0x48, 0x42, 0x79, 0x2c, 0xa8, 0x89, 0xa5, 0x70, 0x45, 0xca, 0x45, 0x2e, 0xb9, 0xb4, 0x47, - 0x32, 0x38, 0xf9, 0xe8, 0x15, 0x2e, 0x25, 0xdf, 0x62, 0x84, 0x26, 0x31, 0xa1, 0x42, 0x48, 0x63, - 0x25, 0xda, 0xbf, 0xbd, 0x9e, 0x45, 0xf7, 0x8a, 0xc6, 0x5b, 0xa9, 0x62, 0x3e, 0xed, 0x5a, 0x56, - 0x5a, 0x42, 0x15, 0xed, 0xfa, 0x62, 0x61, 0x11, 0xa2, 0xa7, 0x03, 0xc4, 0x4d, 0x1b, 0x8c, 0xd8, - 0x76, 0xca, 0xb4, 0x09, 0x9f, 0xc3, 0x8b, 0x23, 0x51, 0x9d, 0x48, 0xa1, 0x19, 0x7a, 0x00, 0x0b, - 0x4e, 0x5c, 0x02, 0x55, 0x50, 0x5b, 0x6c, 0x54, 0x70, 0x86, 0x07, 0xd8, 0x09, 0x9b, 0xb3, 0x07, - 0x3f, 0x2b, 0xb9, 0xc8, 0x8b, 0xc2, 0xcf, 0x00, 0x16, 0x6d, 0xd9, 0x0d, 0x07, 0x3a, 0x6c, 0x87, - 0x4a, 0xf0, 0x1c, 0xed, 0x74, 0x14, 0xd3, 0xae, 0xf0, 0x42, 0x34, 0x7c, 0x44, 0x57, 0x21, 0xf4, - 0x53, 0xbd, 0x8c, 0x3b, 0xa5, 0x7c, 0x15, 0xd4, 0x66, 0xa3, 0x05, 0x1f, 0x79, 0xd2, 0x41, 0x1b, - 0x10, 0x1e, 0x5b, 0x5a, 0x9a, 0xb1, 0x50, 0x37, 0xb0, 0xf3, 0x1f, 0x0f, 0xfc, 0xc7, 0xee, 0xc6, - 0xbc, 0xff, 0x78, 0x93, 0x72, 0xe6, 0x9b, 0x46, 0x27, 0x94, 0xe1, 0x17, 0x00, 0x2f, 0x8d, 0x91, - 0xf9, 0x91, 0x9b, 0x70, 0xde, 0xb7, 0x1b, 0xb0, 0xcd, 0xd4, 0x16, 0x1b, 0xd5, 0xcc, 0xa1, 0xbd, - 0xd8, 0x4f, 0x7d, 0xa4, 0x43, 0x8f, 0x47, 0x28, 0xf3, 0x96, 0x72, 0x65, 0x22, 0xa5, 0x03, 0x38, - 0x89, 0xd9, 0x78, 0x37, 0x07, 0xe7, 0x2c, 0x26, 0x7a, 0x0f, 0x60, 0xc1, 0x79, 0x8c, 0x56, 0x33, - 0x79, 0x4e, 0x5f, 0x6c, 0xf9, 0xf6, 0x74, 0xc9, 0xae, 0x77, 0xb8, 0xf2, 0xf6, 0xfb, 0xef, 0x8f, - 0xf9, 0x25, 0x54, 0x21, 0x67, 0xef, 0x12, 0xfa, 0x06, 0xe0, 0xf9, 0x47, 0xee, 0xca, 0xbc, 0x09, - 0xa8, 0x7e, 0x76, 0xa7, 0xb1, 0x15, 0x28, 0xe3, 0x69, 0xd3, 0x3d, 0xda, 0x43, 0x8b, 0x76, 0x1f, - 0xdd, 0x25, 0x13, 0xbe, 0x06, 0x4d, 0xf6, 0xfc, 0x32, 0xed, 0x93, 0xbd, 0xe3, 0x5d, 0xda, 0x47, - 0x5f, 0x01, 0xbc, 0x30, 0xca, 0xac, 0xff, 0x35, 0xf4, 0xba, 0x85, 0xae, 0xa3, 0xd5, 0xbf, 0x80, - 0x46, 0x9f, 0x00, 0x9c, 0xff, 0x5f, 0x80, 0x37, 0x2d, 0xe0, 0x32, 0x5a, 0x9a, 0x08, 0xd8, 0x7c, - 0x76, 0xd0, 0x0b, 0xc0, 0x61, 0x2f, 0x00, 0xbf, 0x7a, 0x01, 0xf8, 0xd0, 0x0f, 0x72, 0x87, 0xfd, - 0x20, 0xf7, 0xa3, 0x1f, 0xe4, 0x5e, 0xdc, 0xe3, 0xb1, 0x79, 0x9d, 0xb6, 0x70, 0x5b, 0x76, 0x87, - 0x65, 0xea, 0x52, 0xf1, 0xa3, 0x92, 0x3b, 0x77, 0xc8, 0x9b, 0x53, 0x75, 0xcd, 0x6e, 0xc2, 0x74, - 0xab, 0x60, 0x7f, 0x4a, 0xeb, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x96, 0xc1, 0xe7, 0xbe, 0x81, - 0x05, 0x00, 0x00, + 0x19, 0xd7, 0x85, 0x66, 0x67, 0xbb, 0x33, 0x5b, 0x5a, 0x4a, 0x2f, 0x9e, 0x3c, 0x78, 0x10, 0x14, + 0x3f, 0x81, 0xde, 0xfd, 0x18, 0x3d, 0x16, 0xbc, 0x78, 0x12, 0x49, 0xfc, 0x20, 0x92, 0x99, 0x97, + 0xa6, 0x69, 0x58, 0x37, 0x8a, 0xf4, 0x36, 0x79, 0x79, 0xff, 0xff, 0xfb, 0xed, 0x7f, 0xde, 0x2e, + 0x5e, 0x0e, 0x45, 0xa2, 0x63, 0x19, 0xb2, 0xb6, 0x0c, 0x75, 0xcc, 0xdb, 0xba, 0xcb, 0x43, 0xee, + 0x8b, 0x98, 0x6d, 0x27, 0x22, 0xde, 0xa3, 0x51, 0x2c, 0xb5, 0x24, 0x97, 0xa1, 0x89, 0x9e, 0x6a, + 0x2a, 0xdf, 0x6a, 0x4b, 0xd5, 0x95, 0x8a, 0xb5, 0xb8, 0x12, 0x56, 0xc1, 0x76, 0xd6, 0x5a, 0x42, + 0xf3, 0x35, 0x16, 0x71, 0x3f, 0x08, 0xb9, 0x0e, 0x64, 0x68, 0x4d, 0xca, 0x45, 0x5f, 0xfa, 0xd2, + 0x1c, 0xd9, 0xe0, 0x04, 0xd5, 0x2b, 0xbe, 0x94, 0xfe, 0x96, 0x60, 0x3c, 0x0a, 0x18, 0x0f, 0x43, + 0xa9, 0x8d, 0x44, 0xc1, 0xbf, 0xd7, 0xd3, 0xe8, 0x5e, 0xf1, 0x60, 0x2b, 0x89, 0x05, 0xb4, 0x5d, + 0x4b, 0x6b, 0x8b, 0x78, 0xcc, 0xbb, 0x60, 0xe6, 0x16, 0x31, 0x79, 0x3a, 0x40, 0xdc, 0x34, 0x45, + 0x4f, 0x6c, 0x27, 0x42, 0x69, 0xf7, 0x39, 0xbe, 0x38, 0x56, 0x55, 0x91, 0x0c, 0x95, 0x20, 0x0f, + 0x70, 0xc1, 0x8a, 0x4b, 0xa8, 0x8a, 0x6a, 0x8b, 0x8d, 0x0a, 0x4d, 0xc9, 0x80, 0x5a, 0x61, 0x73, + 0xf6, 0xf0, 0x47, 0x25, 0xe7, 0x81, 0xc8, 0xdd, 0xc5, 0x45, 0xe3, 0xba, 0x61, 0x39, 0x87, 0xd3, + 0x48, 0x09, 0x9f, 0xe3, 0x9d, 0x4e, 0x2c, 0x94, 0xf5, 0x5d, 0xf0, 0x86, 0x3f, 0xc9, 0x06, 0xc6, + 0xa3, 0xc8, 0x4a, 0x33, 0x66, 0xe8, 0x0d, 0x6a, 0xf3, 0xa5, 0x83, 0x7c, 0xa9, 0xbd, 0x11, 0xc8, + 0x97, 0x6e, 0x72, 0x5f, 0x80, 0xab, 0x77, 0x42, 0xe9, 0x7e, 0x42, 0xf0, 0x40, 0x30, 0x3a, 0x7b, + 0xf2, 0x55, 0x8c, 0x21, 0xce, 0x97, 0x41, 0xa7, 0x94, 0xaf, 0xa2, 0xda, 0xac, 0xb7, 0x00, 0x95, + 0x27, 0x9d, 0xff, 0x06, 0xf6, 0x19, 0xe1, 0x4b, 0xa7, 0x32, 0x81, 0xac, 0x9b, 0x78, 0x1e, 0xc6, + 0x0d, 0xd8, 0x66, 0x6a, 0x8b, 0x8d, 0x6a, 0x6a, 0xda, 0x20, 0x86, 0xb8, 0x8f, 0x75, 0xe4, 0xf1, + 0x18, 0x65, 0xde, 0x50, 0xae, 0x64, 0x52, 0x5a, 0x80, 0x93, 0x98, 0x8d, 0xb7, 0x73, 0x78, 0xce, + 0x60, 0x92, 0x77, 0x08, 0x17, 0xec, 0xe5, 0x92, 0xd5, 0x54, 0x9e, 0xc9, 0x8d, 0x2a, 0xdf, 0x9e, + 0xae, 0xd9, 0xce, 0x76, 0x57, 0xde, 0x7c, 0xfb, 0xf5, 0x21, 0xbf, 0x44, 0x2a, 0xec, 0xcf, 0x4b, + 0x4c, 0xbe, 0x22, 0x7c, 0xfe, 0x91, 0xbd, 0x32, 0x08, 0x81, 0x64, 0x4c, 0x1a, 0xdf, 0x80, 0x32, + 0x9d, 0xaa, 0x7b, 0x44, 0xf6, 0xd0, 0x90, 0xdd, 0x27, 0x77, 0x59, 0xc6, 0x5b, 0xa8, 0xd8, 0x3e, + 0xec, 0xd2, 0x01, 0xdb, 0x1f, 0xad, 0xd2, 0x01, 0xf9, 0x82, 0xf0, 0x85, 0x71, 0x64, 0x45, 0xea, + 0xd3, 0x52, 0xfc, 0x1b, 0xf4, 0xba, 0x81, 0xae, 0x93, 0xd5, 0xbf, 0x80, 0x26, 0x1f, 0x11, 0x9e, + 0x3f, 0x2b, 0xc0, 0x9b, 0x06, 0x70, 0x99, 0x2c, 0x65, 0x02, 0x36, 0x9f, 0x1d, 0xf6, 0x1c, 0x74, + 0xd4, 0x73, 0xd0, 0xcf, 0x9e, 0x83, 0xde, 0xf7, 0x9d, 0xdc, 0x51, 0xdf, 0xc9, 0x7d, 0xef, 0x3b, + 0xb9, 0x17, 0xf7, 0xfc, 0x40, 0xbf, 0x4e, 0x5a, 0xb4, 0x2d, 0xbb, 0x43, 0x9b, 0xba, 0x8c, 0xfd, + 0x63, 0xcb, 0x9d, 0x3b, 0x6c, 0x77, 0xc2, 0x57, 0xef, 0x45, 0x42, 0xb5, 0x0a, 0xe6, 0x63, 0xb8, + 0xfe, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xfa, 0xdd, 0x5e, 0x09, 0xf9, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -293,7 +348,7 @@ type QueryClient interface { // Parameters queries the parameters of the module. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) // Queries a Failure by contract address and failure ID. - AddressFailure(ctx context.Context, in *QueryFailuresRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) + AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) // Queries Failures by contract address. AddressFailures(ctx context.Context, in *QueryFailuresRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) // Queries a list of Failures occurred on the network. @@ -317,7 +372,7 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } -func (c *queryClient) AddressFailure(ctx context.Context, in *QueryFailuresRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) { +func (c *queryClient) AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) { out := new(QueryFailuresResponse) err := c.cc.Invoke(ctx, "/neutron.contractmanager.Query/AddressFailure", in, out, opts...) if err != nil { @@ -349,7 +404,7 @@ type QueryServer interface { // Parameters queries the parameters of the module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) // Queries a Failure by contract address and failure ID. - AddressFailure(context.Context, *QueryFailuresRequest) (*QueryFailuresResponse, error) + AddressFailure(context.Context, *QueryFailureRequest) (*QueryFailuresResponse, error) // Queries Failures by contract address. AddressFailures(context.Context, *QueryFailuresRequest) (*QueryFailuresResponse, error) // Queries a list of Failures occurred on the network. @@ -363,7 +418,7 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } -func (*UnimplementedQueryServer) AddressFailure(ctx context.Context, req *QueryFailuresRequest) (*QueryFailuresResponse, error) { +func (*UnimplementedQueryServer) AddressFailure(ctx context.Context, req *QueryFailureRequest) (*QueryFailuresResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddressFailure not implemented") } func (*UnimplementedQueryServer) AddressFailures(ctx context.Context, req *QueryFailuresRequest) (*QueryFailuresResponse, error) { @@ -396,7 +451,7 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf } func _Query_AddressFailure_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryFailuresRequest) + in := new(QueryFailureRequest) if err := dec(in); err != nil { return nil, err } @@ -408,7 +463,7 @@ func _Query_AddressFailure_Handler(srv interface{}, ctx context.Context, dec fun FullMethod: "/neutron.contractmanager.Query/AddressFailure", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).AddressFailure(ctx, req.(*QueryFailuresRequest)) + return srv.(QueryServer).AddressFailure(ctx, req.(*QueryFailureRequest)) } return interceptor(ctx, in, info, handler) } @@ -546,6 +601,48 @@ func (m *QueryFailuresRequest) MarshalTo(dAtA []byte) (int, error) { } func (m *QueryFailuresRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pagination != nil { + { + size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryFailureRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryFailureRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFailureRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -658,6 +755,23 @@ func (m *QueryParamsResponse) Size() (n int) { } func (m *QueryFailuresRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Pagination != nil { + l = m.Pagination.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryFailureRequest) Size() (n int) { if m == nil { return 0 } @@ -864,6 +978,124 @@ func (m *QueryFailuresRequest) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: QueryFailuresRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pagination == nil { + m.Pagination = &query.PageRequest{} + } + if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFailureRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFailureRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFailureRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) diff --git a/x/contractmanager/types/query.pb.gw.go b/x/contractmanager/types/query.pb.gw.go index 2c201192b..9570c42b4 100644 --- a/x/contractmanager/types/query.pb.gw.go +++ b/x/contractmanager/types/query.pb.gw.go @@ -56,7 +56,7 @@ var ( ) func request_Query_AddressFailure_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryFailuresRequest + var protoReq QueryFailureRequest var metadata runtime.ServerMetadata var ( @@ -101,7 +101,7 @@ func request_Query_AddressFailure_0(ctx context.Context, marshaler runtime.Marsh } func local_request_Query_AddressFailure_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryFailuresRequest + var protoReq QueryFailureRequest var metadata runtime.ServerMetadata var ( From 3a7ba9b80551996fa90ab121b5dafe2c37978127 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 8 Aug 2024 07:10:38 -0300 Subject: [PATCH 05/60] upd cli as well --- x/contractmanager/client/cli/query_failure.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/contractmanager/client/cli/query_failure.go b/x/contractmanager/client/cli/query_failure.go index 9c320ece8..6898b88f9 100644 --- a/x/contractmanager/client/cli/query_failure.go +++ b/x/contractmanager/client/cli/query_failure.go @@ -78,7 +78,7 @@ func CmdFailureDetails() *cobra.Command { queryClient := contractmanagertypes.NewQueryClient(clientCtx) if _, err = queryClient.AddressFailure( cmd.Context(), - &contractmanagertypes.QueryFailuresRequest{Address: address, FailureId: failureID}, + &contractmanagertypes.QueryFailureRequest{Address: address, FailureId: failureID}, ); err != nil { return err } From d586932a98fe72f5229a14540d398ce242c71aa0 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 8 Aug 2024 16:01:37 +0400 Subject: [PATCH 06/60] omitempty for ica creation ordering field --- wasmbinding/bindings/msg.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index dad007622..2aee5622a 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -81,7 +81,7 @@ type RegisterInterchainAccount struct { ConnectionId string `json:"connection_id"` InterchainAccountId string `json:"interchain_account_id"` RegisterFee sdk.Coins `json:"register_fee,omitempty"` - Ordering string `json:"ordering"` + Ordering string `json:"ordering,omitempty"` } // RegisterInterchainAccountResponse holds response for RegisterInterchainAccount. From f103be80bb1bb131fb19ec731f8926ad1c237cbe Mon Sep 17 00:00:00 2001 From: nhpd Date: Mon, 12 Aug 2024 23:55:09 +0400 Subject: [PATCH 07/60] fix --- wasmbinding/message_plugin.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 37086aee2..61499d249 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -869,13 +869,13 @@ func (m *CustomMessenger) performRegisterInterchainAccount(ctx sdk.Context, cont // parse incoming ordering. If nothing passed, use ORDERED by default var orderValue types1.Order if reg.Ordering == "" { + orderValue = types1.ORDERED + } else { orderValueInt, ok := types1.Order_value[reg.Ordering] if !ok { return nil, fmt.Errorf("failed to register interchain account: incorrect order value passed: %s", reg.Ordering) } orderValue = types1.Order(orderValueInt) - } else { - orderValue = types1.ORDERED } msg := ictxtypes.MsgRegisterInterchainAccount{ From ef1d7992fbdd6a927a2c7c4b4eebe2dfe2cdd27a Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Wed, 14 Aug 2024 13:57:51 +0300 Subject: [PATCH 08/60] add blocker option to schedules --- proto/neutron/cron/schedule.proto | 9 + wasmbinding/bindings/msg.go | 7 +- wasmbinding/message_plugin.go | 2 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 2 +- x/cron/keeper/keeper.go | 31 +- x/cron/keeper/keeper_test.go | 127 +++- x/cron/keeper/migrations.go | 22 + x/cron/migrations/v2/store.go | 56 ++ x/cron/migrations/v2/store_test.go | 53 ++ x/cron/module.go | 6 +- x/cron/types/schedule.pb.go | 112 ++- x/cron/types/v1/schedule.pb.go | 839 +++++++++++++++++++++ x/dex/types/limit_order_tranche_user.pb.go | 5 +- 14 files changed, 1224 insertions(+), 49 deletions(-) create mode 100644 x/cron/keeper/migrations.go create mode 100644 x/cron/migrations/v2/store.go create mode 100644 x/cron/migrations/v2/store_test.go create mode 100644 x/cron/types/v1/schedule.pb.go diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index 5df38de34..8b60fd950 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -5,6 +5,13 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; +// BlockerType defines when messages will be executed in the block +enum BlockerType { + BEGIN = 0; + END = 1; + BOTH = 2; +} + message Schedule { // Name of schedule string name = 1; @@ -14,6 +21,8 @@ message Schedule { repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; + // Blocker where the messages will be executed + BlockerType blocker = 5; } message MsgExecuteContract { diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 03fc3640b..9f38c0fb0 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -195,9 +195,10 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` + Blocker uint64 `json:"blocker"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index a22c5e78d..d6fe12fdc 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -985,7 +985,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs) + err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, addSchedule.Blocker) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), diff --git a/x/cron/genesis.go b/x/cron/genesis.go index 974790399..b5e0e1b01 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, uint64(elem.Blocker)) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index b778f8fba..f8825aca3 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -134,7 +134,7 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, uint64(item.Blocker)) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 2be2f49ee..8da755a5f 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -67,19 +67,32 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // ExecuteReadySchedules gets all schedules that are due for execution (with limit that is equal to Params.Limit) // and executes messages in each one // NOTE that errors in contract calls rollback all already executed messages -func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context) { +func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, isBeginBlocker bool) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) schedules := k.getSchedulesReadyForExecution(ctx) for _, schedule := range schedules { - err := k.executeSchedule(ctx, schedule) - recordExecutedSchedule(err, schedule) + if isBeginBlocker && (schedule.Blocker == types.BlockerType_BEGIN || schedule.Blocker == types.BlockerType_BOTH) { + err := k.executeSchedule(ctx, schedule) + recordExecutedSchedule(err, schedule) + } + + if !isBeginBlocker && (schedule.Blocker == types.BlockerType_END || schedule.Blocker == types.BlockerType_BOTH) { + err := k.executeSchedule(ctx, schedule) + recordExecutedSchedule(err, schedule) + } } } // AddSchedule adds new schedule to execution for every block `period`. // First schedule execution is supposed to be on `now + period` block. -func (k *Keeper) AddSchedule(ctx sdk.Context, name string, period uint64, msgs []types.MsgExecuteContract) error { +func (k *Keeper) AddSchedule( + ctx sdk.Context, + name string, + period uint64, + msgs []types.MsgExecuteContract, + blocker uint64, +) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) } @@ -90,6 +103,16 @@ func (k *Keeper) AddSchedule(ctx sdk.Context, name string, period uint64, msgs [ Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block } + + switch blocker { + case 0: + schedule.Blocker = types.BlockerType_BEGIN + case 2: + schedule.Blocker = types.BlockerType_BOTH + default: + schedule.Blocker = types.BlockerType_END + } + k.storeSchedule(ctx, schedule) k.changeTotalCount(ctx, 1) diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index 8abe2060c..12f88bd60 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -44,7 +44,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { schedules := []types.Schedule{ { Name: "1_unready1", - Period: 3, + Period: 10, Msgs: []types.MsgExecuteContract{ { Contract: "1_neutron", @@ -52,10 +52,11 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, + Blocker: types.BlockerType_BEGIN, }, { Name: "2_ready1", - Period: 3, + Period: 4, Msgs: []types.MsgExecuteContract{ { Contract: "2_neutron", @@ -63,10 +64,11 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + Blocker: types.BlockerType_BEGIN, }, { Name: "3_ready2", - Period: 3, + Period: 4, Msgs: []types.MsgExecuteContract{ { Contract: "3_neutron", @@ -74,12 +76,14 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + Blocker: types.BlockerType_BEGIN, }, { Name: "4_unready2", - Period: 3, + Period: 10, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, + Blocker: types.BlockerType_BOTH, }, { Name: "5_ready3", @@ -91,22 +95,46 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + Blocker: types.BlockerType_BOTH, + }, + { + Name: "6_ready4", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "6_neutron", + Msg: "6_msg", + }, + }, + LastExecuteHeight: 0, + Blocker: types.BlockerType_END, + }, + { + Name: "7_ready5", + Period: 1, + Msgs: []types.MsgExecuteContract{ + { + Contract: "7_neutron", + Msg: "7_msg", + }, + }, + LastExecuteHeight: 0, + Blocker: types.BlockerType_BOTH, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, uint64(item.Blocker)) require.NoError(t, err) } count := k.GetScheduleCount(ctx) - require.Equal(t, count, int32(5)) + require.Equal(t, count, int32(7)) ctx = ctx.WithBlockHeight(5) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr).AnyTimes() wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "2_neutron", @@ -120,45 +148,84 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx) + k.ExecuteReadySchedules(ctx, true) unready1, _ := k.GetSchedule(ctx, "1_unready1") ready1, _ := k.GetSchedule(ctx, "2_ready1") ready2, _ := k.GetSchedule(ctx, "3_ready2") unready2, _ := k.GetSchedule(ctx, "4_unready2") ready3, _ := k.GetSchedule(ctx, "5_ready3") + ready4, _ := k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(0), ready3.LastExecuteHeight) + require.Equal(t, uint64(0), ready4.LastExecuteHeight) // let's make another call at the next height // Notice that now only one ready schedule left because we got limit of 2 at once ctx = ctx.WithBlockHeight(6) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "5_neutron", Msg: []byte("5_msg"), Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) + wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ + Sender: testutil.TestOwnerAddress, + Contract: "6_neutron", + Msg: []byte("6_msg"), + Funds: sdk.NewCoins(), + }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx) + k.ExecuteReadySchedules(ctx, false) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") ready2, _ = k.GetSchedule(ctx, "3_ready2") unready2, _ = k.GetSchedule(ctx, "4_unready2") ready3, _ = k.GetSchedule(ctx, "5_ready3") + ready4, _ = k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(6), ready3.LastExecuteHeight) + require.Equal(t, uint64(6), ready4.LastExecuteHeight) + + ctx = ctx.WithBlockHeight(7) + + wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ + Sender: testutil.TestOwnerAddress, + Contract: "7_neutron", + Msg: []byte("7_msg"), + Funds: sdk.NewCoins(), + }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) + + k.ExecuteReadySchedules(ctx, true) + + ready5, _ := k.GetSchedule(ctx, "7_ready5") + + require.Equal(t, uint64(7), ready5.LastExecuteHeight) + + ctx = ctx.WithBlockHeight(9) + + wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ + Sender: testutil.TestOwnerAddress, + Contract: "7_neutron", + Msg: []byte("7_msg"), + Funds: sdk.NewCoins(), + }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) + + k.ExecuteReadySchedules(ctx, false) + + ready5, _ = k.GetSchedule(ctx, "7_ready5") + + require.Equal(t, uint64(9), ready5.LastExecuteHeight) } func TestAddSchedule(t *testing.T) { @@ -183,11 +250,35 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }) + }, 0) + require.NoError(t, err) + + err = k.AddSchedule(ctx, "b", 7, []types.MsgExecuteContract{ + { + Contract: "c", + Msg: "m", + }, + }, 1) + require.NoError(t, err) + + err = k.AddSchedule(ctx, "c", 7, []types.MsgExecuteContract{ + { + Contract: "c", + Msg: "m", + }, + }, 2) + require.NoError(t, err) + + err = k.AddSchedule(ctx, "d", 7, []types.MsgExecuteContract{ + { + Contract: "c", + Msg: "m", + }, + }, 7) require.NoError(t, err) // second time with same name returns error - err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}) + err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, 1) require.Error(t, err) scheduleA, found := k.GetSchedule(ctx, "a") @@ -198,6 +289,13 @@ func TestAddSchedule(t *testing.T) { {Contract: "c", Msg: "m"}, }) + schedules := k.GetAllSchedules(ctx) + require.Len(t, schedules, 4) + require.Equal(t, schedules[0].Blocker, types.BlockerType_BEGIN) + require.Equal(t, schedules[1].Blocker, types.BlockerType_END) + require.Equal(t, schedules[2].Blocker, types.BlockerType_BOTH) + require.Equal(t, schedules[3].Blocker, types.BlockerType_END) + // remove schedule works k.RemoveSchedule(ctx, "a") _, found = k.GetSchedule(ctx, "a") @@ -223,9 +321,10 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), + Blocker: types.BlockerType_END, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, uint64(s.Blocker)) require.NoError(t, err) } diff --git a/x/cron/keeper/migrations.go b/x/cron/keeper/migrations.go new file mode 100644 index 000000000..0166a8da9 --- /dev/null +++ b/x/cron/keeper/migrations.go @@ -0,0 +1,22 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey) +} diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go new file mode 100644 index 000000000..a1f8008a8 --- /dev/null +++ b/x/cron/migrations/v2/store.go @@ -0,0 +1,56 @@ +package v2 + +import ( + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v4/x/cron/types" +) + +// MigrateStore performs in-place store migrations. +// The migration adds Blocker for execution to schedules. +func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + return migrateSchedules(ctx, cdc, storeKey) +} + +type migrationUpdate struct { + key []byte + val []byte +} + +func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + ctx.Logger().Info("Migrating cron Schedules...") + + store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + schedulesToUpdate := make([]migrationUpdate, 0) + + for ; iterator.Valid(); iterator.Next() { + var schedule types.Schedule + cdc.MustUnmarshal(iterator.Value(), &schedule) + // Set execution in EndBlocker + schedule.Blocker = types.BlockerType_END + + schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ + key: iterator.Key(), + val: cdc.MustMarshal(&schedule), + }) + } + + err := iterator.Close() + if err != nil { + return errorsmod.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated Schedules + for _, v := range schedulesToUpdate { + store.Set(v.key, v.val) + } + + ctx.Logger().Info("Finished migrating cron Schedules...") + + return nil +} diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go new file mode 100644 index 000000000..75dd42e52 --- /dev/null +++ b/x/cron/migrations/v2/store_test.go @@ -0,0 +1,53 @@ +package v2_test + +import ( + "testing" + + "cosmossdk.io/store/prefix" + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v4/testutil" + v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" + "github.com/neutron-org/neutron/v4/x/cron/types" + v1types "github.com/neutron-org/neutron/v4/x/cron/types/v1" +) + +type V4CronMigrationTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(V4CronMigrationTestSuite)) +} + +func (suite *V4CronMigrationTestSuite) TestScheduleUpgrade() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + storeKey = app.GetKey(types.StoreKey) + ctx = suite.ChainA.GetContext() + cdc = app.AppCodec() + ) + + schedule := v1types.Schedule{ + Name: "name", + Period: 3, + Msgs: []v1types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + LastExecuteHeight: 1, + } + + store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) + bz := cdc.MustMarshal(&schedule) + store.Set(types.GetScheduleKey(schedule.Name), bz) + + // Run migration + suite.NoError(v2.MigrateStore(ctx, cdc, storeKey)) + + // Check Schedule has correct Blocker + newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) + suite.Equal(newSchedule.Blocker, types.BlockerType_END) +} diff --git a/x/cron/module.go b/x/cron/module.go index 60dc09b91..df953c111 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -155,10 +155,12 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block -func (am AppModule) BeginBlock(_ sdk.Context) {} +func (am AppModule) BeginBlock(ctx sdk.Context) { + am.keeper.ExecuteReadySchedules(ctx, true) +} // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { - am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx)) + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), false) return []abci.ValidatorUpdate{}, nil } diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index cda29cf72..3cd7cd104 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -23,6 +23,35 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// BlockerType defines when messages will be executed in the block +type BlockerType int32 + +const ( + BlockerType_BEGIN BlockerType = 0 + BlockerType_END BlockerType = 1 + BlockerType_BOTH BlockerType = 2 +) + +var BlockerType_name = map[int32]string{ + 0: "BEGIN", + 1: "END", + 2: "BOTH", +} + +var BlockerType_value = map[string]int32{ + "BEGIN": 0, + "END": 1, + "BOTH": 2, +} + +func (x BlockerType) String() string { + return proto.EnumName(BlockerType_name, int32(x)) +} + +func (BlockerType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_49ace1b59de613ef, []int{0} +} + type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -32,6 +61,8 @@ type Schedule struct { Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` + // Blocker where the messages will be executed + Blocker BlockerType `protobuf:"varint,5,opt,name=blocker,proto3,enum=neutron.cron.BlockerType" json:"blocker,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -95,6 +126,13 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } +func (m *Schedule) GetBlocker() BlockerType { + if m != nil { + return m.Blocker + } + return BlockerType_BEGIN +} + type MsgExecuteContract struct { // Contract is the address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` @@ -195,6 +233,7 @@ func (m *ScheduleCount) GetCount() int32 { } func init() { + proto.RegisterEnum("neutron.cron.BlockerType", BlockerType_name, BlockerType_value) proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") @@ -203,27 +242,31 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 309 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xfb, 0x30, - 0x18, 0xc6, 0x9b, 0xff, 0xba, 0xb1, 0xe5, 0xaf, 0xa0, 0x71, 0x48, 0x99, 0x10, 0x4b, 0x41, 0xe8, - 0xc5, 0x14, 0xd4, 0x93, 0xc7, 0x0e, 0x61, 0x17, 0x2f, 0xf5, 0xe6, 0x65, 0x74, 0x59, 0x48, 0x0b, - 0x6b, 0x53, 0x9a, 0x54, 0xe6, 0xb7, 0xf0, 0x33, 0xf8, 0x69, 0x76, 0xdc, 0xd1, 0x93, 0x48, 0xfb, - 0x45, 0x24, 0x69, 0x26, 0x82, 0x97, 0xf0, 0x7b, 0x78, 0xde, 0x27, 0xef, 0xfb, 0x26, 0xf0, 0xa2, - 0x64, 0x8d, 0xaa, 0x45, 0x19, 0x51, 0x7d, 0x48, 0x9a, 0xb1, 0x75, 0xb3, 0x61, 0xa4, 0xaa, 0x85, - 0x12, 0xe8, 0xc8, 0x9a, 0x44, 0x9b, 0xb3, 0x29, 0x17, 0x5c, 0x18, 0x23, 0xd2, 0xd4, 0xd7, 0x04, - 0xef, 0x00, 0x8e, 0x9f, 0x6c, 0x0c, 0x21, 0xe8, 0x96, 0x69, 0xc1, 0x3c, 0xe0, 0x83, 0x70, 0x92, - 0x18, 0x46, 0xe7, 0x70, 0x54, 0xb1, 0x3a, 0x17, 0x6b, 0xef, 0x9f, 0x0f, 0x42, 0x37, 0xb1, 0x0a, - 0xdd, 0x43, 0xb7, 0x90, 0x5c, 0x7a, 0x03, 0x7f, 0x10, 0xfe, 0xbf, 0xf1, 0xc9, 0xef, 0x5e, 0xe4, - 0x51, 0xf2, 0x87, 0x2d, 0xa3, 0x8d, 0x62, 0x73, 0x51, 0xaa, 0x3a, 0xa5, 0x2a, 0x76, 0x77, 0x9f, - 0x97, 0x4e, 0x62, 0x32, 0x88, 0xc0, 0xb3, 0x4d, 0x2a, 0xd5, 0x92, 0xf5, 0x35, 0xcb, 0x8c, 0xe5, - 0x3c, 0x53, 0x9e, 0x6b, 0x1a, 0x9c, 0x6a, 0xcb, 0xa6, 0x17, 0xc6, 0x08, 0x62, 0x88, 0xfe, 0xde, - 0x88, 0x66, 0x70, 0x4c, 0x2d, 0xdb, 0x89, 0x7f, 0x34, 0x3a, 0x81, 0x83, 0x42, 0x72, 0x33, 0xf2, - 0x24, 0xd1, 0x18, 0x5c, 0xc1, 0xe3, 0xc3, 0x9e, 0x73, 0xd1, 0x94, 0x0a, 0x4d, 0xe1, 0x90, 0x6a, - 0x30, 0xd9, 0x61, 0xd2, 0x8b, 0x78, 0xb1, 0x6b, 0x31, 0xd8, 0xb7, 0x18, 0x7c, 0xb5, 0x18, 0xbc, - 0x75, 0xd8, 0xd9, 0x77, 0xd8, 0xf9, 0xe8, 0xb0, 0xf3, 0x4c, 0x78, 0xae, 0xb2, 0x66, 0x45, 0xa8, - 0x28, 0x22, 0xbb, 0xec, 0xb5, 0xa8, 0xf9, 0x81, 0xa3, 0x97, 0xbb, 0x68, 0xdb, 0x7f, 0x83, 0x7a, - 0xad, 0x98, 0x5c, 0x8d, 0xcc, 0x03, 0xdf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x19, 0x38, - 0x8d, 0xa3, 0x01, 0x00, 0x00, + // 371 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xcf, 0x6a, 0xdb, 0x40, + 0x10, 0xc6, 0xb5, 0x96, 0xe4, 0x3f, 0xe3, 0xb6, 0xa8, 0x5b, 0x53, 0x54, 0x17, 0x54, 0x61, 0x28, + 0x88, 0x96, 0x4a, 0x60, 0xf7, 0xd4, 0xa3, 0x5c, 0x53, 0xf7, 0x10, 0x07, 0x14, 0x9f, 0x72, 0x31, + 0xf6, 0x7a, 0x59, 0x99, 0x58, 0x5a, 0x21, 0xad, 0x82, 0xfd, 0x16, 0x79, 0x2c, 0x1f, 0x7d, 0x4b, + 0x4e, 0x21, 0xd8, 0x2f, 0x12, 0xb4, 0x92, 0x83, 0x43, 0x2e, 0xcb, 0x37, 0xfc, 0xe6, 0x63, 0xe6, + 0xdb, 0x81, 0xaf, 0x31, 0xcd, 0x45, 0xca, 0x63, 0x8f, 0x14, 0x4f, 0x46, 0x42, 0xba, 0xcc, 0xd7, + 0xd4, 0x4d, 0x52, 0x2e, 0x38, 0x7e, 0x57, 0x41, 0xb7, 0x80, 0xdd, 0x0e, 0xe3, 0x8c, 0x4b, 0xe0, + 0x15, 0xaa, 0xec, 0xe9, 0xdd, 0x23, 0x68, 0x5e, 0x55, 0x36, 0x8c, 0x41, 0x8b, 0xe7, 0x11, 0x35, + 0x91, 0x8d, 0x9c, 0x56, 0x20, 0x35, 0xfe, 0x0c, 0xf5, 0x84, 0xa6, 0x2b, 0xbe, 0x34, 0x6b, 0x36, + 0x72, 0xb4, 0xa0, 0xaa, 0xf0, 0x1f, 0xd0, 0xa2, 0x8c, 0x65, 0xa6, 0x6a, 0xab, 0x4e, 0xbb, 0x6f, + 0xbb, 0xe7, 0xb3, 0xdc, 0x8b, 0x8c, 0x8d, 0x36, 0x94, 0xe4, 0x82, 0x0e, 0x79, 0x2c, 0xd2, 0x39, + 0x11, 0xbe, 0xb6, 0x7b, 0xfc, 0xa6, 0x04, 0xd2, 0x83, 0x5d, 0xf8, 0xb4, 0x9e, 0x67, 0x62, 0x46, + 0xcb, 0x9e, 0x59, 0x48, 0x57, 0x2c, 0x14, 0xa6, 0x26, 0x07, 0x7c, 0x2c, 0x50, 0xe5, 0x1e, 0x4b, + 0x80, 0x07, 0xd0, 0x58, 0xac, 0x39, 0xb9, 0xa1, 0xa9, 0xa9, 0xdb, 0xc8, 0xf9, 0xd0, 0xff, 0xf2, + 0x7a, 0x9c, 0x5f, 0xc2, 0xe9, 0x36, 0xa1, 0xc1, 0xa9, 0xb3, 0xe7, 0x03, 0x7e, 0xbb, 0x06, 0xee, + 0x42, 0x93, 0x54, 0xba, 0x8a, 0xf9, 0x52, 0x63, 0x03, 0xd4, 0x28, 0x63, 0x32, 0x67, 0x2b, 0x28, + 0x64, 0xef, 0x3b, 0xbc, 0x3f, 0x7d, 0xce, 0x90, 0xe7, 0xb1, 0xc0, 0x1d, 0xd0, 0x49, 0x21, 0xa4, + 0x57, 0x0f, 0xca, 0xe2, 0xc7, 0x4f, 0x68, 0x9f, 0xad, 0x80, 0x5b, 0xa0, 0xfb, 0xa3, 0x7f, 0xff, + 0x27, 0x86, 0x82, 0x1b, 0xa0, 0x8e, 0x26, 0x7f, 0x0d, 0x84, 0x9b, 0xa0, 0xf9, 0x97, 0xd3, 0xb1, + 0x51, 0xf3, 0xc7, 0xbb, 0x83, 0x85, 0xf6, 0x07, 0x0b, 0x3d, 0x1d, 0x2c, 0x74, 0x77, 0xb4, 0x94, + 0xfd, 0xd1, 0x52, 0x1e, 0x8e, 0x96, 0x72, 0xed, 0xb2, 0x95, 0x08, 0xf3, 0x85, 0x4b, 0x78, 0xe4, + 0x55, 0xf9, 0x7e, 0xf1, 0x94, 0x9d, 0xb4, 0x77, 0xfb, 0xdb, 0xdb, 0x94, 0x87, 0x16, 0xdb, 0x84, + 0x66, 0x8b, 0xba, 0x3c, 0xe1, 0xe0, 0x39, 0x00, 0x00, 0xff, 0xff, 0x52, 0x99, 0x7d, 0xa1, 0x05, + 0x02, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -246,6 +289,11 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Blocker != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.Blocker)) + i-- + dAtA[i] = 0x28 + } if m.LastExecuteHeight != 0 { i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) i-- @@ -378,6 +426,9 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } + if m.Blocker != 0 { + n += 1 + sovSchedule(uint64(m.Blocker)) + } return n } @@ -549,6 +600,25 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocker", wireType) + } + m.Blocker = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Blocker |= BlockerType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipSchedule(dAtA[iNdEx:]) diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go new file mode 100644 index 000000000..cda29cf72 --- /dev/null +++ b/x/cron/types/v1/schedule.pb.go @@ -0,0 +1,839 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: neutron/cron/schedule.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type Schedule struct { + // Name of schedule + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Period in blocks + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + // Msgs that will be executed every period amount of time + Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` + // Last execution's block height + LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` +} + +func (m *Schedule) Reset() { *m = Schedule{} } +func (m *Schedule) String() string { return proto.CompactTextString(m) } +func (*Schedule) ProtoMessage() {} +func (*Schedule) Descriptor() ([]byte, []int) { + return fileDescriptor_49ace1b59de613ef, []int{0} +} +func (m *Schedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Schedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Schedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Schedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_Schedule.Merge(m, src) +} +func (m *Schedule) XXX_Size() int { + return m.Size() +} +func (m *Schedule) XXX_DiscardUnknown() { + xxx_messageInfo_Schedule.DiscardUnknown(m) +} + +var xxx_messageInfo_Schedule proto.InternalMessageInfo + +func (m *Schedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Schedule) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + +func (m *Schedule) GetMsgs() []MsgExecuteContract { + if m != nil { + return m.Msgs + } + return nil +} + +func (m *Schedule) GetLastExecuteHeight() uint64 { + if m != nil { + return m.LastExecuteHeight + } + return 0 +} + +type MsgExecuteContract struct { + // Contract is the address of the smart contract + Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + // Msg is json encoded message to be passed to the contract + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } +func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } +func (*MsgExecuteContract) ProtoMessage() {} +func (*MsgExecuteContract) Descriptor() ([]byte, []int) { + return fileDescriptor_49ace1b59de613ef, []int{1} +} +func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecuteContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecuteContract.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgExecuteContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecuteContract.Merge(m, src) +} +func (m *MsgExecuteContract) XXX_Size() int { + return m.Size() +} +func (m *MsgExecuteContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecuteContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo + +func (m *MsgExecuteContract) GetContract() string { + if m != nil { + return m.Contract + } + return "" +} + +func (m *MsgExecuteContract) GetMsg() string { + if m != nil { + return m.Msg + } + return "" +} + +type ScheduleCount struct { + // Count is the number of current schedules + Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` +} + +func (m *ScheduleCount) Reset() { *m = ScheduleCount{} } +func (m *ScheduleCount) String() string { return proto.CompactTextString(m) } +func (*ScheduleCount) ProtoMessage() {} +func (*ScheduleCount) Descriptor() ([]byte, []int) { + return fileDescriptor_49ace1b59de613ef, []int{2} +} +func (m *ScheduleCount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ScheduleCount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ScheduleCount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ScheduleCount) XXX_Merge(src proto.Message) { + xxx_messageInfo_ScheduleCount.Merge(m, src) +} +func (m *ScheduleCount) XXX_Size() int { + return m.Size() +} +func (m *ScheduleCount) XXX_DiscardUnknown() { + xxx_messageInfo_ScheduleCount.DiscardUnknown(m) +} + +var xxx_messageInfo_ScheduleCount proto.InternalMessageInfo + +func (m *ScheduleCount) GetCount() int32 { + if m != nil { + return m.Count + } + return 0 +} + +func init() { + proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") + proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") + proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") +} + +func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } + +var fileDescriptor_49ace1b59de613ef = []byte{ + // 309 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xfb, 0x30, + 0x18, 0xc6, 0x9b, 0xff, 0xba, 0xb1, 0xe5, 0xaf, 0xa0, 0x71, 0x48, 0x99, 0x10, 0x4b, 0x41, 0xe8, + 0xc5, 0x14, 0xd4, 0x93, 0xc7, 0x0e, 0x61, 0x17, 0x2f, 0xf5, 0xe6, 0x65, 0x74, 0x59, 0x48, 0x0b, + 0x6b, 0x53, 0x9a, 0x54, 0xe6, 0xb7, 0xf0, 0x33, 0xf8, 0x69, 0x76, 0xdc, 0xd1, 0x93, 0x48, 0xfb, + 0x45, 0x24, 0x69, 0x26, 0x82, 0x97, 0xf0, 0x7b, 0x78, 0xde, 0x27, 0xef, 0xfb, 0x26, 0xf0, 0xa2, + 0x64, 0x8d, 0xaa, 0x45, 0x19, 0x51, 0x7d, 0x48, 0x9a, 0xb1, 0x75, 0xb3, 0x61, 0xa4, 0xaa, 0x85, + 0x12, 0xe8, 0xc8, 0x9a, 0x44, 0x9b, 0xb3, 0x29, 0x17, 0x5c, 0x18, 0x23, 0xd2, 0xd4, 0xd7, 0x04, + 0xef, 0x00, 0x8e, 0x9f, 0x6c, 0x0c, 0x21, 0xe8, 0x96, 0x69, 0xc1, 0x3c, 0xe0, 0x83, 0x70, 0x92, + 0x18, 0x46, 0xe7, 0x70, 0x54, 0xb1, 0x3a, 0x17, 0x6b, 0xef, 0x9f, 0x0f, 0x42, 0x37, 0xb1, 0x0a, + 0xdd, 0x43, 0xb7, 0x90, 0x5c, 0x7a, 0x03, 0x7f, 0x10, 0xfe, 0xbf, 0xf1, 0xc9, 0xef, 0x5e, 0xe4, + 0x51, 0xf2, 0x87, 0x2d, 0xa3, 0x8d, 0x62, 0x73, 0x51, 0xaa, 0x3a, 0xa5, 0x2a, 0x76, 0x77, 0x9f, + 0x97, 0x4e, 0x62, 0x32, 0x88, 0xc0, 0xb3, 0x4d, 0x2a, 0xd5, 0x92, 0xf5, 0x35, 0xcb, 0x8c, 0xe5, + 0x3c, 0x53, 0x9e, 0x6b, 0x1a, 0x9c, 0x6a, 0xcb, 0xa6, 0x17, 0xc6, 0x08, 0x62, 0x88, 0xfe, 0xde, + 0x88, 0x66, 0x70, 0x4c, 0x2d, 0xdb, 0x89, 0x7f, 0x34, 0x3a, 0x81, 0x83, 0x42, 0x72, 0x33, 0xf2, + 0x24, 0xd1, 0x18, 0x5c, 0xc1, 0xe3, 0xc3, 0x9e, 0x73, 0xd1, 0x94, 0x0a, 0x4d, 0xe1, 0x90, 0x6a, + 0x30, 0xd9, 0x61, 0xd2, 0x8b, 0x78, 0xb1, 0x6b, 0x31, 0xd8, 0xb7, 0x18, 0x7c, 0xb5, 0x18, 0xbc, + 0x75, 0xd8, 0xd9, 0x77, 0xd8, 0xf9, 0xe8, 0xb0, 0xf3, 0x4c, 0x78, 0xae, 0xb2, 0x66, 0x45, 0xa8, + 0x28, 0x22, 0xbb, 0xec, 0xb5, 0xa8, 0xf9, 0x81, 0xa3, 0x97, 0xbb, 0x68, 0xdb, 0x7f, 0x83, 0x7a, + 0xad, 0x98, 0x5c, 0x8d, 0xcc, 0x03, 0xdf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x19, 0x38, + 0x8d, 0xa3, 0x01, 0x00, 0x00, +} + +func (m *Schedule) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Schedule) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.LastExecuteHeight != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) + i-- + dAtA[i] = 0x20 + } + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSchedule(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.Period != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgExecuteContract) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgExecuteContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x12 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ScheduleCount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ScheduleCount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ScheduleCount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Count != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintSchedule(dAtA []byte, offset int, v uint64) int { + offset -= sovSchedule(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Schedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + if m.Period != 0 { + n += 1 + sovSchedule(uint64(m.Period)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovSchedule(uint64(l)) + } + } + if m.LastExecuteHeight != 0 { + n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) + } + return n +} + +func (m *MsgExecuteContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + return n +} + +func (m *ScheduleCount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Count != 0 { + n += 1 + sovSchedule(uint64(m.Count)) + } + return n +} + +func sovSchedule(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSchedule(x uint64) (n int) { + return sovSchedule(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Schedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Schedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Schedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, MsgExecuteContract{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastExecuteHeight", wireType) + } + m.LastExecuteHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastExecuteHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgExecuteContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecuteContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ScheduleCount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ScheduleCount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ScheduleCount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Count |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSchedule(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSchedule + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSchedule + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSchedule + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSchedule = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSchedule = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSchedule = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dex/types/limit_order_tranche_user.pb.go b/x/dex/types/limit_order_tranche_user.pb.go index b0e65087b..6e52c57d5 100644 --- a/x/dex/types/limit_order_tranche_user.pb.go +++ b/x/dex/types/limit_order_tranche_user.pb.go @@ -31,8 +31,9 @@ type LimitOrderTrancheUser struct { Address string `protobuf:"bytes,4,opt,name=address,proto3" json:"address,omitempty"` SharesOwned cosmossdk_io_math.Int `protobuf:"bytes,5,opt,name=shares_owned,json=sharesOwned,proto3,customtype=cosmossdk.io/math.Int" json:"shares_owned" yaml:"shares_owned"` SharesWithdrawn cosmossdk_io_math.Int `protobuf:"bytes,6,opt,name=shares_withdrawn,json=sharesWithdrawn,proto3,customtype=cosmossdk.io/math.Int" json:"shares_withdrawn" yaml:"shares_withdrawn"` - SharesCancelled cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=shares_cancelled,json=sharesCancelled,proto3,customtype=cosmossdk.io/math.Int" json:"shares_cancelled" yaml:"shares_cancelled"` - OrderType LimitOrderType `protobuf:"varint,8,opt,name=order_type,json=orderType,proto3,enum=neutron.dex.LimitOrderType" json:"order_type,omitempty"` + // TODO: remove this in next release. It is no longer used + SharesCancelled cosmossdk_io_math.Int `protobuf:"bytes,7,opt,name=shares_cancelled,json=sharesCancelled,proto3,customtype=cosmossdk.io/math.Int" json:"shares_cancelled" yaml:"shares_cancelled"` + OrderType LimitOrderType `protobuf:"varint,8,opt,name=order_type,json=orderType,proto3,enum=neutron.dex.LimitOrderType" json:"order_type,omitempty"` } func (m *LimitOrderTrancheUser) Reset() { *m = LimitOrderTrancheUser{} } From 3484f7e98f3704119d31098095f384c41f201449 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 15 Aug 2024 12:15:25 +0400 Subject: [PATCH 09/60] lint --- wasmbinding/message_plugin.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 61499d249..81e05eed0 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -4,10 +4,11 @@ import ( "context" "encoding/json" "fmt" - types1 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "strings" "time" + types1 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + "github.com/cosmos/gogoproto/proto" "golang.org/x/exp/maps" From 71e12c163c527c95d53147726f6e2c3ac2ae5751 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 15 Aug 2024 12:17:52 +0400 Subject: [PATCH 10/60] format proto --- proto/neutron/interchaintxs/v1/tx.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proto/neutron/interchaintxs/v1/tx.proto b/proto/neutron/interchaintxs/v1/tx.proto index 32148ce7b..a2bb14202 100644 --- a/proto/neutron/interchaintxs/v1/tx.proto +++ b/proto/neutron/interchaintxs/v1/tx.proto @@ -9,9 +9,9 @@ import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; import "google/api/http.proto"; import "google/protobuf/any.proto"; +import "ibc/core/channel/v1/channel.proto"; import "neutron/feerefunder/fee.proto"; import "neutron/interchaintxs/v1/params.proto"; -import "ibc/core/channel/v1/channel.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/interchaintxs/types"; @@ -37,7 +37,7 @@ message MsgRegisterInterchainAccount { (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; - ibc.core.channel.v1.Order ordering = 5; + ibc.core.channel.v1.Order ordering = 5; } // MsgRegisterInterchainAccountResponse is the response type for From de5192853149f5d57037d44c0f22524cabd53fa7 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 15 Aug 2024 15:25:11 +0400 Subject: [PATCH 11/60] copy third party proto for ibc from v8.2.1 --- .../proto/ibc/applications/fee/v1/ack.proto | 8 +- .../proto/ibc/applications/fee/v1/fee.proto | 27 +- .../ibc/applications/fee/v1/genesis.proto | 28 +- .../ibc/applications/fee/v1/metadata.proto | 6 +- .../proto/ibc/applications/fee/v1/query.proto | 44 +- .../proto/ibc/applications/fee/v1/tx.proto | 40 +- .../controller/v1/controller.proto | 4 +- .../controller/v1/query.proto | 3 +- .../controller/v1/tx.proto | 55 +- .../genesis/v1/genesis.proto | 40 +- .../interchain_accounts/host/v1/host.proto | 6 +- .../interchain_accounts/host/v1/tx.proto | 35 ++ .../interchain_accounts/v1/account.proto | 5 +- .../interchain_accounts/v1/metadata.proto | 6 +- .../ibc/applications/transfer/v1/authz.proto | 7 +- .../applications/transfer/v1/genesis.proto | 17 +- .../applications/transfer/v1/transfer.proto | 6 +- .../ibc/applications/transfer/v1/tx.proto | 44 +- .../proto/ibc/channel/v1/channel.proto | 187 +++++++ .../proto/ibc/channel/v1/genesis.proto | 30 ++ third_party/proto/ibc/channel/v1/query.proto | 459 +++++++++++++++++ third_party/proto/ibc/channel/v1/tx.proto | 469 ++++++++++++++++++ .../proto/ibc/channel/v1/upgrade.proto | 43 ++ third_party/proto/ibc/client/v1/client.proto | 113 +++++ third_party/proto/ibc/client/v1/genesis.proto | 44 ++ third_party/proto/ibc/client/v1/query.proto | 207 ++++++++ third_party/proto/ibc/client/v1/tx.proto | 175 +++++++ .../proto/ibc/commitment/v1/commitment.proto | 39 ++ .../proto/ibc/connection/v1/connection.proto | 114 +++++ .../proto/ibc/connection/v1/genesis.proto | 17 + .../proto/ibc/connection/v1/query.proto | 152 ++++++ third_party/proto/ibc/connection/v1/tx.proto | 146 ++++++ .../proto/ibc/core/channel/v1/channel.proto | 57 ++- .../proto/ibc/core/channel/v1/genesis.proto | 16 +- .../proto/ibc/core/channel/v1/query.proto | 85 +++- .../proto/ibc/core/channel/v1/tx.proto | 349 ++++++++++--- .../proto/ibc/core/channel/v1/upgrade.proto | 43 ++ .../proto/ibc/core/client/v1/client.proto | 86 ++-- .../proto/ibc/core/client/v1/genesis.proto | 24 +- third_party/proto/ibc/core/client/v1/tx.proto | 107 +++- .../ibc/core/commitment/v1/commitment.proto | 6 +- .../ibc/core/connection/v1/connection.proto | 18 +- .../ibc/core/connection/v1/genesis.proto | 5 +- .../proto/ibc/core/connection/v1/query.proto | 4 +- .../proto/ibc/core/connection/v1/tx.proto | 98 ++-- .../proto/ibc/core/types/v1/genesis.proto | 9 +- third_party/proto/ibc/fee/v1/ack.proto | 15 + third_party/proto/ibc/fee/v1/fee.proto | 61 +++ third_party/proto/ibc/fee/v1/genesis.proto | 60 +++ third_party/proto/ibc/fee/v1/metadata.proto | 14 + third_party/proto/ibc/fee/v1/query.proto | 218 ++++++++ third_party/proto/ibc/fee/v1/tx.proto | 122 +++++ .../controller/v1/controller.proto | 12 + .../controller/v1/query.proto | 42 ++ .../controller/v1/tx.proto | 82 +++ .../genesis/v1/genesis.proto | 47 ++ .../interchain_accounts/host/v1/host.proto | 14 + .../interchain_accounts/host/v1/query.proto | 25 + .../ibc/interchain_accounts/host/v1/tx.proto | 35 ++ .../ibc/interchain_accounts/v1/account.proto | 19 + .../ibc/interchain_accounts/v1/metadata.proto | 23 + .../ibc/interchain_accounts/v1/packet.proto | 31 ++ .../solomachine/v2/solomachine.proto | 34 +- .../solomachine/v3/solomachine.proto | 20 +- .../tendermint/v1/tendermint.proto | 52 +- .../ibc/lightclients/wasm/v1/genesis.proto | 20 + .../ibc/lightclients/wasm/v1/query.proto | 46 ++ .../proto/ibc/lightclients/wasm/v1/tx.proto | 66 +++ .../proto/ibc/lightclients/wasm/v1/wasm.proto | 43 ++ .../proto/ibc/localhost/v2/localhost.proto | 16 + .../ibc/solomachine/v2/solomachine.proto | 189 +++++++ .../ibc/solomachine/v3/solomachine.proto | 99 ++++ .../proto/ibc/tendermint/v1/tendermint.proto | 101 ++++ third_party/proto/ibc/transfer/v1/authz.proto | 34 ++ .../proto/ibc/transfer/v1/genesis.proto | 20 + third_party/proto/ibc/transfer/v1/query.proto | 121 +++++ .../proto/ibc/transfer/v1/transfer.proto | 28 ++ third_party/proto/ibc/transfer/v1/tx.proto | 79 +++ .../proto/ibc/transfer/v2/packet.proto | 21 + third_party/proto/ibc/types/v1/genesis.proto | 20 + third_party/proto/ibc/wasm/v1/genesis.proto | 20 + third_party/proto/ibc/wasm/v1/query.proto | 46 ++ third_party/proto/ibc/wasm/v1/tx.proto | 66 +++ third_party/proto/ibc/wasm/v1/wasm.proto | 43 ++ x/interchaintxs/keeper/msg_server.go | 2 +- x/interchaintxs/keeper/msg_server_test.go | 3 +- x/interchaintxs/types/tx.pb.go | 100 ++-- 87 files changed, 5108 insertions(+), 484 deletions(-) create mode 100644 third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto create mode 100644 third_party/proto/ibc/channel/v1/channel.proto create mode 100644 third_party/proto/ibc/channel/v1/genesis.proto create mode 100644 third_party/proto/ibc/channel/v1/query.proto create mode 100644 third_party/proto/ibc/channel/v1/tx.proto create mode 100644 third_party/proto/ibc/channel/v1/upgrade.proto create mode 100644 third_party/proto/ibc/client/v1/client.proto create mode 100644 third_party/proto/ibc/client/v1/genesis.proto create mode 100644 third_party/proto/ibc/client/v1/query.proto create mode 100644 third_party/proto/ibc/client/v1/tx.proto create mode 100644 third_party/proto/ibc/commitment/v1/commitment.proto create mode 100644 third_party/proto/ibc/connection/v1/connection.proto create mode 100644 third_party/proto/ibc/connection/v1/genesis.proto create mode 100644 third_party/proto/ibc/connection/v1/query.proto create mode 100644 third_party/proto/ibc/connection/v1/tx.proto create mode 100644 third_party/proto/ibc/core/channel/v1/upgrade.proto create mode 100644 third_party/proto/ibc/fee/v1/ack.proto create mode 100644 third_party/proto/ibc/fee/v1/fee.proto create mode 100644 third_party/proto/ibc/fee/v1/genesis.proto create mode 100644 third_party/proto/ibc/fee/v1/metadata.proto create mode 100644 third_party/proto/ibc/fee/v1/query.proto create mode 100644 third_party/proto/ibc/fee/v1/tx.proto create mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto create mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/query.proto create mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto create mode 100644 third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto create mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/host.proto create mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/query.proto create mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/tx.proto create mode 100644 third_party/proto/ibc/interchain_accounts/v1/account.proto create mode 100644 third_party/proto/ibc/interchain_accounts/v1/metadata.proto create mode 100644 third_party/proto/ibc/interchain_accounts/v1/packet.proto create mode 100644 third_party/proto/ibc/lightclients/wasm/v1/genesis.proto create mode 100644 third_party/proto/ibc/lightclients/wasm/v1/query.proto create mode 100644 third_party/proto/ibc/lightclients/wasm/v1/tx.proto create mode 100644 third_party/proto/ibc/lightclients/wasm/v1/wasm.proto create mode 100644 third_party/proto/ibc/localhost/v2/localhost.proto create mode 100644 third_party/proto/ibc/solomachine/v2/solomachine.proto create mode 100644 third_party/proto/ibc/solomachine/v3/solomachine.proto create mode 100644 third_party/proto/ibc/tendermint/v1/tendermint.proto create mode 100644 third_party/proto/ibc/transfer/v1/authz.proto create mode 100644 third_party/proto/ibc/transfer/v1/genesis.proto create mode 100644 third_party/proto/ibc/transfer/v1/query.proto create mode 100644 third_party/proto/ibc/transfer/v1/transfer.proto create mode 100644 third_party/proto/ibc/transfer/v1/tx.proto create mode 100644 third_party/proto/ibc/transfer/v2/packet.proto create mode 100644 third_party/proto/ibc/types/v1/genesis.proto create mode 100644 third_party/proto/ibc/wasm/v1/genesis.proto create mode 100644 third_party/proto/ibc/wasm/v1/query.proto create mode 100644 third_party/proto/ibc/wasm/v1/tx.proto create mode 100644 third_party/proto/ibc/wasm/v1/wasm.proto diff --git a/third_party/proto/ibc/applications/fee/v1/ack.proto b/third_party/proto/ibc/applications/fee/v1/ack.proto index cc12f3b58..2f3746d2c 100644 --- a/third_party/proto/ibc/applications/fee/v1/ack.proto +++ b/third_party/proto/ibc/applications/fee/v1/ack.proto @@ -4,14 +4,12 @@ package ibc.applications.fee.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; -import "gogoproto/gogo.proto"; - // IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware message IncentivizedAcknowledgement { // the underlying app acknowledgement bytes - bytes app_acknowledgement = 1 [(gogoproto.moretags) = "yaml:\"app_acknowledgement\""]; + bytes app_acknowledgement = 1; // the relayer address which submits the recv packet message - string forward_relayer_address = 2 [(gogoproto.moretags) = "yaml:\"forward_relayer_address\""]; + string forward_relayer_address = 2; // success flag of the base application callback - bool underlying_app_success = 3 [(gogoproto.moretags) = "yaml:\"underlying_app_successl\""]; + bool underlying_app_success = 3; } diff --git a/third_party/proto/ibc/applications/fee/v1/fee.proto b/third_party/proto/ibc/applications/fee/v1/fee.proto index 4ef626d41..867e88455 100644 --- a/third_party/proto/ibc/applications/fee/v1/fee.proto +++ b/third_party/proto/ibc/applications/fee/v1/fee.proto @@ -4,38 +4,44 @@ package ibc.applications.fee.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; +import "amino/amino.proto"; import "cosmos/base/v1beta1/coin.proto"; import "gogoproto/gogo.proto"; import "ibc/core/channel/v1/channel.proto"; +import "cosmos/msg/v1/msg.proto"; // Fee defines the ICS29 receive, acknowledgement and timeout fees message Fee { // the packet receive fee repeated cosmos.base.v1beta1.Coin recv_fee = 1 [ - (gogoproto.moretags) = "yaml:\"recv_fee\"", (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" ]; + // the packet acknowledgement fee repeated cosmos.base.v1beta1.Coin ack_fee = 2 [ - (gogoproto.moretags) = "yaml:\"ack_fee\"", (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" ]; + // the packet timeout fee repeated cosmos.base.v1beta1.Coin timeout_fee = 3 [ - (gogoproto.moretags) = "yaml:\"timeout_fee\"", (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" ]; } // PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers message PacketFee { + option (cosmos.msg.v1.signer) = "refund_address"; + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet Fee fee = 1 [(gogoproto.nullable) = false]; // the refund address for unspent fees - string refund_address = 2 [(gogoproto.moretags) = "yaml:\"refund_address\""]; + string refund_address = 2; // optional list of relayers permitted to receive fees repeated string relayers = 3; } @@ -43,14 +49,13 @@ message PacketFee { // PacketFees contains a list of type PacketFee message PacketFees { // list of packet fees - repeated PacketFee packet_fees = 1 [(gogoproto.moretags) = "yaml:\"packet_fees\"", (gogoproto.nullable) = false]; + repeated PacketFee packet_fees = 1 [(gogoproto.nullable) = false]; } // IdentifiedPacketFees contains a list of type PacketFee and associated PacketId message IdentifiedPacketFees { // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"packet_id\""]; + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; // list of packet fees - repeated PacketFee packet_fees = 2 [(gogoproto.moretags) = "yaml:\"packet_fees\"", (gogoproto.nullable) = false]; + repeated PacketFee packet_fees = 2 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/applications/fee/v1/genesis.proto b/third_party/proto/ibc/applications/fee/v1/genesis.proto index 245525ca1..e48ceb535 100644 --- a/third_party/proto/ibc/applications/fee/v1/genesis.proto +++ b/third_party/proto/ibc/applications/fee/v1/genesis.proto @@ -11,34 +11,29 @@ import "ibc/core/channel/v1/channel.proto"; // GenesisState defines the ICS29 fee middleware genesis state message GenesisState { // list of identified packet fees - repeated IdentifiedPacketFees identified_fees = 1 - [(gogoproto.moretags) = "yaml:\"identified_fees\"", (gogoproto.nullable) = false]; + repeated IdentifiedPacketFees identified_fees = 1 [(gogoproto.nullable) = false]; // list of fee enabled channels - repeated FeeEnabledChannel fee_enabled_channels = 2 - [(gogoproto.moretags) = "yaml:\"fee_enabled_channels\"", (gogoproto.nullable) = false]; + repeated FeeEnabledChannel fee_enabled_channels = 2 [(gogoproto.nullable) = false]; // list of registered payees - repeated RegisteredPayee registered_payees = 3 - [(gogoproto.moretags) = "yaml:\"registered_payees\"", (gogoproto.nullable) = false]; + repeated RegisteredPayee registered_payees = 3 [(gogoproto.nullable) = false]; // list of registered counterparty payees - repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 - [(gogoproto.moretags) = "yaml:\"registered_counterparty_payees\"", (gogoproto.nullable) = false]; + repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 [(gogoproto.nullable) = false]; // list of forward relayer addresses - repeated ForwardRelayerAddress forward_relayers = 5 - [(gogoproto.moretags) = "yaml:\"forward_relayers\"", (gogoproto.nullable) = false]; + repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.nullable) = false]; } // FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel message FeeEnabledChannel { // unique port identifier - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // unique channel identifier - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; } // RegisteredPayee contains the relayer address and payee address for a specific channel message RegisteredPayee { // unique channel identifier - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 1; // the relayer address string relayer = 2; // the payee address @@ -49,11 +44,11 @@ message RegisteredPayee { // for recv fee distribution) message RegisteredCounterpartyPayee { // unique channel identifier - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 1; // the relayer address string relayer = 2; // the counterparty payee address - string counterparty_payee = 3 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; + string counterparty_payee = 3; } // ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements @@ -61,6 +56,5 @@ message ForwardRelayerAddress { // the forward relayer address string address = 1; // unique packet identifer comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"packet_id\""]; + ibc.core.channel.v1.PacketId packet_id = 2 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/applications/fee/v1/metadata.proto b/third_party/proto/ibc/applications/fee/v1/metadata.proto index 8d9879f35..1e82e7c25 100644 --- a/third_party/proto/ibc/applications/fee/v1/metadata.proto +++ b/third_party/proto/ibc/applications/fee/v1/metadata.proto @@ -4,13 +4,11 @@ package ibc.applications.fee.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; -import "gogoproto/gogo.proto"; - // Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring // See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning message Metadata { // fee_version defines the ICS29 fee version - string fee_version = 1 [(gogoproto.moretags) = "yaml:\"fee_version\""]; + string fee_version = 1; // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring - string app_version = 2 [(gogoproto.moretags) = "yaml:\"app_version\""]; + string app_version = 2; } diff --git a/third_party/proto/ibc/applications/fee/v1/query.proto b/third_party/proto/ibc/applications/fee/v1/query.proto index 7d54bcd01..726370ee0 100644 --- a/third_party/proto/ibc/applications/fee/v1/query.proto +++ b/third_party/proto/ibc/applications/fee/v1/query.proto @@ -83,6 +83,8 @@ message QueryIncentivizedPacketsRequest { message QueryIncentivizedPacketsResponse { // list of identified fees for incentivized packets repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc @@ -114,6 +116,8 @@ message QueryIncentivizedPacketsForChannelRequest { message QueryIncentivizedPacketsForChannelResponse { // Map of all incentivized_packets repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc @@ -125,11 +129,8 @@ message QueryTotalRecvFeesRequest { // QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc message QueryTotalRecvFeesResponse { // the total packet receive fees - repeated cosmos.base.v1beta1.Coin recv_fees = 1 [ - (gogoproto.moretags) = "yaml:\"recv_fees\"", - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ]; + repeated cosmos.base.v1beta1.Coin recv_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } // QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc @@ -141,11 +142,8 @@ message QueryTotalAckFeesRequest { // QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc message QueryTotalAckFeesResponse { // the total packet acknowledgement fees - repeated cosmos.base.v1beta1.Coin ack_fees = 1 [ - (gogoproto.moretags) = "yaml:\"ack_fees\"", - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ]; + repeated cosmos.base.v1beta1.Coin ack_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } // QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc @@ -157,17 +155,14 @@ message QueryTotalTimeoutFeesRequest { // QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc message QueryTotalTimeoutFeesResponse { // the total packet timeout fees - repeated cosmos.base.v1beta1.Coin timeout_fees = 1 [ - (gogoproto.moretags) = "yaml:\"timeout_fees\"", - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" - ]; + repeated cosmos.base.v1beta1.Coin timeout_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } // QueryPayeeRequest defines the request type for the Payee rpc message QueryPayeeRequest { // unique channel identifier - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 1; // the relayer address to which the distribution address is registered string relayer = 2; } @@ -175,13 +170,13 @@ message QueryPayeeRequest { // QueryPayeeResponse defines the response type for the Payee rpc message QueryPayeeResponse { // the payee address to which packet fees are paid out - string payee_address = 1 [(gogoproto.moretags) = "yaml:\"payee_address\""]; + string payee_address = 1; } // QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc message QueryCounterpartyPayeeRequest { // unique channel identifier - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 1; // the relayer address to which the counterparty is registered string relayer = 2; } @@ -189,7 +184,7 @@ message QueryCounterpartyPayeeRequest { // QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc message QueryCounterpartyPayeeResponse { // the counterparty payee address used to compensate forward relaying - string counterparty_payee = 1 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; + string counterparty_payee = 1; } // QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc @@ -203,20 +198,21 @@ message QueryFeeEnabledChannelsRequest { // QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc message QueryFeeEnabledChannelsResponse { // list of fee enabled channels - repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 - [(gogoproto.moretags) = "yaml:\"fee_enabled_channels\"", (gogoproto.nullable) = false]; + repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; } // QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc message QueryFeeEnabledChannelRequest { // unique port identifier - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // unique channel identifier - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; } // QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc message QueryFeeEnabledChannelResponse { // boolean flag representing the fee enabled channel status - bool fee_enabled = 1 [(gogoproto.moretags) = "yaml:\"fee_enabled\""]; + bool fee_enabled = 1; } diff --git a/third_party/proto/ibc/applications/fee/v1/tx.proto b/third_party/proto/ibc/applications/fee/v1/tx.proto index 63e591617..e59dddfd1 100644 --- a/third_party/proto/ibc/applications/fee/v1/tx.proto +++ b/third_party/proto/ibc/applications/fee/v1/tx.proto @@ -4,12 +4,16 @@ package ibc.applications.fee.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; +import "amino/amino.proto"; import "gogoproto/gogo.proto"; import "ibc/applications/fee/v1/fee.proto"; import "ibc/core/channel/v1/channel.proto"; +import "cosmos/msg/v1/msg.proto"; // Msg defines the ICS29 Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // RegisterPayee defines a rpc handler method for MsgRegisterPayee // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on @@ -39,13 +43,15 @@ service Msg { // MsgRegisterPayee defines the request type for the RegisterPayee rpc message MsgRegisterPayee { - option (gogoproto.equal) = false; + option (amino.name) = "cosmos-sdk/MsgRegisterPayee"; + option (cosmos.msg.v1.signer) = "relayer"; + option (gogoproto.goproto_getters) = false; // unique port identifier - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // unique channel identifier - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; // the relayer address string relayer = 3; // the payee address @@ -57,17 +63,19 @@ message MsgRegisterPayeeResponse {} // MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc message MsgRegisterCounterpartyPayee { - option (gogoproto.equal) = false; + option (amino.name) = "cosmos-sdk/MsgRegisterCounterpartyPayee"; + option (cosmos.msg.v1.signer) = "relayer"; + option (gogoproto.goproto_getters) = false; // unique port identifier - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // unique channel identifier - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; // the relayer address string relayer = 3; // the counterparty payee address - string counterparty_payee = 4 [(gogoproto.moretags) = "yaml:\"counterparty_payee\""]; + string counterparty_payee = 4; } // MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc @@ -77,15 +85,17 @@ message MsgRegisterCounterpartyPayeeResponse {} // This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be // paid for message MsgPayPacketFee { - option (gogoproto.equal) = false; + option (amino.name) = "cosmos-sdk/MsgPayPacketFee"; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false]; + ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; // the source port unique identifier - string source_port_id = 2 [(gogoproto.moretags) = "yaml:\"source_port_id\""]; + string source_port_id = 2; // the source channel unique identifer - string source_channel_id = 3 [(gogoproto.moretags) = "yaml:\"source_channel_id\""]; + string source_channel_id = 3; // account address to refund fee if necessary string signer = 4; // optional list of relayers permitted to the receive packet fees @@ -98,14 +108,14 @@ message MsgPayPacketFeeResponse {} // MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc // This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) message MsgPayPacketFeeAsync { - option (gogoproto.equal) = false; + option (amino.name) = "cosmos-sdk/MsgPayPacketFeeAsync"; + option (cosmos.msg.v1.signer) = "packet_fee"; option (gogoproto.goproto_getters) = false; // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 - [(gogoproto.moretags) = "yaml:\"packet_id\"", (gogoproto.nullable) = false]; + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; // the packet fee associated with a particular IBC packet - PacketFee packet_fee = 2 [(gogoproto.moretags) = "yaml:\"packet_fee\"", (gogoproto.nullable) = false]; + PacketFee packet_fee = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; } // MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto index 0974b9d9b..2e6bbe1a1 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto @@ -4,11 +4,9 @@ package ibc.applications.interchain_accounts.controller.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; -import "gogoproto/gogo.proto"; - // Params defines the set of on-chain interchain accounts parameters. // The following parameters may be used to disable the controller submodule. message Params { // controller_enabled enables or disables the controller submodule. - bool controller_enabled = 1 [(gogoproto.moretags) = "yaml:\"controller_enabled\""]; + bool controller_enabled = 1; } diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto index 3779ed387..31885fcb2 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto @@ -5,7 +5,6 @@ package ibc.applications.interchain_accounts.controller.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; // Query provides defines the gRPC querier service. @@ -25,7 +24,7 @@ service Query { // QueryInterchainAccountRequest is the request type for the Query/InterchainAccount RPC method. message QueryInterchainAccountRequest { string owner = 1; - string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; + string connection_id = 2; } // QueryInterchainAccountResponse the response type for the Query/InterchainAccount RPC method. diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto index 11fb3cfdc..ec5c2e62e 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto @@ -6,46 +6,77 @@ option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-acco import "gogoproto/gogo.proto"; import "ibc/applications/interchain_accounts/v1/packet.proto"; +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "cosmos/msg/v1/msg.proto"; +import "ibc/core/channel/v1/channel.proto"; // Msg defines the 27-interchain-accounts/controller Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // RegisterInterchainAccount defines a rpc handler for MsgRegisterInterchainAccount. rpc RegisterInterchainAccount(MsgRegisterInterchainAccount) returns (MsgRegisterInterchainAccountResponse); // SendTx defines a rpc handler for MsgSendTx. rpc SendTx(MsgSendTx) returns (MsgSendTxResponse); + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } // MsgRegisterInterchainAccount defines the payload for Msg/RegisterAccount message MsgRegisterInterchainAccount { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "owner"; + option (gogoproto.goproto_getters) = false; - string owner = 1; - string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - string version = 3; + string owner = 1; + string connection_id = 2; + string version = 3; + ibc.core.channel.v1.Order ordering = 4; } // MsgRegisterInterchainAccountResponse defines the response for Msg/RegisterAccount message MsgRegisterInterchainAccountResponse { - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""]; + option (gogoproto.goproto_getters) = false; + + string channel_id = 1; + string port_id = 2; } // MsgSendTx defines the payload for Msg/SendTx message MsgSendTx { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "owner"; + option (gogoproto.goproto_getters) = false; - string owner = 1; - string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - ibc.applications.interchain_accounts.v1.InterchainAccountPacketData packet_data = 3 - [(gogoproto.moretags) = "yaml:\"packet_data\"", (gogoproto.nullable) = false]; + string owner = 1; + string connection_id = 2; + ibc.applications.interchain_accounts.v1.InterchainAccountPacketData packet_data = 3 [(gogoproto.nullable) = false]; // Relative timeout timestamp provided will be added to the current block time during transaction execution. // The timeout timestamp must be non-zero. - uint64 relative_timeout = 4 [(gogoproto.moretags) = "yaml:\"relative_timeout\""]; + uint64 relative_timeout = 4; } // MsgSendTxResponse defines the response for MsgSendTx message MsgSendTxResponse { + option (gogoproto.goproto_getters) = false; + uint64 sequence = 1; } + +// MsgUpdateParams defines the payload for Msg/UpdateParams +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the 27-interchain-accounts/controller parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response for Msg/UpdateParams +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto b/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto index f0fd73ede..4393e5b0b 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto @@ -10,44 +10,38 @@ import "ibc/applications/interchain_accounts/host/v1/host.proto"; // GenesisState defines the interchain accounts genesis state message GenesisState { - ControllerGenesisState controller_genesis_state = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"controller_genesis_state\""]; - HostGenesisState host_genesis_state = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"host_genesis_state\""]; + ControllerGenesisState controller_genesis_state = 1 [(gogoproto.nullable) = false]; + HostGenesisState host_genesis_state = 2 [(gogoproto.nullable) = false]; } // ControllerGenesisState defines the interchain accounts controller genesis state message ControllerGenesisState { - repeated ActiveChannel active_channels = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; - repeated RegisteredInterchainAccount interchain_accounts = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - repeated string ports = 3; - ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; + repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; + repeated string ports = 3; + ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; } // HostGenesisState defines the interchain accounts host genesis state message HostGenesisState { - repeated ActiveChannel active_channels = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"active_channels\""]; - repeated RegisteredInterchainAccount interchain_accounts = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"interchain_accounts\""]; - string port = 3; - ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; + repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; + string port = 3; + ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; } // ActiveChannel contains a connection ID, port ID and associated active channel ID, as well as a boolean flag to // indicate if the channel is middleware enabled message ActiveChannel { - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 3 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - bool is_middleware_enabled = 4 [(gogoproto.moretags) = "yaml:\"is_middleware_enabled\""]; + string connection_id = 1; + string port_id = 2; + string channel_id = 3; + bool is_middleware_enabled = 4; } // RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address message RegisteredInterchainAccount { - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - string port_id = 2 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string account_address = 3 [(gogoproto.moretags) = "yaml:\"account_address\""]; + string connection_id = 1; + string port_id = 2; + string account_address = 3; } \ No newline at end of file diff --git a/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto index 2247e2fe0..f03685711 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto @@ -4,13 +4,11 @@ package ibc.applications.interchain_accounts.host.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; -import "gogoproto/gogo.proto"; - // Params defines the set of on-chain interchain accounts parameters. // The following parameters may be used to disable the host submodule. message Params { // host_enabled enables or disables the host submodule. - bool host_enabled = 1 [(gogoproto.moretags) = "yaml:\"host_enabled\""]; + bool host_enabled = 1; // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. - repeated string allow_messages = 2 [(gogoproto.moretags) = "yaml:\"allow_messages\""]; + repeated string allow_messages = 2; } diff --git a/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto b/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto new file mode 100644 index 000000000..5a8073bc9 --- /dev/null +++ b/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; + +// Msg defines the 27-interchain-accounts/host Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgUpdateParams defines the payload for Msg/UpdateParams +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the 27-interchain-accounts/host parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response for Msg/UpdateParams +message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto b/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto index 85d4e5828..4a6947c1c 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto @@ -14,7 +14,6 @@ message InterchainAccount { option (gogoproto.goproto_stringer) = false; option (cosmos_proto.implements_interface) = "ibc.applications.interchain_accounts.v1.InterchainAccountI"; - cosmos.auth.v1beta1.BaseAccount base_account = 1 - [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"base_account\""]; - string account_owner = 2 [(gogoproto.moretags) = "yaml:\"account_owner\""]; + cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; + string account_owner = 2; } diff --git a/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto b/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto index 5984ba4d6..df72b41eb 100644 --- a/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto +++ b/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto @@ -4,17 +4,15 @@ package ibc.applications.interchain_accounts.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; -import "gogoproto/gogo.proto"; - // Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring // See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning message Metadata { // version defines the ICS27 protocol version string version = 1; // controller_connection_id is the connection identifier associated with the controller chain - string controller_connection_id = 2 [(gogoproto.moretags) = "yaml:\"controller_connection_id\""]; + string controller_connection_id = 2; // host_connection_id is the connection identifier associated with the host chain - string host_connection_id = 3 [(gogoproto.moretags) = "yaml:\"host_connection_id\""]; + string host_connection_id = 3; // address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step // NOTE: the address field is empty on the OnChanOpenInit handshake step string address = 4; diff --git a/third_party/proto/ibc/applications/transfer/v1/authz.proto b/third_party/proto/ibc/applications/transfer/v1/authz.proto index df1ee24ed..e7561b070 100644 --- a/third_party/proto/ibc/applications/transfer/v1/authz.proto +++ b/third_party/proto/ibc/applications/transfer/v1/authz.proto @@ -11,14 +11,17 @@ import "cosmos/base/v1beta1/coin.proto"; // Allocation defines the spend limit for a particular port and channel message Allocation { // the port on which the packet will be sent - string source_port = 1 [(gogoproto.moretags) = "yaml:\"source_port\""]; + string source_port = 1; // the channel by which the packet will be sent - string source_channel = 2 [(gogoproto.moretags) = "yaml:\"source_channel\""]; + string source_channel = 2; // spend limitation on the channel repeated cosmos.base.v1beta1.Coin spend_limit = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; // allow list of receivers, an empty allow list permits any receiver address repeated string allow_list = 4; + // allow list of packet data keys, an empty list prohibits all packet data keys; + // a list only with "*" permits any packet data key + repeated string allowed_packet_data = 5; } // TransferAuthorization allows the grantee to spend up to spend_limit coins from diff --git a/third_party/proto/ibc/applications/transfer/v1/genesis.proto b/third_party/proto/ibc/applications/transfer/v1/genesis.proto index 578c2242e..f7d707f6c 100644 --- a/third_party/proto/ibc/applications/transfer/v1/genesis.proto +++ b/third_party/proto/ibc/applications/transfer/v1/genesis.proto @@ -10,18 +10,11 @@ import "gogoproto/gogo.proto"; // GenesisState defines the ibc-transfer genesis state message GenesisState { - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - repeated DenomTrace denom_traces = 2 [ - (gogoproto.castrepeated) = "Traces", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"denom_traces\"" - ]; - Params params = 3 [(gogoproto.nullable) = false]; + string port_id = 1; + repeated DenomTrace denom_traces = 2 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false]; + Params params = 3 [(gogoproto.nullable) = false]; // total_escrowed contains the total amount of tokens escrowed // by the transfer module - repeated cosmos.base.v1beta1.Coin total_escrowed = 4 [ - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (gogoproto.nullable) = false, - (gogoproto.moretags) = "yaml:\"total_escrowed\"" - ]; + repeated cosmos.base.v1beta1.Coin total_escrowed = 4 + [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/applications/transfer/v1/transfer.proto b/third_party/proto/ibc/applications/transfer/v1/transfer.proto index 0c13a48ce..7f7723762 100644 --- a/third_party/proto/ibc/applications/transfer/v1/transfer.proto +++ b/third_party/proto/ibc/applications/transfer/v1/transfer.proto @@ -4,8 +4,6 @@ package ibc.applications.transfer.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; -import "gogoproto/gogo.proto"; - // DenomTrace contains the base denomination for ICS20 fungible tokens and the // source tracing information path. message DenomTrace { @@ -23,8 +21,8 @@ message DenomTrace { message Params { // send_enabled enables or disables all cross-chain token transfers from this // chain. - bool send_enabled = 1 [(gogoproto.moretags) = "yaml:\"send_enabled\""]; + bool send_enabled = 1; // receive_enabled enables or disables all cross-chain token transfers to this // chain. - bool receive_enabled = 2 [(gogoproto.moretags) = "yaml:\"receive_enabled\""]; + bool receive_enabled = 2; } diff --git a/third_party/proto/ibc/applications/transfer/v1/tx.proto b/third_party/proto/ibc/applications/transfer/v1/tx.proto index 02466eab7..42c70d3be 100644 --- a/third_party/proto/ibc/applications/transfer/v1/tx.proto +++ b/third_party/proto/ibc/applications/transfer/v1/tx.proto @@ -4,46 +4,76 @@ package ibc.applications.transfer.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; +import "amino/amino.proto"; import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; import "cosmos/base/v1beta1/coin.proto"; import "ibc/core/client/v1/client.proto"; +import "ibc/applications/transfer/v1/transfer.proto"; // Msg defines the ibc/transfer Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // Transfer defines a rpc handler method for MsgTransfer. rpc Transfer(MsgTransfer) returns (MsgTransferResponse); + + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } // MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between // ICS20 enabled chains. See ICS Spec here: // https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures message MsgTransfer { - option (gogoproto.equal) = false; + option (amino.name) = "cosmos-sdk/MsgTransfer"; + option (cosmos.msg.v1.signer) = "sender"; + option (gogoproto.goproto_getters) = false; // the port on which the packet will be sent - string source_port = 1 [(gogoproto.moretags) = "yaml:\"source_port\""]; + string source_port = 1; // the channel by which the packet will be sent - string source_channel = 2 [(gogoproto.moretags) = "yaml:\"source_channel\""]; + string source_channel = 2; // the tokens to be transferred - cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false]; + cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; // the sender address string sender = 4; // the recipient address on the destination chain string receiver = 5; // Timeout height relative to the current block height. // The timeout is disabled when set to 0. - ibc.core.client.v1.Height timeout_height = 6 - [(gogoproto.moretags) = "yaml:\"timeout_height\"", (gogoproto.nullable) = false]; + ibc.core.client.v1.Height timeout_height = 6 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; // Timeout timestamp in absolute nanoseconds since unix epoch. // The timeout is disabled when set to 0. - uint64 timeout_timestamp = 7 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; + uint64 timeout_timestamp = 7; // optional memo string memo = 8; } // MsgTransferResponse defines the Msg/Transfer response type. message MsgTransferResponse { + option (gogoproto.goproto_getters) = false; + // sequence number of the transfer packet sent uint64 sequence = 1; } + +// MsgUpdateParams is the Msg/UpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the transfer parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/channel/v1/channel.proto b/third_party/proto/ibc/channel/v1/channel.proto new file mode 100644 index 000000000..05a18fefb --- /dev/null +++ b/third_party/proto/ibc/channel/v1/channel.proto @@ -0,0 +1,187 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/client/v1/client.proto"; + +// Channel defines pipeline for exactly-once packet delivery between specific +// modules on separate blockchains, which has at least one end capable of +// sending packets and one end capable of receiving packets. +message Channel { + option (gogoproto.goproto_getters) = false; + + // current state of the channel end + State state = 1; + // whether the channel is ordered or unordered + Order ordering = 2; + // counterparty channel end + Counterparty counterparty = 3 [(gogoproto.nullable) = false]; + // list of connection identifiers, in order, along which packets sent on + // this channel will travel + repeated string connection_hops = 4; + // opaque channel version, which is agreed upon during the handshake + string version = 5; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 6; +} + +// IdentifiedChannel defines a channel with additional port and channel +// identifier fields. +message IdentifiedChannel { + option (gogoproto.goproto_getters) = false; + + // current state of the channel end + State state = 1; + // whether the channel is ordered or unordered + Order ordering = 2; + // counterparty channel end + Counterparty counterparty = 3 [(gogoproto.nullable) = false]; + // list of connection identifiers, in order, along which packets sent on + // this channel will travel + repeated string connection_hops = 4; + // opaque channel version, which is agreed upon during the handshake + string version = 5; + // port identifier + string port_id = 6; + // channel identifier + string channel_id = 7; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 8; +} + +// State defines if a channel is in one of the following states: +// CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. +enum State { + option (gogoproto.goproto_enum_prefix) = false; + + // Default State + STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; + // A channel has just started the opening handshake. + STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; + // A channel has acknowledged the handshake step on the counterparty chain. + STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; + // A channel has completed the handshake. Open channels are + // ready to send and receive packets. + STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; + // A channel has been closed and can no longer be used to send or receive + // packets. + STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"]; + // A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. + STATE_FLUSHING = 5 [(gogoproto.enumvalue_customname) = "FLUSHING"]; + // A channel has just completed flushing any in-flight packets. + STATE_FLUSHCOMPLETE = 6 [(gogoproto.enumvalue_customname) = "FLUSHCOMPLETE"]; +} + +// Order defines if a channel is ORDERED or UNORDERED +enum Order { + option (gogoproto.goproto_enum_prefix) = false; + + // zero-value for channel ordering + ORDER_NONE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "NONE"]; + // packets can be delivered in any order, which may differ from the order in + // which they were sent. + ORDER_UNORDERED = 1 [(gogoproto.enumvalue_customname) = "UNORDERED"]; + // packets are delivered exactly in the order which they were sent + ORDER_ORDERED = 2 [(gogoproto.enumvalue_customname) = "ORDERED"]; +} + +// Counterparty defines a channel end counterparty +message Counterparty { + option (gogoproto.goproto_getters) = false; + + // port on the counterparty chain which owns the other end of the channel. + string port_id = 1; + // channel end on the counterparty chain + string channel_id = 2; +} + +// Packet defines a type that carries data across different chains through IBC +message Packet { + option (gogoproto.goproto_getters) = false; + + // number corresponds to the order of sends and receives, where a Packet + // with an earlier sequence number must be sent and received before a Packet + // with a later sequence number. + uint64 sequence = 1; + // identifies the port on the sending chain. + string source_port = 2; + // identifies the channel end on the sending chain. + string source_channel = 3; + // identifies the port on the receiving chain. + string destination_port = 4; + // identifies the channel end on the receiving chain. + string destination_channel = 5; + // actual opaque bytes transferred directly to the application module + bytes data = 6; + // block height after which the packet times out + ibc.core.client.v1.Height timeout_height = 7 [(gogoproto.nullable) = false]; + // block timestamp (in nanoseconds) after which the packet times out + uint64 timeout_timestamp = 8; +} + +// PacketState defines the generic type necessary to retrieve and store +// packet commitments, acknowledgements, and receipts. +// Caller is responsible for knowing the context necessary to interpret this +// state as a commitment, acknowledgement, or a receipt. +message PacketState { + option (gogoproto.goproto_getters) = false; + + // channel port identifier. + string port_id = 1; + // channel unique identifier. + string channel_id = 2; + // packet sequence. + uint64 sequence = 3; + // embedded data that represents packet state. + bytes data = 4; +} + +// PacketId is an identifer for a unique Packet +// Source chains refer to packets by source port/channel +// Destination chains refer to packets by destination port/channel +message PacketId { + option (gogoproto.goproto_getters) = false; + + // channel port identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // packet sequence + uint64 sequence = 3; +} + +// Acknowledgement is the recommended acknowledgement format to be used by +// app-specific protocols. +// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental +// conflicts with other protobuf message formats used for acknowledgements. +// The first byte of any message with this format will be the non-ASCII values +// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: +// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope +message Acknowledgement { + // response contains either a result or an error and must be non-empty + oneof response { + bytes result = 21; + string error = 22; + } +} + +// Timeout defines an execution deadline structure for 04-channel handlers. +// This includes packet lifecycle handlers as well as the upgrade handshake handlers. +// A valid Timeout contains either one or both of a timestamp and block height (sequence). +message Timeout { + // block height after which the packet or upgrade times out + ibc.core.client.v1.Height height = 1 [(gogoproto.nullable) = false]; + // block timestamp (in nanoseconds) after which the packet or upgrade times out + uint64 timestamp = 2; +} + +// Params defines the set of IBC channel parameters. +message Params { + // the relative timeout after which channel upgrades will time out. + Timeout upgrade_timeout = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/channel/v1/genesis.proto b/third_party/proto/ibc/channel/v1/genesis.proto new file mode 100644 index 000000000..665b2b156 --- /dev/null +++ b/third_party/proto/ibc/channel/v1/genesis.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// GenesisState defines the ibc channel submodule's genesis state. +message GenesisState { + repeated IdentifiedChannel channels = 1 [(gogoproto.casttype) = "IdentifiedChannel", (gogoproto.nullable) = false]; + repeated PacketState acknowledgements = 2 [(gogoproto.nullable) = false]; + repeated PacketState commitments = 3 [(gogoproto.nullable) = false]; + repeated PacketState receipts = 4 [(gogoproto.nullable) = false]; + repeated PacketSequence send_sequences = 5 [(gogoproto.nullable) = false]; + repeated PacketSequence recv_sequences = 6 [(gogoproto.nullable) = false]; + repeated PacketSequence ack_sequences = 7 [(gogoproto.nullable) = false]; + // the sequence for the next generated channel identifier + uint64 next_channel_sequence = 8; + Params params = 9 [(gogoproto.nullable) = false]; +} + +// PacketSequence defines the genesis type necessary to retrieve and store +// next send and receive sequences. +message PacketSequence { + string port_id = 1; + string channel_id = 2; + uint64 sequence = 3; +} diff --git a/third_party/proto/ibc/channel/v1/query.proto b/third_party/proto/ibc/channel/v1/query.proto new file mode 100644 index 000000000..f89d21273 --- /dev/null +++ b/third_party/proto/ibc/channel/v1/query.proto @@ -0,0 +1,459 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "ibc/core/client/v1/client.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/upgrade.proto"; + +// Query provides defines the gRPC querier service +service Query { + // Channel queries an IBC Channel. + rpc Channel(QueryChannelRequest) returns (QueryChannelResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}"; + } + + // Channels queries all the IBC channels of a chain. + rpc Channels(QueryChannelsRequest) returns (QueryChannelsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels"; + } + + // ConnectionChannels queries all the channels associated with a connection + // end. + rpc ConnectionChannels(QueryConnectionChannelsRequest) returns (QueryConnectionChannelsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/connections/{connection}/channels"; + } + + // ChannelClientState queries for the client state for the channel associated + // with the provided channel identifiers. + rpc ChannelClientState(QueryChannelClientStateRequest) returns (QueryChannelClientStateResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/client_state"; + } + + // ChannelConsensusState queries for the consensus state for the channel + // associated with the provided channel identifiers. + rpc ChannelConsensusState(QueryChannelConsensusStateRequest) returns (QueryChannelConsensusStateResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/consensus_state/revision/" + "{revision_number}/height/{revision_height}"; + } + + // PacketCommitment queries a stored packet commitment hash. + rpc PacketCommitment(QueryPacketCommitmentRequest) returns (QueryPacketCommitmentResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" + "packet_commitments/{sequence}"; + } + + // PacketCommitments returns all the packet commitments hashes associated + // with a channel. + rpc PacketCommitments(QueryPacketCommitmentsRequest) returns (QueryPacketCommitmentsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/packet_commitments"; + } + + // PacketReceipt queries if a given packet sequence has been received on the + // queried chain + rpc PacketReceipt(QueryPacketReceiptRequest) returns (QueryPacketReceiptResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/packet_receipts/{sequence}"; + } + + // PacketAcknowledgement queries a stored packet acknowledgement hash. + rpc PacketAcknowledgement(QueryPacketAcknowledgementRequest) returns (QueryPacketAcknowledgementResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/packet_acks/{sequence}"; + } + + // PacketAcknowledgements returns all the packet acknowledgements associated + // with a channel. + rpc PacketAcknowledgements(QueryPacketAcknowledgementsRequest) returns (QueryPacketAcknowledgementsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/packet_acknowledgements"; + } + + // UnreceivedPackets returns all the unreceived IBC packets associated with a + // channel and sequences. + rpc UnreceivedPackets(QueryUnreceivedPacketsRequest) returns (QueryUnreceivedPacketsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" + "packet_commitments/" + "{packet_commitment_sequences}/unreceived_packets"; + } + + // UnreceivedAcks returns all the unreceived IBC acknowledgements associated + // with a channel and sequences. + rpc UnreceivedAcks(QueryUnreceivedAcksRequest) returns (QueryUnreceivedAcksResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/packet_commitments/" + "{packet_ack_sequences}/unreceived_acks"; + } + + // NextSequenceReceive returns the next receive sequence for a given channel. + rpc NextSequenceReceive(QueryNextSequenceReceiveRequest) returns (QueryNextSequenceReceiveResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/next_sequence"; + } + + // NextSequenceSend returns the next send sequence for a given channel. + rpc NextSequenceSend(QueryNextSequenceSendRequest) returns (QueryNextSequenceSendResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/next_sequence_send"; + } + + // UpgradeError returns the error receipt if the upgrade handshake failed. + rpc UpgradeError(QueryUpgradeErrorRequest) returns (QueryUpgradeErrorResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade_error"; + } + + // Upgrade returns the upgrade for a given port and channel id. + rpc Upgrade(QueryUpgradeRequest) returns (QueryUpgradeResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade"; + } + + // ChannelParams queries all parameters of the ibc channel submodule. + rpc ChannelParams(QueryChannelParamsRequest) returns (QueryChannelParamsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/params"; + } +} + +// QueryChannelRequest is the request type for the Query/Channel RPC method +message QueryChannelRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; +} + +// QueryChannelResponse is the response type for the Query/Channel RPC method. +// Besides the Channel end, it includes a proof and the height from which the +// proof was retrieved. +message QueryChannelResponse { + // channel associated with the request identifiers + ibc.core.channel.v1.Channel channel = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelsRequest is the request type for the Query/Channels RPC method +message QueryChannelsRequest { + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryChannelsResponse is the response type for the Query/Channels RPC method. +message QueryChannelsResponse { + // list of stored channels of the chain. + repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; + // query block height + ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; +} + +// QueryConnectionChannelsRequest is the request type for the +// Query/QueryConnectionChannels RPC method +message QueryConnectionChannelsRequest { + // connection unique identifier + string connection = 1; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryConnectionChannelsResponse is the Response type for the +// Query/QueryConnectionChannels RPC method +message QueryConnectionChannelsResponse { + // list of channels associated with a connection. + repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; + // query block height + ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelClientStateRequest is the request type for the Query/ClientState +// RPC method +message QueryChannelClientStateRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; +} + +// QueryChannelClientStateResponse is the Response type for the +// Query/QueryChannelClientState RPC method +message QueryChannelClientStateResponse { + // client state associated with the channel + ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelConsensusStateRequest is the request type for the +// Query/ConsensusState RPC method +message QueryChannelConsensusStateRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // revision number of the consensus state + uint64 revision_number = 3; + // revision height of the consensus state + uint64 revision_height = 4; +} + +// QueryChannelClientStateResponse is the Response type for the +// Query/QueryChannelClientState RPC method +message QueryChannelConsensusStateResponse { + // consensus state associated with the channel + google.protobuf.Any consensus_state = 1; + // client ID associated with the consensus state + string client_id = 2; + // merkle proof of existence + bytes proof = 3; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; +} + +// QueryPacketCommitmentRequest is the request type for the +// Query/PacketCommitment RPC method +message QueryPacketCommitmentRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // packet sequence + uint64 sequence = 3; +} + +// QueryPacketCommitmentResponse defines the client query response for a packet +// which also includes a proof and the height from which the proof was +// retrieved +message QueryPacketCommitmentResponse { + // packet associated with the request fields + bytes commitment = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryPacketCommitmentsRequest is the request type for the +// Query/QueryPacketCommitments RPC method +message QueryPacketCommitmentsRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 3; +} + +// QueryPacketCommitmentsResponse is the request type for the +// Query/QueryPacketCommitments RPC method +message QueryPacketCommitmentsResponse { + repeated ibc.core.channel.v1.PacketState commitments = 1; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; + // query block height + ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; +} + +// QueryPacketReceiptRequest is the request type for the +// Query/PacketReceipt RPC method +message QueryPacketReceiptRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // packet sequence + uint64 sequence = 3; +} + +// QueryPacketReceiptResponse defines the client query response for a packet +// receipt which also includes a proof, and the height from which the proof was +// retrieved +message QueryPacketReceiptResponse { + // success flag for if receipt exists + bool received = 2; + // merkle proof of existence + bytes proof = 3; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; +} + +// QueryPacketAcknowledgementRequest is the request type for the +// Query/PacketAcknowledgement RPC method +message QueryPacketAcknowledgementRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // packet sequence + uint64 sequence = 3; +} + +// QueryPacketAcknowledgementResponse defines the client query response for a +// packet which also includes a proof and the height from which the +// proof was retrieved +message QueryPacketAcknowledgementResponse { + // packet associated with the request fields + bytes acknowledgement = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryPacketAcknowledgementsRequest is the request type for the +// Query/QueryPacketCommitments RPC method +message QueryPacketAcknowledgementsRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 3; + // list of packet sequences + repeated uint64 packet_commitment_sequences = 4; +} + +// QueryPacketAcknowledgemetsResponse is the request type for the +// Query/QueryPacketAcknowledgements RPC method +message QueryPacketAcknowledgementsResponse { + repeated ibc.core.channel.v1.PacketState acknowledgements = 1; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; + // query block height + ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUnreceivedPacketsRequest is the request type for the +// Query/UnreceivedPackets RPC method +message QueryUnreceivedPacketsRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // list of packet sequences + repeated uint64 packet_commitment_sequences = 3; +} + +// QueryUnreceivedPacketsResponse is the response type for the +// Query/UnreceivedPacketCommitments RPC method +message QueryUnreceivedPacketsResponse { + // list of unreceived packet sequences + repeated uint64 sequences = 1; + // query block height + ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; +} + +// QueryUnreceivedAcks is the request type for the +// Query/UnreceivedAcks RPC method +message QueryUnreceivedAcksRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; + // list of acknowledgement sequences + repeated uint64 packet_ack_sequences = 3; +} + +// QueryUnreceivedAcksResponse is the response type for the +// Query/UnreceivedAcks RPC method +message QueryUnreceivedAcksResponse { + // list of unreceived acknowledgement sequences + repeated uint64 sequences = 1; + // query block height + ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; +} + +// QueryNextSequenceReceiveRequest is the request type for the +// Query/QueryNextSequenceReceiveRequest RPC method +message QueryNextSequenceReceiveRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; +} + +// QuerySequenceResponse is the response type for the +// Query/QueryNextSequenceReceiveResponse RPC method +message QueryNextSequenceReceiveResponse { + // next sequence receive number + uint64 next_sequence_receive = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryNextSequenceSendRequest is the request type for the +// Query/QueryNextSequenceSend RPC method +message QueryNextSequenceSendRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; +} + +// QueryNextSequenceSendResponse is the request type for the +// Query/QueryNextSequenceSend RPC method +message QueryNextSequenceSendResponse { + // next sequence send number + uint64 next_sequence_send = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeErrorRequest is the request type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeErrorResponse is the response type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorResponse { + ErrorReceipt error_receipt = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeRequest is the request type for the QueryUpgradeRequest RPC method +message QueryUpgradeRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC method +message QueryUpgradeResponse { + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelParamsRequest is the request type for the Query/ChannelParams RPC method. +message QueryChannelParamsRequest {} + +// QueryChannelParamsResponse is the response type for the Query/ChannelParams RPC method. +message QueryChannelParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/channel/v1/tx.proto b/third_party/proto/ibc/channel/v1/tx.proto new file mode 100644 index 000000000..3f30e8b8c --- /dev/null +++ b/third_party/proto/ibc/channel/v1/tx.proto @@ -0,0 +1,469 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "ibc/core/channel/v1/upgrade.proto"; + +// Msg defines the ibc/channel Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. + rpc ChannelOpenInit(MsgChannelOpenInit) returns (MsgChannelOpenInitResponse); + + // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. + rpc ChannelOpenTry(MsgChannelOpenTry) returns (MsgChannelOpenTryResponse); + + // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. + rpc ChannelOpenAck(MsgChannelOpenAck) returns (MsgChannelOpenAckResponse); + + // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. + rpc ChannelOpenConfirm(MsgChannelOpenConfirm) returns (MsgChannelOpenConfirmResponse); + + // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. + rpc ChannelCloseInit(MsgChannelCloseInit) returns (MsgChannelCloseInitResponse); + + // ChannelCloseConfirm defines a rpc handler method for + // MsgChannelCloseConfirm. + rpc ChannelCloseConfirm(MsgChannelCloseConfirm) returns (MsgChannelCloseConfirmResponse); + + // RecvPacket defines a rpc handler method for MsgRecvPacket. + rpc RecvPacket(MsgRecvPacket) returns (MsgRecvPacketResponse); + + // Timeout defines a rpc handler method for MsgTimeout. + rpc Timeout(MsgTimeout) returns (MsgTimeoutResponse); + + // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. + rpc TimeoutOnClose(MsgTimeoutOnClose) returns (MsgTimeoutOnCloseResponse); + + // Acknowledgement defines a rpc handler method for MsgAcknowledgement. + rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); + + // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. + rpc ChannelUpgradeInit(MsgChannelUpgradeInit) returns (MsgChannelUpgradeInitResponse); + + // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. + rpc ChannelUpgradeTry(MsgChannelUpgradeTry) returns (MsgChannelUpgradeTryResponse); + + // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. + rpc ChannelUpgradeAck(MsgChannelUpgradeAck) returns (MsgChannelUpgradeAckResponse); + + // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. + rpc ChannelUpgradeConfirm(MsgChannelUpgradeConfirm) returns (MsgChannelUpgradeConfirmResponse); + + // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. + rpc ChannelUpgradeOpen(MsgChannelUpgradeOpen) returns (MsgChannelUpgradeOpenResponse); + + // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. + rpc ChannelUpgradeTimeout(MsgChannelUpgradeTimeout) returns (MsgChannelUpgradeTimeoutResponse); + + // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. + rpc ChannelUpgradeCancel(MsgChannelUpgradeCancel) returns (MsgChannelUpgradeCancelResponse); + + // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. + rpc UpdateChannelParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); + + // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. + rpc PruneAcknowledgements(MsgPruneAcknowledgements) returns (MsgPruneAcknowledgementsResponse); +} + +// ResponseResultType defines the possible outcomes of the execution of a message +enum ResponseResultType { + option (gogoproto.goproto_enum_prefix) = false; + + // Default zero value enumeration + RESPONSE_RESULT_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + // The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) + RESPONSE_RESULT_TYPE_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; + // The message was executed successfully + RESPONSE_RESULT_TYPE_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; + // The message was executed unsuccessfully + RESPONSE_RESULT_TYPE_FAILURE = 3 [(gogoproto.enumvalue_customname) = "FAILURE"]; +} + +// MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It +// is called by a relayer on Chain A. +message MsgChannelOpenInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + Channel channel = 2 [(gogoproto.nullable) = false]; + string signer = 3; +} + +// MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. +message MsgChannelOpenInitResponse { + option (gogoproto.goproto_getters) = false; + + string channel_id = 1; + string version = 2; +} + +// MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel +// on Chain B. The version field within the Channel field has been deprecated. Its +// value will be ignored by core IBC. +message MsgChannelOpenTry { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. + string previous_channel_id = 2 [deprecated = true]; + // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. + Channel channel = 3 [(gogoproto.nullable) = false]; + string counterparty_version = 4; + bytes proof_init = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. +message MsgChannelOpenTryResponse { + option (gogoproto.goproto_getters) = false; + + string version = 1; + string channel_id = 2; +} + +// MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge +// the change of channel state to TRYOPEN on Chain B. +// WARNING: a channel upgrade MUST NOT initialize an upgrade for this channel +// in the same block as executing this message otherwise the counterparty will +// be incapable of opening. +message MsgChannelOpenAck { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + string counterparty_channel_id = 3; + string counterparty_version = 4; + bytes proof_try = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelOpenAckResponse defines the Msg/ChannelOpenAck response type. +message MsgChannelOpenAckResponse {} + +// MsgChannelOpenConfirm defines a msg sent by a Relayer to Chain B to +// acknowledge the change of channel state to OPEN on Chain A. +message MsgChannelOpenConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + bytes proof_ack = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; +} + +// MsgChannelOpenConfirmResponse defines the Msg/ChannelOpenConfirm response +// type. +message MsgChannelOpenConfirmResponse {} + +// MsgChannelCloseInit defines a msg sent by a Relayer to Chain A +// to close a channel with Chain B. +message MsgChannelCloseInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + string signer = 3; +} + +// MsgChannelCloseInitResponse defines the Msg/ChannelCloseInit response type. +message MsgChannelCloseInitResponse {} + +// MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B +// to acknowledge the change of channel state to CLOSED on Chain A. +message MsgChannelCloseConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + bytes proof_init = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; + uint64 counterparty_upgrade_sequence = 6; +} + +// MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response +// type. +message MsgChannelCloseConfirmResponse {} + +// MsgRecvPacket receives incoming IBC packet +message MsgRecvPacket { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_commitment = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + string signer = 4; +} + +// MsgRecvPacketResponse defines the Msg/RecvPacket response type. +message MsgRecvPacketResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgTimeout receives timed-out packet +message MsgTimeout { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_unreceived = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + uint64 next_sequence_recv = 4; + string signer = 5; +} + +// MsgTimeoutResponse defines the Msg/Timeout response type. +message MsgTimeoutResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgTimeoutOnClose timed-out packet upon counterparty channel closure. +message MsgTimeoutOnClose { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_unreceived = 2; + bytes proof_close = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + uint64 next_sequence_recv = 5; + string signer = 6; + uint64 counterparty_upgrade_sequence = 7; +} + +// MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. +message MsgTimeoutOnCloseResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgAcknowledgement receives incoming IBC acknowledgement +message MsgAcknowledgement { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes acknowledgement = 2; + bytes proof_acked = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; +} + +// MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. +message MsgAcknowledgementResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeInit defines the request type for the ChannelUpgradeInit rpc +// WARNING: Initializing a channel upgrade in the same block as opening the channel +// may result in the counterparty being incapable of opening. +message MsgChannelUpgradeInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + UpgradeFields fields = 3 [(gogoproto.nullable) = false]; + string signer = 4; +} + +// MsgChannelUpgradeInitResponse defines the MsgChannelUpgradeInit response type +message MsgChannelUpgradeInitResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; +} + +// MsgChannelUpgradeTry defines the request type for the ChannelUpgradeTry rpc +message MsgChannelUpgradeTry { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + repeated string proposed_upgrade_connection_hops = 3; + UpgradeFields counterparty_upgrade_fields = 4 [(gogoproto.nullable) = false]; + uint64 counterparty_upgrade_sequence = 5; + bytes proof_channel = 6; + bytes proof_upgrade = 7; + ibc.core.client.v1.Height proof_height = 8 [(gogoproto.nullable) = false]; + string signer = 9; +} + +// MsgChannelUpgradeTryResponse defines the MsgChannelUpgradeTry response type +message MsgChannelUpgradeTryResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; + ResponseResultType result = 3; +} + +// MsgChannelUpgradeAck defines the request type for the ChannelUpgradeAck rpc +message MsgChannelUpgradeAck { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + Upgrade counterparty_upgrade = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + bytes proof_upgrade = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeAckResponse defines MsgChannelUpgradeAck response type +message MsgChannelUpgradeAckResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeConfirm defines the request type for the ChannelUpgradeConfirm rpc +message MsgChannelUpgradeConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + Upgrade counterparty_upgrade = 4 [(gogoproto.nullable) = false]; + bytes proof_channel = 5; + bytes proof_upgrade = 6; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; + string signer = 8; +} + +// MsgChannelUpgradeConfirmResponse defines MsgChannelUpgradeConfirm response type +message MsgChannelUpgradeConfirmResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeOpen defines the request type for the ChannelUpgradeOpen rpc +message MsgChannelUpgradeOpen { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + uint64 counterparty_upgrade_sequence = 4; + bytes proof_channel = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeOpenResponse defines the MsgChannelUpgradeOpen response type +message MsgChannelUpgradeOpenResponse {} + +// MsgChannelUpgradeTimeout defines the request type for the ChannelUpgradeTimeout rpc +message MsgChannelUpgradeTimeout { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + Channel counterparty_channel = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeTimeoutRepsonse defines the MsgChannelUpgradeTimeout response type +message MsgChannelUpgradeTimeoutResponse {} + +// MsgChannelUpgradeCancel defines the request type for the ChannelUpgradeCancel rpc +message MsgChannelUpgradeCancel { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + ErrorReceipt error_receipt = 3 [(gogoproto.nullable) = false]; + bytes proof_error_receipt = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeCancelResponse defines the MsgChannelUpgradeCancel response type +message MsgChannelUpgradeCancelResponse {} + +// MsgUpdateParams is the MsgUpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + option (gogoproto.goproto_getters) = false; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1; + + // params defines the channel parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} + +// MsgPruneAcknowledgements defines the request type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgements { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + uint64 limit = 3; + string signer = 4; +} + +// MsgPruneAcknowledgementsResponse defines the response type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgementsResponse { + // Number of sequences pruned (includes both packet acknowledgements and packet receipts where appropriate). + uint64 total_pruned_sequences = 1; + // Number of sequences left after pruning. + uint64 total_remaining_sequences = 2; +} diff --git a/third_party/proto/ibc/channel/v1/upgrade.proto b/third_party/proto/ibc/channel/v1/upgrade.proto new file mode 100644 index 000000000..81530ed2a --- /dev/null +++ b/third_party/proto/ibc/channel/v1/upgrade.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Upgrade is a verifiable type which contains the relevant information +// for an attempted upgrade. It provides the proposed changes to the channel +// end, the timeout for this upgrade attempt and the next packet sequence +// which allows the counterparty to efficiently know the highest sequence it has received. +// The next sequence send is used for pruning and upgrading from unordered to ordered channels. +message Upgrade { + option (gogoproto.goproto_getters) = false; + + UpgradeFields fields = 1 [(gogoproto.nullable) = false]; + Timeout timeout = 2 [(gogoproto.nullable) = false]; + uint64 next_sequence_send = 3; +} + +// UpgradeFields are the fields in a channel end which may be changed +// during a channel upgrade. +message UpgradeFields { + option (gogoproto.goproto_getters) = false; + + Order ordering = 1; + repeated string connection_hops = 2; + string version = 3; +} + +// ErrorReceipt defines a type which encapsulates the upgrade sequence and error associated with the +// upgrade handshake failure. When a channel upgrade handshake is aborted both chains are expected to increment to the +// next sequence. +message ErrorReceipt { + option (gogoproto.goproto_getters) = false; + + // the channel upgrade sequence + uint64 sequence = 1; + // the error message detailing the cause of failure + string message = 2; +} diff --git a/third_party/proto/ibc/client/v1/client.proto b/third_party/proto/ibc/client/v1/client.proto new file mode 100644 index 000000000..7a09e360a --- /dev/null +++ b/third_party/proto/ibc/client/v1/client.proto @@ -0,0 +1,113 @@ +syntax = "proto3"; + +package ibc.core.client.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; + +import "cosmos/upgrade/v1beta1/upgrade.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +// IdentifiedClientState defines a client state with an additional client +// identifier field. +message IdentifiedClientState { + // client identifier + string client_id = 1; + // client state + google.protobuf.Any client_state = 2; +} + +// ConsensusStateWithHeight defines a consensus state with an additional height +// field. +message ConsensusStateWithHeight { + // consensus state height + Height height = 1 [(gogoproto.nullable) = false]; + // consensus state + google.protobuf.Any consensus_state = 2; +} + +// ClientConsensusStates defines all the stored consensus states for a given +// client. +message ClientConsensusStates { + // client identifier + string client_id = 1; + // consensus states and their heights associated with the client + repeated ConsensusStateWithHeight consensus_states = 2 [(gogoproto.nullable) = false]; +} + +// Height is a monotonically increasing data type +// that can be compared against another Height for the purposes of updating and +// freezing clients +// +// Normally the RevisionHeight is incremented at each height while keeping +// RevisionNumber the same. However some consensus algorithms may choose to +// reset the height in certain conditions e.g. hard forks, state-machine +// breaking changes In these cases, the RevisionNumber is incremented so that +// height continues to be monitonically increasing even as the RevisionHeight +// gets reset +message Height { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + // the revision that the client is currently on + uint64 revision_number = 1; + // the height within the given revision + uint64 revision_height = 2; +} + +// Params defines the set of IBC light client parameters. +message Params { + // allowed_clients defines the list of allowed client state types which can be created + // and interacted with. If a client type is removed from the allowed clients list, usage + // of this client will be disabled until it is added again to the list. + repeated string allowed_clients = 1; +} + +// ClientUpdateProposal is a legacy governance proposal. If it passes, the substitute +// client's latest consensus state is copied over to the subject client. The proposal +// handler may fail if the subject and the substitute do not match in client and +// chain parameters (with exception to latest height, frozen height, and chain-id). +// +// Deprecated: Please use MsgRecoverClient in favour of this message type. +message ClientUpdateProposal { + option deprecated = true; + + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + option (gogoproto.goproto_getters) = false; + + // the title of the update proposal + string title = 1; + // the description of the proposal + string description = 2; + // the client identifier for the client to be updated if the proposal passes + string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""]; + // the substitute client identifier for the client standing in for the subject + // client + string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"substitute_client_id\""]; +} + +// UpgradeProposal is a gov Content type for initiating an IBC breaking +// upgrade. +// +// Deprecated: Please use MsgIBCSoftwareUpgrade in favour of this message type. +message UpgradeProposal { + option deprecated = true; + + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (gogoproto.equal) = true; + + string title = 1; + string description = 2; + cosmos.upgrade.v1beta1.Plan plan = 3 [(gogoproto.nullable) = false]; + + // An UpgradedClientState must be provided to perform an IBC breaking upgrade. + // This will make the chain commit to the correct upgraded (self) client state + // before the upgrade occurs, so that connecting chains can verify that the + // new upgraded client is valid by verifying a proof on the previous version + // of the chain. This will allow IBC connections to persist smoothly across + // planned chain upgrades + google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; +} diff --git a/third_party/proto/ibc/client/v1/genesis.proto b/third_party/proto/ibc/client/v1/genesis.proto new file mode 100644 index 000000000..43610b0d4 --- /dev/null +++ b/third_party/proto/ibc/client/v1/genesis.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package ibc.core.client.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; + +import "ibc/core/client/v1/client.proto"; +import "gogoproto/gogo.proto"; + +// GenesisState defines the ibc client submodule's genesis state. +message GenesisState { + // client states with their corresponding identifiers + repeated IdentifiedClientState clients = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; + // consensus states from each client + repeated ClientConsensusStates clients_consensus = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "ClientsConsensusStates"]; + // metadata from each client + repeated IdentifiedGenesisMetadata clients_metadata = 3 [(gogoproto.nullable) = false]; + Params params = 4 [(gogoproto.nullable) = false]; + // Deprecated: create_localhost has been deprecated. + // The localhost client is automatically created at genesis. + bool create_localhost = 5 [deprecated = true]; + // the sequence for the next generated client identifier + uint64 next_client_sequence = 6; +} + +// GenesisMetadata defines the genesis type for metadata that clients may return +// with ExportMetadata +message GenesisMetadata { + option (gogoproto.goproto_getters) = false; + + // store key of metadata without clientID-prefix + bytes key = 1; + // metadata value + bytes value = 2; +} + +// IdentifiedGenesisMetadata has the client metadata with the corresponding +// client id. +message IdentifiedGenesisMetadata { + string client_id = 1; + repeated GenesisMetadata client_metadata = 2 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/client/v1/query.proto b/third_party/proto/ibc/client/v1/query.proto new file mode 100644 index 000000000..0032306ec --- /dev/null +++ b/third_party/proto/ibc/client/v1/query.proto @@ -0,0 +1,207 @@ +syntax = "proto3"; + +package ibc.core.client.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; + +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/core/client/v1/client.proto"; +import "google/protobuf/any.proto"; +import "google/api/annotations.proto"; +import "gogoproto/gogo.proto"; + +// Query provides defines the gRPC querier service +service Query { + // ClientState queries an IBC light client. + rpc ClientState(QueryClientStateRequest) returns (QueryClientStateResponse) { + option (google.api.http).get = "/ibc/core/client/v1/client_states/{client_id}"; + } + + // ClientStates queries all the IBC light clients of a chain. + rpc ClientStates(QueryClientStatesRequest) returns (QueryClientStatesResponse) { + option (google.api.http).get = "/ibc/core/client/v1/client_states"; + } + + // ConsensusState queries a consensus state associated with a client state at + // a given height. + rpc ConsensusState(QueryConsensusStateRequest) returns (QueryConsensusStateResponse) { + option (google.api.http).get = "/ibc/core/client/v1/consensus_states/" + "{client_id}/revision/{revision_number}/" + "height/{revision_height}"; + } + + // ConsensusStates queries all the consensus state associated with a given + // client. + rpc ConsensusStates(QueryConsensusStatesRequest) returns (QueryConsensusStatesResponse) { + option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}"; + } + + // ConsensusStateHeights queries the height of every consensus states associated with a given client. + rpc ConsensusStateHeights(QueryConsensusStateHeightsRequest) returns (QueryConsensusStateHeightsResponse) { + option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}/heights"; + } + + // Status queries the status of an IBC client. + rpc ClientStatus(QueryClientStatusRequest) returns (QueryClientStatusResponse) { + option (google.api.http).get = "/ibc/core/client/v1/client_status/{client_id}"; + } + + // ClientParams queries all parameters of the ibc client submodule. + rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) { + option (google.api.http).get = "/ibc/core/client/v1/params"; + } + + // UpgradedClientState queries an Upgraded IBC light client. + rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) { + option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states"; + } + + // UpgradedConsensusState queries an Upgraded IBC consensus state. + rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) { + option (google.api.http).get = "/ibc/core/client/v1/upgraded_consensus_states"; + } +} + +// QueryClientStateRequest is the request type for the Query/ClientState RPC +// method +message QueryClientStateRequest { + // client state unique identifier + string client_id = 1; +} + +// QueryClientStateResponse is the response type for the Query/ClientState RPC +// method. Besides the client state, it includes a proof and the height from +// which the proof was retrieved. +message QueryClientStateResponse { + // client state associated with the request identifier + google.protobuf.Any client_state = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryClientStatesRequest is the request type for the Query/ClientStates RPC +// method +message QueryClientStatesRequest { + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryClientStatesResponse is the response type for the Query/ClientStates RPC +// method. +message QueryClientStatesResponse { + // list of stored ClientStates of the chain. + repeated IdentifiedClientState client_states = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryConsensusStateRequest is the request type for the Query/ConsensusState +// RPC method. Besides the consensus state, it includes a proof and the height +// from which the proof was retrieved. +message QueryConsensusStateRequest { + // client identifier + string client_id = 1; + // consensus state revision number + uint64 revision_number = 2; + // consensus state revision height + uint64 revision_height = 3; + // latest_height overrrides the height field and queries the latest stored + // ConsensusState + bool latest_height = 4; +} + +// QueryConsensusStateResponse is the response type for the Query/ConsensusState +// RPC method +message QueryConsensusStateResponse { + // consensus state associated with the client identifier at the given height + google.protobuf.Any consensus_state = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryConsensusStatesRequest is the request type for the Query/ConsensusStates +// RPC method. +message QueryConsensusStatesRequest { + // client identifier + string client_id = 1; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryConsensusStatesResponse is the response type for the +// Query/ConsensusStates RPC method +message QueryConsensusStatesResponse { + // consensus states associated with the identifier + repeated ConsensusStateWithHeight consensus_states = 1 [(gogoproto.nullable) = false]; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights +// RPC method. +message QueryConsensusStateHeightsRequest { + // client identifier + string client_id = 1; + // pagination request + cosmos.base.query.v1beta1.PageRequest pagination = 2; +} + +// QueryConsensusStateHeightsResponse is the response type for the +// Query/ConsensusStateHeights RPC method +message QueryConsensusStateHeightsResponse { + // consensus state heights + repeated Height consensus_state_heights = 1 [(gogoproto.nullable) = false]; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryClientStatusRequest is the request type for the Query/ClientStatus RPC +// method +message QueryClientStatusRequest { + // client unique identifier + string client_id = 1; +} + +// QueryClientStatusResponse is the response type for the Query/ClientStatus RPC +// method. It returns the current status of the IBC client. +message QueryClientStatusResponse { + string status = 1; +} + +// QueryClientParamsRequest is the request type for the Query/ClientParams RPC +// method. +message QueryClientParamsRequest {} + +// QueryClientParamsResponse is the response type for the Query/ClientParams RPC +// method. +message QueryClientParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} + +// QueryUpgradedClientStateRequest is the request type for the +// Query/UpgradedClientState RPC method +message QueryUpgradedClientStateRequest {} + +// QueryUpgradedClientStateResponse is the response type for the +// Query/UpgradedClientState RPC method. +message QueryUpgradedClientStateResponse { + // client state associated with the request identifier + google.protobuf.Any upgraded_client_state = 1; +} + +// QueryUpgradedConsensusStateRequest is the request type for the +// Query/UpgradedConsensusState RPC method +message QueryUpgradedConsensusStateRequest {} + +// QueryUpgradedConsensusStateResponse is the response type for the +// Query/UpgradedConsensusState RPC method. +message QueryUpgradedConsensusStateResponse { + // Consensus state associated with the request identifier + google.protobuf.Any upgraded_consensus_state = 1; +} diff --git a/third_party/proto/ibc/client/v1/tx.proto b/third_party/proto/ibc/client/v1/tx.proto new file mode 100644 index 000000000..b504ab692 --- /dev/null +++ b/third_party/proto/ibc/client/v1/tx.proto @@ -0,0 +1,175 @@ +syntax = "proto3"; + +package ibc.core.client.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; + +import "cosmos/msg/v1/msg.proto"; +import "cosmos/upgrade/v1beta1/upgrade.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "ibc/core/client/v1/client.proto"; + +// Msg defines the ibc/client Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // CreateClient defines a rpc handler method for MsgCreateClient. + rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse); + + // UpdateClient defines a rpc handler method for MsgUpdateClient. + rpc UpdateClient(MsgUpdateClient) returns (MsgUpdateClientResponse); + + // UpgradeClient defines a rpc handler method for MsgUpgradeClient. + rpc UpgradeClient(MsgUpgradeClient) returns (MsgUpgradeClientResponse); + + // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. + rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); + + // RecoverClient defines a rpc handler method for MsgRecoverClient. + rpc RecoverClient(MsgRecoverClient) returns (MsgRecoverClientResponse); + + // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. + rpc IBCSoftwareUpgrade(MsgIBCSoftwareUpgrade) returns (MsgIBCSoftwareUpgradeResponse); + + // UpdateClientParams defines a rpc handler method for MsgUpdateParams. + rpc UpdateClientParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgCreateClient defines a message to create an IBC client +message MsgCreateClient { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // light client state + google.protobuf.Any client_state = 1; + // consensus state associated with the client that corresponds to a given + // height. + google.protobuf.Any consensus_state = 2; + // signer address + string signer = 3; +} + +// MsgCreateClientResponse defines the Msg/CreateClient response type. +message MsgCreateClientResponse {} + +// MsgUpdateClient defines an sdk.Msg to update a IBC client state using +// the given client message. +message MsgUpdateClient { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // client unique identifier + string client_id = 1; + // client message to update the light client + google.protobuf.Any client_message = 2; + // signer address + string signer = 3; +} + +// MsgUpdateClientResponse defines the Msg/UpdateClient response type. +message MsgUpdateClientResponse {} + +// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client +// state +message MsgUpgradeClient { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // client unique identifier + string client_id = 1; + // upgraded client state + google.protobuf.Any client_state = 2; + // upgraded consensus state, only contains enough information to serve as a + // basis of trust in update logic + google.protobuf.Any consensus_state = 3; + // proof that old chain committed to new client + bytes proof_upgrade_client = 4; + // proof that old chain committed to new consensus state + bytes proof_upgrade_consensus_state = 5; + // signer address + string signer = 6; +} + +// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type. +message MsgUpgradeClientResponse {} + +// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for +// light client misbehaviour. +// This message has been deprecated. Use MsgUpdateClient instead. +message MsgSubmitMisbehaviour { + option deprecated = true; + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // client unique identifier + string client_id = 1; + // misbehaviour used for freezing the light client + google.protobuf.Any misbehaviour = 2; + // signer address + string signer = 3; +} + +// MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response +// type. +message MsgSubmitMisbehaviourResponse {} + +// MsgRecoverClient defines the message used to recover a frozen or expired client. +message MsgRecoverClient { + option (gogoproto.goproto_getters) = false; + option (cosmos.msg.v1.signer) = "signer"; + + // the client identifier for the client to be updated if the proposal passes + string subject_client_id = 1; + // the substitute client identifier for the client which will replace the subject + // client + string substitute_client_id = 2; + + // signer address + string signer = 3; +} + +// MsgRecoverClientResponse defines the Msg/RecoverClient response type. +message MsgRecoverClientResponse {} + +// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal +message MsgIBCSoftwareUpgrade { + option (cosmos.msg.v1.signer) = "signer"; + cosmos.upgrade.v1beta1.Plan plan = 1 [(gogoproto.nullable) = false]; + // An UpgradedClientState must be provided to perform an IBC breaking upgrade. + // This will make the chain commit to the correct upgraded (self) client state + // before the upgrade occurs, so that connecting chains can verify that the + // new upgraded client is valid by verifying a proof on the previous version + // of the chain. This will allow IBC connections to persist smoothly across + // planned chain upgrades. Correspondingly, the UpgradedClientState field has been + // deprecated in the Cosmos SDK to allow for this logic to exist solely in + // the 02-client module. + google.protobuf.Any upgraded_client_state = 2; + // signer address + string signer = 3; +} + +// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. +message MsgIBCSoftwareUpgradeResponse {} + +// MsgUpdateParams defines the sdk.Msg type to update the client parameters. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the client parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/commitment/v1/commitment.proto b/third_party/proto/ibc/commitment/v1/commitment.proto new file mode 100644 index 000000000..b4753be2d --- /dev/null +++ b/third_party/proto/ibc/commitment/v1/commitment.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package ibc.core.commitment.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/ics23/v1/proofs.proto"; + +// MerkleRoot defines a merkle root hash. +// In the Cosmos SDK, the AppHash of a block header becomes the root. +message MerkleRoot { + option (gogoproto.goproto_getters) = false; + + bytes hash = 1; +} + +// MerklePrefix is merkle path prefixed to the key. +// The constructed key from the Path and the key will be append(Path.KeyPath, +// append(Path.KeyPrefix, key...)) +message MerklePrefix { + bytes key_prefix = 1; +} + +// MerklePath is the path used to verify commitment proofs, which can be an +// arbitrary structured object (defined by a commitment type). +// MerklePath is represented from root-to-leaf +message MerklePath { + repeated string key_path = 1; +} + +// MerkleProof is a wrapper type over a chain of CommitmentProofs. +// It demonstrates membership or non-membership for an element or set of +// elements, verifiable in conjunction with a known commitment root. Proofs +// should be succinct. +// MerkleProofs are ordered from leaf-to-root +message MerkleProof { + repeated cosmos.ics23.v1.CommitmentProof proofs = 1; +} diff --git a/third_party/proto/ibc/connection/v1/connection.proto b/third_party/proto/ibc/connection/v1/connection.proto new file mode 100644 index 000000000..852f3999b --- /dev/null +++ b/third_party/proto/ibc/connection/v1/connection.proto @@ -0,0 +1,114 @@ +syntax = "proto3"; + +package ibc.core.connection.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/commitment/v1/commitment.proto"; + +// ICS03 - Connection Data Structures as defined in +// https://github.com/cosmos/ibc/blob/master/spec/core/ics-003-connection-semantics#data-structures + +// ConnectionEnd defines a stateful object on a chain connected to another +// separate one. +// NOTE: there must only be 2 defined ConnectionEnds to establish +// a connection between two chains. +message ConnectionEnd { + option (gogoproto.goproto_getters) = false; + // client associated with this connection. + string client_id = 1; + // IBC version which can be utilised to determine encodings or protocols for + // channels or packets utilising this connection. + repeated Version versions = 2; + // current state of the connection end. + State state = 3; + // counterparty chain associated with this connection. + Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + // delay period that must pass before a consensus state can be used for + // packet-verification NOTE: delay period logic is only implemented by some + // clients. + uint64 delay_period = 5; +} + +// IdentifiedConnection defines a connection with additional connection +// identifier field. +message IdentifiedConnection { + option (gogoproto.goproto_getters) = false; + // connection identifier. + string id = 1; + // client associated with this connection. + string client_id = 2; + // IBC version which can be utilised to determine encodings or protocols for + // channels or packets utilising this connection + repeated Version versions = 3; + // current state of the connection end. + State state = 4; + // counterparty chain associated with this connection. + Counterparty counterparty = 5 [(gogoproto.nullable) = false]; + // delay period associated with this connection. + uint64 delay_period = 6; +} + +// State defines if a connection is in one of the following states: +// INIT, TRYOPEN, OPEN or UNINITIALIZED. +enum State { + option (gogoproto.goproto_enum_prefix) = false; + + // Default State + STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; + // A connection end has just started the opening handshake. + STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; + // A connection end has acknowledged the handshake step on the counterparty + // chain. + STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; + // A connection end has completed the handshake. + STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; +} + +// Counterparty defines the counterparty chain associated with a connection end. +message Counterparty { + option (gogoproto.goproto_getters) = false; + + // identifies the client on the counterparty chain associated with a given + // connection. + string client_id = 1; + // identifies the connection end on the counterparty chain associated with a + // given connection. + string connection_id = 2; + // commitment merkle prefix of the counterparty chain. + ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false]; +} + +// ClientPaths define all the connection paths for a client state. +message ClientPaths { + // list of connection paths + repeated string paths = 1; +} + +// ConnectionPaths define all the connection paths for a given client state. +message ConnectionPaths { + // client state unique identifier + string client_id = 1; + // list of connection paths + repeated string paths = 2; +} + +// Version defines the versioning scheme used to negotiate the IBC verison in +// the connection handshake. +message Version { + option (gogoproto.goproto_getters) = false; + + // unique version identifier + string identifier = 1; + // list of features compatible with the specified identifier + repeated string features = 2; +} + +// Params defines the set of Connection parameters. +message Params { + // maximum expected time per block (in nanoseconds), used to enforce block delay. This parameter should reflect the + // largest amount of time that the chain might reasonably take to produce the next block under normal operating + // conditions. A safe choice is 3-5x the expected time per block. + uint64 max_expected_time_per_block = 1; +} diff --git a/third_party/proto/ibc/connection/v1/genesis.proto b/third_party/proto/ibc/connection/v1/genesis.proto new file mode 100644 index 000000000..a5eb6b3a1 --- /dev/null +++ b/third_party/proto/ibc/connection/v1/genesis.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; + +package ibc.core.connection.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/connection/v1/connection.proto"; + +// GenesisState defines the ibc connection submodule's genesis state. +message GenesisState { + repeated IdentifiedConnection connections = 1 [(gogoproto.nullable) = false]; + repeated ConnectionPaths client_connection_paths = 2 [(gogoproto.nullable) = false]; + // the sequence for the next generated connection identifier + uint64 next_connection_sequence = 3; + Params params = 4 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/connection/v1/query.proto b/third_party/proto/ibc/connection/v1/query.proto new file mode 100644 index 000000000..c0f1a6f57 --- /dev/null +++ b/third_party/proto/ibc/connection/v1/query.proto @@ -0,0 +1,152 @@ +syntax = "proto3"; + +package ibc.core.connection.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/core/connection/v1/connection.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/any.proto"; + +// Query provides defines the gRPC querier service +service Query { + // Connection queries an IBC connection end. + rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}"; + } + + // Connections queries all the IBC connections of a chain. + rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/connections"; + } + + // ClientConnections queries the connection paths associated with a client + // state. + rpc ClientConnections(QueryClientConnectionsRequest) returns (QueryClientConnectionsResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/client_connections/{client_id}"; + } + + // ConnectionClientState queries the client state associated with the + // connection. + rpc ConnectionClientState(QueryConnectionClientStateRequest) returns (QueryConnectionClientStateResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/client_state"; + } + + // ConnectionConsensusState queries the consensus state associated with the + // connection. + rpc ConnectionConsensusState(QueryConnectionConsensusStateRequest) returns (QueryConnectionConsensusStateResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/consensus_state/" + "revision/{revision_number}/height/{revision_height}"; + } + + // ConnectionParams queries all parameters of the ibc connection submodule. + rpc ConnectionParams(QueryConnectionParamsRequest) returns (QueryConnectionParamsResponse) { + option (google.api.http).get = "/ibc/core/connection/v1/params"; + } +} + +// QueryConnectionRequest is the request type for the Query/Connection RPC +// method +message QueryConnectionRequest { + // connection unique identifier + string connection_id = 1; +} + +// QueryConnectionResponse is the response type for the Query/Connection RPC +// method. Besides the connection end, it includes a proof and the height from +// which the proof was retrieved. +message QueryConnectionResponse { + // connection associated with the request identifier + ibc.core.connection.v1.ConnectionEnd connection = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryConnectionsRequest is the request type for the Query/Connections RPC +// method +message QueryConnectionsRequest { + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryConnectionsResponse is the response type for the Query/Connections RPC +// method. +message QueryConnectionsResponse { + // list of stored connections of the chain. + repeated ibc.core.connection.v1.IdentifiedConnection connections = 1; + // pagination response + cosmos.base.query.v1beta1.PageResponse pagination = 2; + // query block height + ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; +} + +// QueryClientConnectionsRequest is the request type for the +// Query/ClientConnections RPC method +message QueryClientConnectionsRequest { + // client identifier associated with a connection + string client_id = 1; +} + +// QueryClientConnectionsResponse is the response type for the +// Query/ClientConnections RPC method +message QueryClientConnectionsResponse { + // slice of all the connection paths associated with a client. + repeated string connection_paths = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was generated + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryConnectionClientStateRequest is the request type for the +// Query/ConnectionClientState RPC method +message QueryConnectionClientStateRequest { + // connection identifier + string connection_id = 1; +} + +// QueryConnectionClientStateResponse is the response type for the +// Query/ConnectionClientState RPC method +message QueryConnectionClientStateResponse { + // client state associated with the channel + ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryConnectionConsensusStateRequest is the request type for the +// Query/ConnectionConsensusState RPC method +message QueryConnectionConsensusStateRequest { + // connection identifier + string connection_id = 1; + uint64 revision_number = 2; + uint64 revision_height = 3; +} + +// QueryConnectionConsensusStateResponse is the response type for the +// Query/ConnectionConsensusState RPC method +message QueryConnectionConsensusStateResponse { + // consensus state associated with the channel + google.protobuf.Any consensus_state = 1; + // client ID associated with the consensus state + string client_id = 2; + // merkle proof of existence + bytes proof = 3; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; +} + +// QueryConnectionParamsRequest is the request type for the Query/ConnectionParams RPC method. +message QueryConnectionParamsRequest {} + +// QueryConnectionParamsResponse is the response type for the Query/ConnectionParams RPC method. +message QueryConnectionParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/connection/v1/tx.proto b/third_party/proto/ibc/connection/v1/tx.proto new file mode 100644 index 000000000..3ba8ff456 --- /dev/null +++ b/third_party/proto/ibc/connection/v1/tx.proto @@ -0,0 +1,146 @@ +syntax = "proto3"; + +package ibc.core.connection.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "google/protobuf/any.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/core/connection/v1/connection.proto"; + +// Msg defines the ibc/connection Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit. + rpc ConnectionOpenInit(MsgConnectionOpenInit) returns (MsgConnectionOpenInitResponse); + + // ConnectionOpenTry defines a rpc handler method for MsgConnectionOpenTry. + rpc ConnectionOpenTry(MsgConnectionOpenTry) returns (MsgConnectionOpenTryResponse); + + // ConnectionOpenAck defines a rpc handler method for MsgConnectionOpenAck. + rpc ConnectionOpenAck(MsgConnectionOpenAck) returns (MsgConnectionOpenAckResponse); + + // ConnectionOpenConfirm defines a rpc handler method for + // MsgConnectionOpenConfirm. + rpc ConnectionOpenConfirm(MsgConnectionOpenConfirm) returns (MsgConnectionOpenConfirmResponse); + + // UpdateConnectionParams defines a rpc handler method for + // MsgUpdateParams. + rpc UpdateConnectionParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgConnectionOpenInit defines the msg sent by an account on Chain A to +// initialize a connection with Chain B. +message MsgConnectionOpenInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string client_id = 1; + Counterparty counterparty = 2 [(gogoproto.nullable) = false]; + Version version = 3; + uint64 delay_period = 4; + string signer = 5; +} + +// MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response +// type. +message MsgConnectionOpenInitResponse {} + +// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a +// connection on Chain B. +message MsgConnectionOpenTry { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string client_id = 1; + // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. + string previous_connection_id = 2 [deprecated = true]; + google.protobuf.Any client_state = 3; + Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + uint64 delay_period = 5; + repeated Version counterparty_versions = 6; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; + // proof of the initialization the connection on Chain A: `UNITIALIZED -> + // INIT` + bytes proof_init = 8; + // proof of client state included in message + bytes proof_client = 9; + // proof of client consensus state + bytes proof_consensus = 10; + ibc.core.client.v1.Height consensus_height = 11 [(gogoproto.nullable) = false]; + string signer = 12; + // optional proof data for host state machines that are unable to introspect their own consensus state + bytes host_consensus_state_proof = 13; +} + +// MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type. +message MsgConnectionOpenTryResponse {} + +// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to +// acknowledge the change of connection state to TRYOPEN on Chain B. +message MsgConnectionOpenAck { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string connection_id = 1; + string counterparty_connection_id = 2; + Version version = 3; + google.protobuf.Any client_state = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + // proof of the initialization the connection on Chain B: `UNITIALIZED -> + // TRYOPEN` + bytes proof_try = 6; + // proof of client state included in message + bytes proof_client = 7; + // proof of client consensus state + bytes proof_consensus = 8; + ibc.core.client.v1.Height consensus_height = 9 [(gogoproto.nullable) = false]; + string signer = 10; + // optional proof data for host state machines that are unable to introspect their own consensus state + bytes host_consensus_state_proof = 11; +} + +// MsgConnectionOpenAckResponse defines the Msg/ConnectionOpenAck response type. +message MsgConnectionOpenAckResponse {} + +// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to +// acknowledge the change of connection state to OPEN on Chain A. +message MsgConnectionOpenConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string connection_id = 1; + // proof for the change of the connection state on Chain A: `INIT -> OPEN` + bytes proof_ack = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + string signer = 4; +} + +// MsgConnectionOpenConfirmResponse defines the Msg/ConnectionOpenConfirm +// response type. +message MsgConnectionOpenConfirmResponse {} + +// MsgUpdateParams defines the sdk.Msg type to update the connection parameters. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the connection parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/core/channel/v1/channel.proto b/third_party/proto/ibc/core/channel/v1/channel.proto index eb073fd18..05a18fefb 100644 --- a/third_party/proto/ibc/core/channel/v1/channel.proto +++ b/third_party/proto/ibc/core/channel/v1/channel.proto @@ -21,9 +21,12 @@ message Channel { Counterparty counterparty = 3 [(gogoproto.nullable) = false]; // list of connection identifiers, in order, along which packets sent on // this channel will travel - repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""]; + repeated string connection_hops = 4; // opaque channel version, which is agreed upon during the handshake string version = 5; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 6; } // IdentifiedChannel defines a channel with additional port and channel @@ -39,17 +42,20 @@ message IdentifiedChannel { Counterparty counterparty = 3 [(gogoproto.nullable) = false]; // list of connection identifiers, in order, along which packets sent on // this channel will travel - repeated string connection_hops = 4 [(gogoproto.moretags) = "yaml:\"connection_hops\""]; + repeated string connection_hops = 4; // opaque channel version, which is agreed upon during the handshake string version = 5; // port identifier string port_id = 6; // channel identifier string channel_id = 7; + // upgrade sequence indicates the latest upgrade attempt performed by this channel + // the value of 0 indicates the channel has never been upgraded + uint64 upgrade_sequence = 8; } // State defines if a channel is in one of the following states: -// CLOSED, INIT, TRYOPEN, OPEN or UNINITIALIZED. +// CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. enum State { option (gogoproto.goproto_enum_prefix) = false; @@ -65,6 +71,10 @@ enum State { // A channel has been closed and can no longer be used to send or receive // packets. STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"]; + // A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. + STATE_FLUSHING = 5 [(gogoproto.enumvalue_customname) = "FLUSHING"]; + // A channel has just completed flushing any in-flight packets. + STATE_FLUSHCOMPLETE = 6 [(gogoproto.enumvalue_customname) = "FLUSHCOMPLETE"]; } // Order defines if a channel is ORDERED or UNORDERED @@ -85,9 +95,9 @@ message Counterparty { option (gogoproto.goproto_getters) = false; // port on the counterparty chain which owns the other end of the channel. - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // channel end on the counterparty chain - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; } // Packet defines a type that carries data across different chains through IBC @@ -99,20 +109,19 @@ message Packet { // with a later sequence number. uint64 sequence = 1; // identifies the port on the sending chain. - string source_port = 2 [(gogoproto.moretags) = "yaml:\"source_port\""]; + string source_port = 2; // identifies the channel end on the sending chain. - string source_channel = 3 [(gogoproto.moretags) = "yaml:\"source_channel\""]; + string source_channel = 3; // identifies the port on the receiving chain. - string destination_port = 4 [(gogoproto.moretags) = "yaml:\"destination_port\""]; + string destination_port = 4; // identifies the channel end on the receiving chain. - string destination_channel = 5 [(gogoproto.moretags) = "yaml:\"destination_channel\""]; + string destination_channel = 5; // actual opaque bytes transferred directly to the application module bytes data = 6; // block height after which the packet times out - ibc.core.client.v1.Height timeout_height = 7 - [(gogoproto.moretags) = "yaml:\"timeout_height\"", (gogoproto.nullable) = false]; + ibc.core.client.v1.Height timeout_height = 7 [(gogoproto.nullable) = false]; // block timestamp (in nanoseconds) after which the packet times out - uint64 timeout_timestamp = 8 [(gogoproto.moretags) = "yaml:\"timeout_timestamp\""]; + uint64 timeout_timestamp = 8; } // PacketState defines the generic type necessary to retrieve and store @@ -123,9 +132,9 @@ message PacketState { option (gogoproto.goproto_getters) = false; // channel port identifier. - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // channel unique identifier. - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; // packet sequence. uint64 sequence = 3; // embedded data that represents packet state. @@ -139,9 +148,9 @@ message PacketId { option (gogoproto.goproto_getters) = false; // channel port identifier - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // channel unique identifier - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; // packet sequence uint64 sequence = 3; } @@ -160,3 +169,19 @@ message Acknowledgement { string error = 22; } } + +// Timeout defines an execution deadline structure for 04-channel handlers. +// This includes packet lifecycle handlers as well as the upgrade handshake handlers. +// A valid Timeout contains either one or both of a timestamp and block height (sequence). +message Timeout { + // block height after which the packet or upgrade times out + ibc.core.client.v1.Height height = 1 [(gogoproto.nullable) = false]; + // block timestamp (in nanoseconds) after which the packet or upgrade times out + uint64 timestamp = 2; +} + +// Params defines the set of IBC channel parameters. +message Params { + // the relative timeout after which channel upgrades will time out. + Timeout upgrade_timeout = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/core/channel/v1/genesis.proto b/third_party/proto/ibc/core/channel/v1/genesis.proto index 813e98f36..665b2b156 100644 --- a/third_party/proto/ibc/core/channel/v1/genesis.proto +++ b/third_party/proto/ibc/core/channel/v1/genesis.proto @@ -13,20 +13,18 @@ message GenesisState { repeated PacketState acknowledgements = 2 [(gogoproto.nullable) = false]; repeated PacketState commitments = 3 [(gogoproto.nullable) = false]; repeated PacketState receipts = 4 [(gogoproto.nullable) = false]; - repeated PacketSequence send_sequences = 5 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"send_sequences\""]; - repeated PacketSequence recv_sequences = 6 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"recv_sequences\""]; - repeated PacketSequence ack_sequences = 7 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"ack_sequences\""]; + repeated PacketSequence send_sequences = 5 [(gogoproto.nullable) = false]; + repeated PacketSequence recv_sequences = 6 [(gogoproto.nullable) = false]; + repeated PacketSequence ack_sequences = 7 [(gogoproto.nullable) = false]; // the sequence for the next generated channel identifier - uint64 next_channel_sequence = 8 [(gogoproto.moretags) = "yaml:\"next_channel_sequence\""]; + uint64 next_channel_sequence = 8; + Params params = 9 [(gogoproto.nullable) = false]; } // PacketSequence defines the genesis type necessary to retrieve and store // next send and receive sequences. message PacketSequence { - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string port_id = 1; + string channel_id = 2; uint64 sequence = 3; } diff --git a/third_party/proto/ibc/core/channel/v1/query.proto b/third_party/proto/ibc/core/channel/v1/query.proto index 0170a2aac..f89d21273 100644 --- a/third_party/proto/ibc/core/channel/v1/query.proto +++ b/third_party/proto/ibc/core/channel/v1/query.proto @@ -10,6 +10,7 @@ import "ibc/core/channel/v1/channel.proto"; import "google/api/annotations.proto"; import "google/protobuf/any.proto"; import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/upgrade.proto"; // Query provides defines the gRPC querier service service Query { @@ -98,6 +99,29 @@ service Query { option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" "ports/{port_id}/next_sequence"; } + + // NextSequenceSend returns the next send sequence for a given channel. + rpc NextSequenceSend(QueryNextSequenceSendRequest) returns (QueryNextSequenceSendResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/next_sequence_send"; + } + + // UpgradeError returns the error receipt if the upgrade handshake failed. + rpc UpgradeError(QueryUpgradeErrorRequest) returns (QueryUpgradeErrorResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade_error"; + } + + // Upgrade returns the upgrade for a given port and channel id. + rpc Upgrade(QueryUpgradeRequest) returns (QueryUpgradeResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" + "ports/{port_id}/upgrade"; + } + + // ChannelParams queries all parameters of the ibc channel submodule. + rpc ChannelParams(QueryChannelParamsRequest) returns (QueryChannelParamsResponse) { + option (google.api.http).get = "/ibc/core/channel/v1/params"; + } } // QueryChannelRequest is the request type for the Query/Channel RPC method @@ -364,7 +388,7 @@ message QueryNextSequenceReceiveRequest { string channel_id = 2; } -// QuerySequenceResponse is the request type for the +// QuerySequenceResponse is the response type for the // Query/QueryNextSequenceReceiveResponse RPC method message QueryNextSequenceReceiveResponse { // next sequence receive number @@ -374,3 +398,62 @@ message QueryNextSequenceReceiveResponse { // height at which the proof was retrieved ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; } + +// QueryNextSequenceSendRequest is the request type for the +// Query/QueryNextSequenceSend RPC method +message QueryNextSequenceSendRequest { + // port unique identifier + string port_id = 1; + // channel unique identifier + string channel_id = 2; +} + +// QueryNextSequenceSendResponse is the request type for the +// Query/QueryNextSequenceSend RPC method +message QueryNextSequenceSendResponse { + // next sequence send number + uint64 next_sequence_send = 1; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeErrorRequest is the request type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeErrorResponse is the response type for the Query/QueryUpgradeError RPC method +message QueryUpgradeErrorResponse { + ErrorReceipt error_receipt = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryUpgradeRequest is the request type for the QueryUpgradeRequest RPC method +message QueryUpgradeRequest { + string port_id = 1; + string channel_id = 2; +} + +// QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC method +message QueryUpgradeResponse { + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + // merkle proof of existence + bytes proof = 2; + // height at which the proof was retrieved + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; +} + +// QueryChannelParamsRequest is the request type for the Query/ChannelParams RPC method. +message QueryChannelParamsRequest {} + +// QueryChannelParamsResponse is the response type for the Query/ChannelParams RPC method. +message QueryChannelParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/core/channel/v1/tx.proto b/third_party/proto/ibc/core/channel/v1/tx.proto index d0918eaff..3f30e8b8c 100644 --- a/third_party/proto/ibc/core/channel/v1/tx.proto +++ b/third_party/proto/ibc/core/channel/v1/tx.proto @@ -5,11 +5,15 @@ package ibc.core.channel.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/core/channel/v1/channel.proto"; +import "ibc/core/channel/v1/upgrade.proto"; // Msg defines the ibc/channel Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. rpc ChannelOpenInit(MsgChannelOpenInit) returns (MsgChannelOpenInitResponse); @@ -40,6 +44,33 @@ service Msg { // Acknowledgement defines a rpc handler method for MsgAcknowledgement. rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); + + // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. + rpc ChannelUpgradeInit(MsgChannelUpgradeInit) returns (MsgChannelUpgradeInitResponse); + + // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. + rpc ChannelUpgradeTry(MsgChannelUpgradeTry) returns (MsgChannelUpgradeTryResponse); + + // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. + rpc ChannelUpgradeAck(MsgChannelUpgradeAck) returns (MsgChannelUpgradeAckResponse); + + // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. + rpc ChannelUpgradeConfirm(MsgChannelUpgradeConfirm) returns (MsgChannelUpgradeConfirmResponse); + + // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. + rpc ChannelUpgradeOpen(MsgChannelUpgradeOpen) returns (MsgChannelUpgradeOpenResponse); + + // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. + rpc ChannelUpgradeTimeout(MsgChannelUpgradeTimeout) returns (MsgChannelUpgradeTimeoutResponse); + + // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. + rpc ChannelUpgradeCancel(MsgChannelUpgradeCancel) returns (MsgChannelUpgradeCancelResponse); + + // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. + rpc UpdateChannelParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); + + // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. + rpc PruneAcknowledgements(MsgPruneAcknowledgements) returns (MsgPruneAcknowledgementsResponse); } // ResponseResultType defines the possible outcomes of the execution of a message @@ -52,22 +83,27 @@ enum ResponseResultType { RESPONSE_RESULT_TYPE_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; // The message was executed successfully RESPONSE_RESULT_TYPE_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; + // The message was executed unsuccessfully + RESPONSE_RESULT_TYPE_FAILURE = 3 [(gogoproto.enumvalue_customname) = "FAILURE"]; } // MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It // is called by a relayer on Chain A. message MsgChannelOpenInit { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; Channel channel = 2 [(gogoproto.nullable) = false]; string signer = 3; } // MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. message MsgChannelOpenInitResponse { - string channel_id = 1 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + option (gogoproto.goproto_getters) = false; + + string channel_id = 1; string version = 2; } @@ -75,41 +111,46 @@ message MsgChannelOpenInitResponse { // on Chain B. The version field within the Channel field has been deprecated. Its // value will be ignored by core IBC. message MsgChannelOpenTry { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; + string port_id = 1; // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. - string previous_channel_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_channel_id\""]; + string previous_channel_id = 2 [deprecated = true]; // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. Channel channel = 3 [(gogoproto.nullable) = false]; - string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; - bytes proof_init = 5 [(gogoproto.moretags) = "yaml:\"proof_init\""]; - ibc.core.client.v1.Height proof_height = 6 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 7; + string counterparty_version = 4; + bytes proof_init = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; } // MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. message MsgChannelOpenTryResponse { + option (gogoproto.goproto_getters) = false; + string version = 1; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string channel_id = 2; } // MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge // the change of channel state to TRYOPEN on Chain B. +// WARNING: a channel upgrade MUST NOT initialize an upgrade for this channel +// in the same block as executing this message otherwise the counterparty will +// be incapable of opening. message MsgChannelOpenAck { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - string counterparty_channel_id = 3 [(gogoproto.moretags) = "yaml:\"counterparty_channel_id\""]; - string counterparty_version = 4 [(gogoproto.moretags) = "yaml:\"counterparty_version\""]; - bytes proof_try = 5 [(gogoproto.moretags) = "yaml:\"proof_try\""]; - ibc.core.client.v1.Height proof_height = 6 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 7; + string port_id = 1; + string channel_id = 2; + string counterparty_channel_id = 3; + string counterparty_version = 4; + bytes proof_try = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; } // MsgChannelOpenAckResponse defines the Msg/ChannelOpenAck response type. @@ -118,15 +159,15 @@ message MsgChannelOpenAckResponse {} // MsgChannelOpenConfirm defines a msg sent by a Relayer to Chain B to // acknowledge the change of channel state to OPEN on Chain A. message MsgChannelOpenConfirm { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - bytes proof_ack = 3 [(gogoproto.moretags) = "yaml:\"proof_ack\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; + string port_id = 1; + string channel_id = 2; + bytes proof_ack = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; } // MsgChannelOpenConfirmResponse defines the Msg/ChannelOpenConfirm response @@ -136,11 +177,12 @@ message MsgChannelOpenConfirmResponse {} // MsgChannelCloseInit defines a msg sent by a Relayer to Chain A // to close a channel with Chain B. message MsgChannelCloseInit { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; + string port_id = 1; + string channel_id = 2; string signer = 3; } @@ -150,15 +192,16 @@ message MsgChannelCloseInitResponse {} // MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B // to acknowledge the change of channel state to CLOSED on Chain A. message MsgChannelCloseConfirm { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string port_id = 1 [(gogoproto.moretags) = "yaml:\"port_id\""]; - string channel_id = 2 [(gogoproto.moretags) = "yaml:\"channel_id\""]; - bytes proof_init = 3 [(gogoproto.moretags) = "yaml:\"proof_init\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; + string port_id = 1; + string channel_id = 2; + bytes proof_init = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; + uint64 counterparty_upgrade_sequence = 6; } // MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response @@ -167,14 +210,14 @@ message MsgChannelCloseConfirmResponse {} // MsgRecvPacket receives incoming IBC packet message MsgRecvPacket { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_commitment = 2 [(gogoproto.moretags) = "yaml:\"proof_commitment\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 4; + bytes proof_commitment = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + string signer = 4; } // MsgRecvPacketResponse defines the Msg/RecvPacket response type. @@ -186,15 +229,15 @@ message MsgRecvPacketResponse { // MsgTimeout receives timed-out packet message MsgTimeout { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - uint64 next_sequence_recv = 4 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""]; - string signer = 5; + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_unreceived = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + uint64 next_sequence_recv = 4; + string signer = 5; } // MsgTimeoutResponse defines the Msg/Timeout response type. @@ -206,16 +249,17 @@ message MsgTimeoutResponse { // MsgTimeoutOnClose timed-out packet upon counterparty channel closure. message MsgTimeoutOnClose { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2 [(gogoproto.moretags) = "yaml:\"proof_unreceived\""]; - bytes proof_close = 3 [(gogoproto.moretags) = "yaml:\"proof_close\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - uint64 next_sequence_recv = 5 [(gogoproto.moretags) = "yaml:\"next_sequence_recv\""]; - string signer = 6; + Packet packet = 1 [(gogoproto.nullable) = false]; + bytes proof_unreceived = 2; + bytes proof_close = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + uint64 next_sequence_recv = 5; + string signer = 6; + uint64 counterparty_upgrade_sequence = 7; } // MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. @@ -227,15 +271,15 @@ message MsgTimeoutOnCloseResponse { // MsgAcknowledgement receives incoming IBC acknowledgement message MsgAcknowledgement { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; Packet packet = 1 [(gogoproto.nullable) = false]; bytes acknowledgement = 2; - bytes proof_acked = 3 [(gogoproto.moretags) = "yaml:\"proof_acked\""]; - ibc.core.client.v1.Height proof_height = 4 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 5; + bytes proof_acked = 3; + ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; + string signer = 5; } // MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. @@ -244,3 +288,182 @@ message MsgAcknowledgementResponse { ResponseResultType result = 1; } + +// MsgChannelUpgradeInit defines the request type for the ChannelUpgradeInit rpc +// WARNING: Initializing a channel upgrade in the same block as opening the channel +// may result in the counterparty being incapable of opening. +message MsgChannelUpgradeInit { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + UpgradeFields fields = 3 [(gogoproto.nullable) = false]; + string signer = 4; +} + +// MsgChannelUpgradeInitResponse defines the MsgChannelUpgradeInit response type +message MsgChannelUpgradeInitResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; +} + +// MsgChannelUpgradeTry defines the request type for the ChannelUpgradeTry rpc +message MsgChannelUpgradeTry { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + repeated string proposed_upgrade_connection_hops = 3; + UpgradeFields counterparty_upgrade_fields = 4 [(gogoproto.nullable) = false]; + uint64 counterparty_upgrade_sequence = 5; + bytes proof_channel = 6; + bytes proof_upgrade = 7; + ibc.core.client.v1.Height proof_height = 8 [(gogoproto.nullable) = false]; + string signer = 9; +} + +// MsgChannelUpgradeTryResponse defines the MsgChannelUpgradeTry response type +message MsgChannelUpgradeTryResponse { + option (gogoproto.goproto_getters) = false; + + Upgrade upgrade = 1 [(gogoproto.nullable) = false]; + uint64 upgrade_sequence = 2; + ResponseResultType result = 3; +} + +// MsgChannelUpgradeAck defines the request type for the ChannelUpgradeAck rpc +message MsgChannelUpgradeAck { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + Upgrade counterparty_upgrade = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + bytes proof_upgrade = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeAckResponse defines MsgChannelUpgradeAck response type +message MsgChannelUpgradeAckResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeConfirm defines the request type for the ChannelUpgradeConfirm rpc +message MsgChannelUpgradeConfirm { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + Upgrade counterparty_upgrade = 4 [(gogoproto.nullable) = false]; + bytes proof_channel = 5; + bytes proof_upgrade = 6; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; + string signer = 8; +} + +// MsgChannelUpgradeConfirmResponse defines MsgChannelUpgradeConfirm response type +message MsgChannelUpgradeConfirmResponse { + option (gogoproto.goproto_getters) = false; + + ResponseResultType result = 1; +} + +// MsgChannelUpgradeOpen defines the request type for the ChannelUpgradeOpen rpc +message MsgChannelUpgradeOpen { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + string port_id = 1; + string channel_id = 2; + State counterparty_channel_state = 3; + uint64 counterparty_upgrade_sequence = 4; + bytes proof_channel = 5; + ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; + string signer = 7; +} + +// MsgChannelUpgradeOpenResponse defines the MsgChannelUpgradeOpen response type +message MsgChannelUpgradeOpenResponse {} + +// MsgChannelUpgradeTimeout defines the request type for the ChannelUpgradeTimeout rpc +message MsgChannelUpgradeTimeout { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + Channel counterparty_channel = 3 [(gogoproto.nullable) = false]; + bytes proof_channel = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeTimeoutRepsonse defines the MsgChannelUpgradeTimeout response type +message MsgChannelUpgradeTimeoutResponse {} + +// MsgChannelUpgradeCancel defines the request type for the ChannelUpgradeCancel rpc +message MsgChannelUpgradeCancel { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + ErrorReceipt error_receipt = 3 [(gogoproto.nullable) = false]; + bytes proof_error_receipt = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; + string signer = 6; +} + +// MsgChannelUpgradeCancelResponse defines the MsgChannelUpgradeCancel response type +message MsgChannelUpgradeCancelResponse {} + +// MsgUpdateParams is the MsgUpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + option (gogoproto.goproto_getters) = false; + + // authority is the address that controls the module (defaults to x/gov unless overwritten). + string authority = 1; + + // params defines the channel parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} + +// MsgPruneAcknowledgements defines the request type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgements { + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; + + string port_id = 1; + string channel_id = 2; + uint64 limit = 3; + string signer = 4; +} + +// MsgPruneAcknowledgementsResponse defines the response type for the PruneAcknowledgements rpc. +message MsgPruneAcknowledgementsResponse { + // Number of sequences pruned (includes both packet acknowledgements and packet receipts where appropriate). + uint64 total_pruned_sequences = 1; + // Number of sequences left after pruning. + uint64 total_remaining_sequences = 2; +} diff --git a/third_party/proto/ibc/core/channel/v1/upgrade.proto b/third_party/proto/ibc/core/channel/v1/upgrade.proto new file mode 100644 index 000000000..81530ed2a --- /dev/null +++ b/third_party/proto/ibc/core/channel/v1/upgrade.proto @@ -0,0 +1,43 @@ +syntax = "proto3"; + +package ibc.core.channel.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Upgrade is a verifiable type which contains the relevant information +// for an attempted upgrade. It provides the proposed changes to the channel +// end, the timeout for this upgrade attempt and the next packet sequence +// which allows the counterparty to efficiently know the highest sequence it has received. +// The next sequence send is used for pruning and upgrading from unordered to ordered channels. +message Upgrade { + option (gogoproto.goproto_getters) = false; + + UpgradeFields fields = 1 [(gogoproto.nullable) = false]; + Timeout timeout = 2 [(gogoproto.nullable) = false]; + uint64 next_sequence_send = 3; +} + +// UpgradeFields are the fields in a channel end which may be changed +// during a channel upgrade. +message UpgradeFields { + option (gogoproto.goproto_getters) = false; + + Order ordering = 1; + repeated string connection_hops = 2; + string version = 3; +} + +// ErrorReceipt defines a type which encapsulates the upgrade sequence and error associated with the +// upgrade handshake failure. When a channel upgrade handshake is aborted both chains are expected to increment to the +// next sequence. +message ErrorReceipt { + option (gogoproto.goproto_getters) = false; + + // the channel upgrade sequence + uint64 sequence = 1; + // the error message detailing the cause of failure + string message = 2; +} diff --git a/third_party/proto/ibc/core/client/v1/client.proto b/third_party/proto/ibc/core/client/v1/client.proto index b9f6b1ca1..7a09e360a 100644 --- a/third_party/proto/ibc/core/client/v1/client.proto +++ b/third_party/proto/ibc/core/client/v1/client.proto @@ -4,18 +4,18 @@ package ibc.core.client.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; import "cosmos/upgrade/v1beta1/upgrade.proto"; import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; // IdentifiedClientState defines a client state with an additional client // identifier field. message IdentifiedClientState { // client identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 2; } // ConsensusStateWithHeight defines a consensus state with an additional height @@ -24,26 +24,58 @@ message ConsensusStateWithHeight { // consensus state height Height height = 1 [(gogoproto.nullable) = false]; // consensus state - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + google.protobuf.Any consensus_state = 2; } // ClientConsensusStates defines all the stored consensus states for a given // client. message ClientConsensusStates { // client identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // consensus states and their heights associated with the client - repeated ConsensusStateWithHeight consensus_states = 2 - [(gogoproto.moretags) = "yaml:\"consensus_states\"", (gogoproto.nullable) = false]; + repeated ConsensusStateWithHeight consensus_states = 2 [(gogoproto.nullable) = false]; +} + +// Height is a monotonically increasing data type +// that can be compared against another Height for the purposes of updating and +// freezing clients +// +// Normally the RevisionHeight is incremented at each height while keeping +// RevisionNumber the same. However some consensus algorithms may choose to +// reset the height in certain conditions e.g. hard forks, state-machine +// breaking changes In these cases, the RevisionNumber is incremented so that +// height continues to be monitonically increasing even as the RevisionHeight +// gets reset +message Height { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + + // the revision that the client is currently on + uint64 revision_number = 1; + // the height within the given revision + uint64 revision_height = 2; +} + +// Params defines the set of IBC light client parameters. +message Params { + // allowed_clients defines the list of allowed client state types which can be created + // and interacted with. If a client type is removed from the allowed clients list, usage + // of this client will be disabled until it is added again to the list. + repeated string allowed_clients = 1; } -// ClientUpdateProposal is a governance proposal. If it passes, the substitute +// ClientUpdateProposal is a legacy governance proposal. If it passes, the substitute // client's latest consensus state is copied over to the subject client. The proposal // handler may fail if the subject and the substitute do not match in client and // chain parameters (with exception to latest height, frozen height, and chain-id). +// +// Deprecated: Please use MsgRecoverClient in favour of this message type. message ClientUpdateProposal { - option (gogoproto.goproto_getters) = false; + option deprecated = true; + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; + option (gogoproto.goproto_getters) = false; + // the title of the update proposal string title = 1; // the description of the proposal @@ -57,11 +89,15 @@ message ClientUpdateProposal { // UpgradeProposal is a gov Content type for initiating an IBC breaking // upgrade. +// +// Deprecated: Please use MsgIBCSoftwareUpgrade in favour of this message type. message UpgradeProposal { + option deprecated = true; + + option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; option (gogoproto.goproto_getters) = false; option (gogoproto.goproto_stringer) = false; option (gogoproto.equal) = true; - option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; string title = 1; string description = 2; @@ -75,31 +111,3 @@ message UpgradeProposal { // planned chain upgrades google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; } - -// Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and -// freezing clients -// -// Normally the RevisionHeight is incremented at each height while keeping -// RevisionNumber the same. However some consensus algorithms may choose to -// reset the height in certain conditions e.g. hard forks, state-machine -// breaking changes In these cases, the RevisionNumber is incremented so that -// height continues to be monitonically increasing even as the RevisionHeight -// gets reset -message Height { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // the revision that the client is currently on - uint64 revision_number = 1 [(gogoproto.moretags) = "yaml:\"revision_number\""]; - // the height within the given revision - uint64 revision_height = 2 [(gogoproto.moretags) = "yaml:\"revision_height\""]; -} - -// Params defines the set of IBC light client parameters. -message Params { - // allowed_clients defines the list of allowed client state types which can be created - // and interacted with. If a client type is removed from the allowed clients list, usage - // of this client will be disabled until it is added again to the list. - repeated string allowed_clients = 1 [(gogoproto.moretags) = "yaml:\"allowed_clients\""]; -} diff --git a/third_party/proto/ibc/core/client/v1/genesis.proto b/third_party/proto/ibc/core/client/v1/genesis.proto index b09ff1eaf..43610b0d4 100644 --- a/third_party/proto/ibc/core/client/v1/genesis.proto +++ b/third_party/proto/ibc/core/client/v1/genesis.proto @@ -13,19 +13,16 @@ message GenesisState { repeated IdentifiedClientState clients = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; // consensus states from each client - repeated ClientConsensusStates clients_consensus = 2 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "ClientsConsensusStates", - (gogoproto.moretags) = "yaml:\"clients_consensus\"" - ]; + repeated ClientConsensusStates clients_consensus = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "ClientsConsensusStates"]; // metadata from each client - repeated IdentifiedGenesisMetadata clients_metadata = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"clients_metadata\""]; - Params params = 4 [(gogoproto.nullable) = false]; - // create localhost on initialization - bool create_localhost = 5 [(gogoproto.moretags) = "yaml:\"create_localhost\""]; + repeated IdentifiedGenesisMetadata clients_metadata = 3 [(gogoproto.nullable) = false]; + Params params = 4 [(gogoproto.nullable) = false]; + // Deprecated: create_localhost has been deprecated. + // The localhost client is automatically created at genesis. + bool create_localhost = 5 [deprecated = true]; // the sequence for the next generated client identifier - uint64 next_client_sequence = 6 [(gogoproto.moretags) = "yaml:\"next_client_sequence\""]; + uint64 next_client_sequence = 6; } // GenesisMetadata defines the genesis type for metadata that clients may return @@ -42,7 +39,6 @@ message GenesisMetadata { // IdentifiedGenesisMetadata has the client metadata with the corresponding // client id. message IdentifiedGenesisMetadata { - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; - repeated GenesisMetadata client_metadata = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_metadata\""]; + string client_id = 1; + repeated GenesisMetadata client_metadata = 2 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/core/client/v1/tx.proto b/third_party/proto/ibc/core/client/v1/tx.proto index 752718c11..b504ab692 100644 --- a/third_party/proto/ibc/core/client/v1/tx.proto +++ b/third_party/proto/ibc/core/client/v1/tx.proto @@ -4,11 +4,16 @@ package ibc.core.client.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos/upgrade/v1beta1/upgrade.proto"; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; +import "ibc/core/client/v1/client.proto"; // Msg defines the ibc/client Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // CreateClient defines a rpc handler method for MsgCreateClient. rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse); @@ -20,18 +25,28 @@ service Msg { // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); + + // RecoverClient defines a rpc handler method for MsgRecoverClient. + rpc RecoverClient(MsgRecoverClient) returns (MsgRecoverClientResponse); + + // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. + rpc IBCSoftwareUpgrade(MsgIBCSoftwareUpgrade) returns (MsgIBCSoftwareUpgradeResponse); + + // UpdateClientParams defines a rpc handler method for MsgUpdateParams. + rpc UpdateClientParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } // MsgCreateClient defines a message to create an IBC client message MsgCreateClient { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; // light client state - google.protobuf.Any client_state = 1 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 1; // consensus state associated with the client that corresponds to a given // height. - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + google.protobuf.Any consensus_state = 2; // signer address string signer = 3; } @@ -42,11 +57,12 @@ message MsgCreateClientResponse {} // MsgUpdateClient defines an sdk.Msg to update a IBC client state using // the given client message. message MsgUpdateClient { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // client message to update the light client google.protobuf.Any client_message = 2; // signer address @@ -59,20 +75,21 @@ message MsgUpdateClientResponse {} // MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client // state message MsgUpgradeClient { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // upgraded client state - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 2; // upgraded consensus state, only contains enough information to serve as a // basis of trust in update logic - google.protobuf.Any consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + google.protobuf.Any consensus_state = 3; // proof that old chain committed to new client - bytes proof_upgrade_client = 4 [(gogoproto.moretags) = "yaml:\"proof_upgrade_client\""]; + bytes proof_upgrade_client = 4; // proof that old chain committed to new consensus state - bytes proof_upgrade_consensus_state = 5 [(gogoproto.moretags) = "yaml:\"proof_upgrade_consensus_state\""]; + bytes proof_upgrade_consensus_state = 5; // signer address string signer = 6; } @@ -82,19 +99,77 @@ message MsgUpgradeClientResponse {} // MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for // light client misbehaviour. -// Warning: DEPRECATED +// This message has been deprecated. Use MsgUpdateClient instead. message MsgSubmitMisbehaviour { - option (gogoproto.equal) = false; + option deprecated = true; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; // client unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\"", deprecated = true]; + string client_id = 1; // misbehaviour used for freezing the light client - google.protobuf.Any misbehaviour = 2 [deprecated = true]; + google.protobuf.Any misbehaviour = 2; // signer address - string signer = 3 [deprecated = true]; + string signer = 3; } // MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response // type. message MsgSubmitMisbehaviourResponse {} + +// MsgRecoverClient defines the message used to recover a frozen or expired client. +message MsgRecoverClient { + option (gogoproto.goproto_getters) = false; + option (cosmos.msg.v1.signer) = "signer"; + + // the client identifier for the client to be updated if the proposal passes + string subject_client_id = 1; + // the substitute client identifier for the client which will replace the subject + // client + string substitute_client_id = 2; + + // signer address + string signer = 3; +} + +// MsgRecoverClientResponse defines the Msg/RecoverClient response type. +message MsgRecoverClientResponse {} + +// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal +message MsgIBCSoftwareUpgrade { + option (cosmos.msg.v1.signer) = "signer"; + cosmos.upgrade.v1beta1.Plan plan = 1 [(gogoproto.nullable) = false]; + // An UpgradedClientState must be provided to perform an IBC breaking upgrade. + // This will make the chain commit to the correct upgraded (self) client state + // before the upgrade occurs, so that connecting chains can verify that the + // new upgraded client is valid by verifying a proof on the previous version + // of the chain. This will allow IBC connections to persist smoothly across + // planned chain upgrades. Correspondingly, the UpgradedClientState field has been + // deprecated in the Cosmos SDK to allow for this logic to exist solely in + // the 02-client module. + google.protobuf.Any upgraded_client_state = 2; + // signer address + string signer = 3; +} + +// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. +message MsgIBCSoftwareUpgradeResponse {} + +// MsgUpdateParams defines the sdk.Msg type to update the client parameters. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the client parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/core/commitment/v1/commitment.proto b/third_party/proto/ibc/core/commitment/v1/commitment.proto index 60abc5d1c..b4753be2d 100644 --- a/third_party/proto/ibc/core/commitment/v1/commitment.proto +++ b/third_party/proto/ibc/core/commitment/v1/commitment.proto @@ -19,16 +19,14 @@ message MerkleRoot { // The constructed key from the Path and the key will be append(Path.KeyPath, // append(Path.KeyPrefix, key...)) message MerklePrefix { - bytes key_prefix = 1 [(gogoproto.moretags) = "yaml:\"key_prefix\""]; + bytes key_prefix = 1; } // MerklePath is the path used to verify commitment proofs, which can be an // arbitrary structured object (defined by a commitment type). // MerklePath is represented from root-to-leaf message MerklePath { - option (gogoproto.goproto_stringer) = false; - - repeated string key_path = 1 [(gogoproto.moretags) = "yaml:\"key_path\""]; + repeated string key_path = 1; } // MerkleProof is a wrapper type over a chain of CommitmentProofs. diff --git a/third_party/proto/ibc/core/connection/v1/connection.proto b/third_party/proto/ibc/core/connection/v1/connection.proto index 2cec817a0..852f3999b 100644 --- a/third_party/proto/ibc/core/connection/v1/connection.proto +++ b/third_party/proto/ibc/core/connection/v1/connection.proto @@ -17,7 +17,7 @@ import "ibc/core/commitment/v1/commitment.proto"; message ConnectionEnd { option (gogoproto.goproto_getters) = false; // client associated with this connection. - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // IBC version which can be utilised to determine encodings or protocols for // channels or packets utilising this connection. repeated Version versions = 2; @@ -28,7 +28,7 @@ message ConnectionEnd { // delay period that must pass before a consensus state can be used for // packet-verification NOTE: delay period logic is only implemented by some // clients. - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + uint64 delay_period = 5; } // IdentifiedConnection defines a connection with additional connection @@ -36,9 +36,9 @@ message ConnectionEnd { message IdentifiedConnection { option (gogoproto.goproto_getters) = false; // connection identifier. - string id = 1 [(gogoproto.moretags) = "yaml:\"id\""]; + string id = 1; // client associated with this connection. - string client_id = 2 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 2; // IBC version which can be utilised to determine encodings or protocols for // channels or packets utilising this connection repeated Version versions = 3; @@ -47,7 +47,7 @@ message IdentifiedConnection { // counterparty chain associated with this connection. Counterparty counterparty = 5 [(gogoproto.nullable) = false]; // delay period associated with this connection. - uint64 delay_period = 6 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + uint64 delay_period = 6; } // State defines if a connection is in one of the following states: @@ -72,10 +72,10 @@ message Counterparty { // identifies the client on the counterparty chain associated with a given // connection. - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // identifies the connection end on the counterparty chain associated with a // given connection. - string connection_id = 2 [(gogoproto.moretags) = "yaml:\"connection_id\""]; + string connection_id = 2; // commitment merkle prefix of the counterparty chain. ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false]; } @@ -89,7 +89,7 @@ message ClientPaths { // ConnectionPaths define all the connection paths for a given client state. message ConnectionPaths { // client state unique identifier - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // list of connection paths repeated string paths = 2; } @@ -110,5 +110,5 @@ message Params { // maximum expected time per block (in nanoseconds), used to enforce block delay. This parameter should reflect the // largest amount of time that the chain might reasonably take to produce the next block under normal operating // conditions. A safe choice is 3-5x the expected time per block. - uint64 max_expected_time_per_block = 1 [(gogoproto.moretags) = "yaml:\"max_expected_time_per_block\""]; + uint64 max_expected_time_per_block = 1; } diff --git a/third_party/proto/ibc/core/connection/v1/genesis.proto b/third_party/proto/ibc/core/connection/v1/genesis.proto index 830bbe138..a5eb6b3a1 100644 --- a/third_party/proto/ibc/core/connection/v1/genesis.proto +++ b/third_party/proto/ibc/core/connection/v1/genesis.proto @@ -10,9 +10,8 @@ import "ibc/core/connection/v1/connection.proto"; // GenesisState defines the ibc connection submodule's genesis state. message GenesisState { repeated IdentifiedConnection connections = 1 [(gogoproto.nullable) = false]; - repeated ConnectionPaths client_connection_paths = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_connection_paths\""]; + repeated ConnectionPaths client_connection_paths = 2 [(gogoproto.nullable) = false]; // the sequence for the next generated connection identifier - uint64 next_connection_sequence = 3 [(gogoproto.moretags) = "yaml:\"next_connection_sequence\""]; + uint64 next_connection_sequence = 3; Params params = 4 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/core/connection/v1/query.proto b/third_party/proto/ibc/core/connection/v1/query.proto index d1e120c92..c0f1a6f57 100644 --- a/third_party/proto/ibc/core/connection/v1/query.proto +++ b/third_party/proto/ibc/core/connection/v1/query.proto @@ -106,7 +106,7 @@ message QueryClientConnectionsResponse { // Query/ConnectionClientState RPC method message QueryConnectionClientStateRequest { // connection identifier - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; + string connection_id = 1; } // QueryConnectionClientStateResponse is the response type for the @@ -124,7 +124,7 @@ message QueryConnectionClientStateResponse { // Query/ConnectionConsensusState RPC method message QueryConnectionConsensusStateRequest { // connection identifier - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; + string connection_id = 1; uint64 revision_number = 2; uint64 revision_height = 3; } diff --git a/third_party/proto/ibc/core/connection/v1/tx.proto b/third_party/proto/ibc/core/connection/v1/tx.proto index d2ef2b914..3ba8ff456 100644 --- a/third_party/proto/ibc/core/connection/v1/tx.proto +++ b/third_party/proto/ibc/core/connection/v1/tx.proto @@ -5,12 +5,15 @@ package ibc.core.connection.v1; option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; import "google/protobuf/any.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/core/connection/v1/connection.proto"; // Msg defines the ibc/connection Msg service. service Msg { + option (cosmos.msg.v1.service) = true; + // ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit. rpc ConnectionOpenInit(MsgConnectionOpenInit) returns (MsgConnectionOpenInitResponse); @@ -23,18 +26,23 @@ service Msg { // ConnectionOpenConfirm defines a rpc handler method for // MsgConnectionOpenConfirm. rpc ConnectionOpenConfirm(MsgConnectionOpenConfirm) returns (MsgConnectionOpenConfirmResponse); + + // UpdateConnectionParams defines a rpc handler method for + // MsgUpdateParams. + rpc UpdateConnectionParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); } // MsgConnectionOpenInit defines the msg sent by an account on Chain A to // initialize a connection with Chain B. message MsgConnectionOpenInit { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; Counterparty counterparty = 2 [(gogoproto.nullable) = false]; Version version = 3; - uint64 delay_period = 4 [(gogoproto.moretags) = "yaml:\"delay_period\""]; + uint64 delay_period = 4; string signer = 5; } @@ -45,28 +53,27 @@ message MsgConnectionOpenInitResponse {} // MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a // connection on Chain B. message MsgConnectionOpenTry { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. - string previous_connection_id = 2 [deprecated = true, (gogoproto.moretags) = "yaml:\"previous_connection_id\""]; - google.protobuf.Any client_state = 3 [(gogoproto.moretags) = "yaml:\"client_state\""]; - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - uint64 delay_period = 5 [(gogoproto.moretags) = "yaml:\"delay_period\""]; - repeated Version counterparty_versions = 6 [(gogoproto.moretags) = "yaml:\"counterparty_versions\""]; - ibc.core.client.v1.Height proof_height = 7 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; + string previous_connection_id = 2 [deprecated = true]; + google.protobuf.Any client_state = 3; + Counterparty counterparty = 4 [(gogoproto.nullable) = false]; + uint64 delay_period = 5; + repeated Version counterparty_versions = 6; + ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; // proof of the initialization the connection on Chain A: `UNITIALIZED -> // INIT` - bytes proof_init = 8 [(gogoproto.moretags) = "yaml:\"proof_init\""]; + bytes proof_init = 8; // proof of client state included in message - bytes proof_client = 9 [(gogoproto.moretags) = "yaml:\"proof_client\""]; + bytes proof_client = 9; // proof of client consensus state - bytes proof_consensus = 10 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; - ibc.core.client.v1.Height consensus_height = 11 - [(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false]; - string signer = 12; + bytes proof_consensus = 10; + ibc.core.client.v1.Height consensus_height = 11 [(gogoproto.nullable) = false]; + string signer = 12; // optional proof data for host state machines that are unable to introspect their own consensus state bytes host_consensus_state_proof = 13; } @@ -77,25 +84,24 @@ message MsgConnectionOpenTryResponse {} // MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to // acknowledge the change of connection state to TRYOPEN on Chain B. message MsgConnectionOpenAck { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; - string counterparty_connection_id = 2 [(gogoproto.moretags) = "yaml:\"counterparty_connection_id\""]; - Version version = 3; - google.protobuf.Any client_state = 4 [(gogoproto.moretags) = "yaml:\"client_state\""]; - ibc.core.client.v1.Height proof_height = 5 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; + string connection_id = 1; + string counterparty_connection_id = 2; + Version version = 3; + google.protobuf.Any client_state = 4; + ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; // proof of the initialization the connection on Chain B: `UNITIALIZED -> // TRYOPEN` - bytes proof_try = 6 [(gogoproto.moretags) = "yaml:\"proof_try\""]; + bytes proof_try = 6; // proof of client state included in message - bytes proof_client = 7 [(gogoproto.moretags) = "yaml:\"proof_client\""]; + bytes proof_client = 7; // proof of client consensus state - bytes proof_consensus = 8 [(gogoproto.moretags) = "yaml:\"proof_consensus\""]; - ibc.core.client.v1.Height consensus_height = 9 - [(gogoproto.moretags) = "yaml:\"consensus_height\"", (gogoproto.nullable) = false]; - string signer = 10; + bytes proof_consensus = 8; + ibc.core.client.v1.Height consensus_height = 9 [(gogoproto.nullable) = false]; + string signer = 10; // optional proof data for host state machines that are unable to introspect their own consensus state bytes host_consensus_state_proof = 11; } @@ -106,17 +112,35 @@ message MsgConnectionOpenAckResponse {} // MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to // acknowledge the change of connection state to OPEN on Chain A. message MsgConnectionOpenConfirm { - option (gogoproto.equal) = false; + option (cosmos.msg.v1.signer) = "signer"; + option (gogoproto.goproto_getters) = false; - string connection_id = 1 [(gogoproto.moretags) = "yaml:\"connection_id\""]; + string connection_id = 1; // proof for the change of the connection state on Chain A: `INIT -> OPEN` - bytes proof_ack = 2 [(gogoproto.moretags) = "yaml:\"proof_ack\""]; - ibc.core.client.v1.Height proof_height = 3 - [(gogoproto.moretags) = "yaml:\"proof_height\"", (gogoproto.nullable) = false]; - string signer = 4; + bytes proof_ack = 2; + ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; + string signer = 4; } // MsgConnectionOpenConfirmResponse defines the Msg/ConnectionOpenConfirm // response type. message MsgConnectionOpenConfirmResponse {} + +// MsgUpdateParams defines the sdk.Msg type to update the connection parameters. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the connection parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the MsgUpdateParams response type. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/core/types/v1/genesis.proto b/third_party/proto/ibc/core/types/v1/genesis.proto index 51c227916..4b34f6889 100644 --- a/third_party/proto/ibc/core/types/v1/genesis.proto +++ b/third_party/proto/ibc/core/types/v1/genesis.proto @@ -12,12 +12,9 @@ import "ibc/core/channel/v1/genesis.proto"; // GenesisState defines the ibc module's genesis state. message GenesisState { // ICS002 - Clients genesis state - ibc.core.client.v1.GenesisState client_genesis = 1 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"client_genesis\""]; + ibc.core.client.v1.GenesisState client_genesis = 1 [(gogoproto.nullable) = false]; // ICS003 - Connections genesis state - ibc.core.connection.v1.GenesisState connection_genesis = 2 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"connection_genesis\""]; + ibc.core.connection.v1.GenesisState connection_genesis = 2 [(gogoproto.nullable) = false]; // ICS004 - Channel genesis state - ibc.core.channel.v1.GenesisState channel_genesis = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"channel_genesis\""]; + ibc.core.channel.v1.GenesisState channel_genesis = 3 [(gogoproto.nullable) = false]; } diff --git a/third_party/proto/ibc/fee/v1/ack.proto b/third_party/proto/ibc/fee/v1/ack.proto new file mode 100644 index 000000000..2f3746d2c --- /dev/null +++ b/third_party/proto/ibc/fee/v1/ack.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware +message IncentivizedAcknowledgement { + // the underlying app acknowledgement bytes + bytes app_acknowledgement = 1; + // the relayer address which submits the recv packet message + string forward_relayer_address = 2; + // success flag of the base application callback + bool underlying_app_success = 3; +} diff --git a/third_party/proto/ibc/fee/v1/fee.proto b/third_party/proto/ibc/fee/v1/fee.proto new file mode 100644 index 000000000..867e88455 --- /dev/null +++ b/third_party/proto/ibc/fee/v1/fee.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +import "amino/amino.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "cosmos/msg/v1/msg.proto"; + +// Fee defines the ICS29 receive, acknowledgement and timeout fees +message Fee { + // the packet receive fee + repeated cosmos.base.v1beta1.Coin recv_fee = 1 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" + ]; + + // the packet acknowledgement fee + repeated cosmos.base.v1beta1.Coin ack_fee = 2 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" + ]; + + // the packet timeout fee + repeated cosmos.base.v1beta1.Coin timeout_fee = 3 [ + (gogoproto.nullable) = false, + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", + (amino.encoding) = "legacy_coins" + ]; +} + +// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers +message PacketFee { + option (cosmos.msg.v1.signer) = "refund_address"; + + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + Fee fee = 1 [(gogoproto.nullable) = false]; + // the refund address for unspent fees + string refund_address = 2; + // optional list of relayers permitted to receive fees + repeated string relayers = 3; +} + +// PacketFees contains a list of type PacketFee +message PacketFees { + // list of packet fees + repeated PacketFee packet_fees = 1 [(gogoproto.nullable) = false]; +} + +// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId +message IdentifiedPacketFees { + // unique packet identifier comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; + // list of packet fees + repeated PacketFee packet_fees = 2 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/fee/v1/genesis.proto b/third_party/proto/ibc/fee/v1/genesis.proto new file mode 100644 index 000000000..e48ceb535 --- /dev/null +++ b/third_party/proto/ibc/fee/v1/genesis.proto @@ -0,0 +1,60 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// GenesisState defines the ICS29 fee middleware genesis state +message GenesisState { + // list of identified packet fees + repeated IdentifiedPacketFees identified_fees = 1 [(gogoproto.nullable) = false]; + // list of fee enabled channels + repeated FeeEnabledChannel fee_enabled_channels = 2 [(gogoproto.nullable) = false]; + // list of registered payees + repeated RegisteredPayee registered_payees = 3 [(gogoproto.nullable) = false]; + // list of registered counterparty payees + repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 [(gogoproto.nullable) = false]; + // list of forward relayer addresses + repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.nullable) = false]; +} + +// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel +message FeeEnabledChannel { + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; +} + +// RegisteredPayee contains the relayer address and payee address for a specific channel +message RegisteredPayee { + // unique channel identifier + string channel_id = 1; + // the relayer address + string relayer = 2; + // the payee address + string payee = 3; +} + +// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used +// for recv fee distribution) +message RegisteredCounterpartyPayee { + // unique channel identifier + string channel_id = 1; + // the relayer address + string relayer = 2; + // the counterparty payee address + string counterparty_payee = 3; +} + +// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements +message ForwardRelayerAddress { + // the forward relayer address + string address = 1; + // unique packet identifer comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 2 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/fee/v1/metadata.proto b/third_party/proto/ibc/fee/v1/metadata.proto new file mode 100644 index 000000000..1e82e7c25 --- /dev/null +++ b/third_party/proto/ibc/fee/v1/metadata.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring +// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning +message Metadata { + // fee_version defines the ICS29 fee version + string fee_version = 1; + // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring + string app_version = 2; +} diff --git a/third_party/proto/ibc/fee/v1/query.proto b/third_party/proto/ibc/fee/v1/query.proto new file mode 100644 index 000000000..726370ee0 --- /dev/null +++ b/third_party/proto/ibc/fee/v1/query.proto @@ -0,0 +1,218 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/applications/fee/v1/genesis.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Query defines the ICS29 gRPC querier service. +service Query { + // IncentivizedPackets returns all incentivized packets and their associated fees + rpc IncentivizedPackets(QueryIncentivizedPacketsRequest) returns (QueryIncentivizedPacketsResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets"; + } + + // IncentivizedPacket returns all packet fees for a packet given its identifier + rpc IncentivizedPacket(QueryIncentivizedPacketRequest) returns (QueryIncentivizedPacketResponse) { + option (google.api.http).get = + "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/" + "{packet_id.sequence}/incentivized_packet"; + } + + // Gets all incentivized packets for a specific channel + rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) + returns (QueryIncentivizedPacketsForChannelResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets"; + } + + // TotalRecvFees returns the total receive fees for a packet given its identifier + rpc TotalRecvFees(QueryTotalRecvFeesRequest) returns (QueryTotalRecvFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_recv_fees"; + } + + // TotalAckFees returns the total acknowledgement fees for a packet given its identifier + rpc TotalAckFees(QueryTotalAckFeesRequest) returns (QueryTotalAckFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_ack_fees"; + } + + // TotalTimeoutFees returns the total timeout fees for a packet given its identifier + rpc TotalTimeoutFees(QueryTotalTimeoutFeesRequest) returns (QueryTotalTimeoutFeesResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" + "sequences/{packet_id.sequence}/total_timeout_fees"; + } + + // Payee returns the registered payee address for a specific channel given the relayer address + rpc Payee(QueryPayeeRequest) returns (QueryPayeeResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee"; + } + + // CounterpartyPayee returns the registered counterparty payee for forward relaying + rpc CounterpartyPayee(QueryCounterpartyPayeeRequest) returns (QueryCounterpartyPayeeResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee"; + } + + // FeeEnabledChannels returns a list of all fee enabled channels + rpc FeeEnabledChannels(QueryFeeEnabledChannelsRequest) returns (QueryFeeEnabledChannelsResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled"; + } + + // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel + rpc FeeEnabledChannel(QueryFeeEnabledChannelRequest) returns (QueryFeeEnabledChannelResponse) { + option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled"; + } +} + +// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc +message QueryIncentivizedPacketsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + // block height at which to query + uint64 query_height = 2; +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc +message QueryIncentivizedPacketsResponse { + // list of identified fees for incentivized packets + repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc +message QueryIncentivizedPacketRequest { + // unique packet identifier comprised of channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; + // block height at which to query + uint64 query_height = 2; +} + +// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc +message QueryIncentivizedPacketResponse { + // the identified fees for the incentivized packet + ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packet = 1 [(gogoproto.nullable) = false]; +} + +// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets +// for a specific channel +message QueryIncentivizedPacketsForChannelRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + string port_id = 2; + string channel_id = 3; + // Height to query at + uint64 query_height = 4; +} + +// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC +message QueryIncentivizedPacketsForChannelResponse { + // Map of all incentivized_packets + repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc +message QueryTotalRecvFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc +message QueryTotalRecvFeesResponse { + // the total packet receive fees + repeated cosmos.base.v1beta1.Coin recv_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc +message QueryTotalAckFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc +message QueryTotalAckFeesResponse { + // the total packet acknowledgement fees + repeated cosmos.base.v1beta1.Coin ack_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc +message QueryTotalTimeoutFeesRequest { + // the packet identifier for the associated fees + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; +} + +// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc +message QueryTotalTimeoutFeesResponse { + // the total packet timeout fees + repeated cosmos.base.v1beta1.Coin timeout_fees = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; +} + +// QueryPayeeRequest defines the request type for the Payee rpc +message QueryPayeeRequest { + // unique channel identifier + string channel_id = 1; + // the relayer address to which the distribution address is registered + string relayer = 2; +} + +// QueryPayeeResponse defines the response type for the Payee rpc +message QueryPayeeResponse { + // the payee address to which packet fees are paid out + string payee_address = 1; +} + +// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc +message QueryCounterpartyPayeeRequest { + // unique channel identifier + string channel_id = 1; + // the relayer address to which the counterparty is registered + string relayer = 2; +} + +// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc +message QueryCounterpartyPayeeResponse { + // the counterparty payee address used to compensate forward relaying + string counterparty_payee = 1; +} + +// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc +message QueryFeeEnabledChannelsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; + // block height at which to query + uint64 query_height = 2; +} + +// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc +message QueryFeeEnabledChannelsResponse { + // list of fee enabled channels + repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 [(gogoproto.nullable) = false]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc +message QueryFeeEnabledChannelRequest { + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; +} + +// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc +message QueryFeeEnabledChannelResponse { + // boolean flag representing the fee enabled channel status + bool fee_enabled = 1; +} diff --git a/third_party/proto/ibc/fee/v1/tx.proto b/third_party/proto/ibc/fee/v1/tx.proto new file mode 100644 index 000000000..e59dddfd1 --- /dev/null +++ b/third_party/proto/ibc/fee/v1/tx.proto @@ -0,0 +1,122 @@ +syntax = "proto3"; + +package ibc.applications.fee.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; + +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; +import "ibc/applications/fee/v1/fee.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "cosmos/msg/v1/msg.proto"; + +// Msg defines the ICS29 Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // RegisterPayee defines a rpc handler method for MsgRegisterPayee + // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional + // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on + // the source chain from which packets originate as this is where fee distribution takes place. This function may be + // called more than once by a relayer, in which case, the latest payee is always used. + rpc RegisterPayee(MsgRegisterPayee) returns (MsgRegisterPayeeResponse); + + // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee + // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty + // payee address before relaying. This ensures they will be properly compensated for forward relaying since + // the destination chain must include the registered counterparty payee address in the acknowledgement. This function + // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. + rpc RegisterCounterpartyPayee(MsgRegisterCounterpartyPayee) returns (MsgRegisterCounterpartyPayeeResponse); + + // PayPacketFee defines a rpc handler method for MsgPayPacketFee + // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of the packet at the next sequence + // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows + // initiates the lifecycle of the incentivized packet + rpc PayPacketFee(MsgPayPacketFee) returns (MsgPayPacketFeeResponse); + + // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync + // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to + // incentivize the relaying of a known packet (i.e. at a particular sequence) + rpc PayPacketFeeAsync(MsgPayPacketFeeAsync) returns (MsgPayPacketFeeAsyncResponse); +} + +// MsgRegisterPayee defines the request type for the RegisterPayee rpc +message MsgRegisterPayee { + option (amino.name) = "cosmos-sdk/MsgRegisterPayee"; + option (cosmos.msg.v1.signer) = "relayer"; + + option (gogoproto.goproto_getters) = false; + + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; + // the relayer address + string relayer = 3; + // the payee address + string payee = 4; +} + +// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc +message MsgRegisterPayeeResponse {} + +// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc +message MsgRegisterCounterpartyPayee { + option (amino.name) = "cosmos-sdk/MsgRegisterCounterpartyPayee"; + option (cosmos.msg.v1.signer) = "relayer"; + + option (gogoproto.goproto_getters) = false; + + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; + // the relayer address + string relayer = 3; + // the counterparty payee address + string counterparty_payee = 4; +} + +// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc +message MsgRegisterCounterpartyPayeeResponse {} + +// MsgPayPacketFee defines the request type for the PayPacketFee rpc +// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be +// paid for +message MsgPayPacketFee { + option (amino.name) = "cosmos-sdk/MsgPayPacketFee"; + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // fee encapsulates the recv, ack and timeout fees associated with an IBC packet + ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + // the source port unique identifier + string source_port_id = 2; + // the source channel unique identifer + string source_channel_id = 3; + // account address to refund fee if necessary + string signer = 4; + // optional list of relayers permitted to the receive packet fees + repeated string relayers = 5; +} + +// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc +message MsgPayPacketFeeResponse {} + +// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc +// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) +message MsgPayPacketFeeAsync { + option (amino.name) = "cosmos-sdk/MsgPayPacketFeeAsync"; + option (cosmos.msg.v1.signer) = "packet_fee"; + option (gogoproto.goproto_getters) = false; + + // unique packet identifier comprised of the channel ID, port ID and sequence + ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + // the packet fee associated with a particular IBC packet + PacketFee packet_fee = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; +} + +// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc +message MsgPayPacketFeeAsyncResponse {} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto new file mode 100644 index 000000000..2e6bbe1a1 --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.controller.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the controller submodule. +message Params { + // controller_enabled enables or disables the controller submodule. + bool controller_enabled = 1; +} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto new file mode 100644 index 000000000..31885fcb2 --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.controller.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; + +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "google/api/annotations.proto"; + +// Query provides defines the gRPC querier service. +service Query { + // InterchainAccount returns the interchain account address for a given owner address on a given connection + rpc InterchainAccount(QueryInterchainAccountRequest) returns (QueryInterchainAccountResponse) { + option (google.api.http).get = + "/ibc/apps/interchain_accounts/controller/v1/owners/{owner}/connections/{connection_id}"; + } + + // Params queries all parameters of the ICA controller submodule. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ibc/apps/interchain_accounts/controller/v1/params"; + } +} + +// QueryInterchainAccountRequest is the request type for the Query/InterchainAccount RPC method. +message QueryInterchainAccountRequest { + string owner = 1; + string connection_id = 2; +} + +// QueryInterchainAccountResponse the response type for the Query/InterchainAccount RPC method. +message QueryInterchainAccountResponse { + string address = 1; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto new file mode 100644 index 000000000..ec5c2e62e --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto @@ -0,0 +1,82 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.controller.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/interchain_accounts/v1/packet.proto"; +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "cosmos/msg/v1/msg.proto"; +import "ibc/core/channel/v1/channel.proto"; + +// Msg defines the 27-interchain-accounts/controller Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // RegisterInterchainAccount defines a rpc handler for MsgRegisterInterchainAccount. + rpc RegisterInterchainAccount(MsgRegisterInterchainAccount) returns (MsgRegisterInterchainAccountResponse); + // SendTx defines a rpc handler for MsgSendTx. + rpc SendTx(MsgSendTx) returns (MsgSendTxResponse); + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgRegisterInterchainAccount defines the payload for Msg/RegisterAccount +message MsgRegisterInterchainAccount { + option (cosmos.msg.v1.signer) = "owner"; + + option (gogoproto.goproto_getters) = false; + + string owner = 1; + string connection_id = 2; + string version = 3; + ibc.core.channel.v1.Order ordering = 4; +} + +// MsgRegisterInterchainAccountResponse defines the response for Msg/RegisterAccount +message MsgRegisterInterchainAccountResponse { + option (gogoproto.goproto_getters) = false; + + string channel_id = 1; + string port_id = 2; +} + +// MsgSendTx defines the payload for Msg/SendTx +message MsgSendTx { + option (cosmos.msg.v1.signer) = "owner"; + + option (gogoproto.goproto_getters) = false; + + string owner = 1; + string connection_id = 2; + ibc.applications.interchain_accounts.v1.InterchainAccountPacketData packet_data = 3 [(gogoproto.nullable) = false]; + // Relative timeout timestamp provided will be added to the current block time during transaction execution. + // The timeout timestamp must be non-zero. + uint64 relative_timeout = 4; +} + +// MsgSendTxResponse defines the response for MsgSendTx +message MsgSendTxResponse { + option (gogoproto.goproto_getters) = false; + + uint64 sequence = 1; +} + +// MsgUpdateParams defines the payload for Msg/UpdateParams +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the 27-interchain-accounts/controller parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response for Msg/UpdateParams +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto b/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto new file mode 100644 index 000000000..4393e5b0b --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.genesis.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/genesis/types"; + +import "gogoproto/gogo.proto"; +import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; + +// GenesisState defines the interchain accounts genesis state +message GenesisState { + ControllerGenesisState controller_genesis_state = 1 [(gogoproto.nullable) = false]; + HostGenesisState host_genesis_state = 2 [(gogoproto.nullable) = false]; +} + +// ControllerGenesisState defines the interchain accounts controller genesis state +message ControllerGenesisState { + repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; + repeated string ports = 3; + ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; +} + +// HostGenesisState defines the interchain accounts host genesis state +message HostGenesisState { + repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; + repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; + string port = 3; + ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; +} + +// ActiveChannel contains a connection ID, port ID and associated active channel ID, as well as a boolean flag to +// indicate if the channel is middleware enabled +message ActiveChannel { + string connection_id = 1; + string port_id = 2; + string channel_id = 3; + bool is_middleware_enabled = 4; +} + +// RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address +message RegisteredInterchainAccount { + string connection_id = 1; + string port_id = 2; + string account_address = 3; +} \ No newline at end of file diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/host.proto b/third_party/proto/ibc/interchain_accounts/host/v1/host.proto new file mode 100644 index 000000000..f03685711 --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/host/v1/host.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; + +// Params defines the set of on-chain interchain accounts parameters. +// The following parameters may be used to disable the host submodule. +message Params { + // host_enabled enables or disables the host submodule. + bool host_enabled = 1; + // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. + repeated string allow_messages = 2; +} diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/query.proto b/third_party/proto/ibc/interchain_accounts/host/v1/query.proto new file mode 100644 index 000000000..6f206a14c --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/host/v1/query.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; + +import "google/api/annotations.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; + +// Query provides defines the gRPC querier service. +service Query { + // Params queries all parameters of the ICA host submodule. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ibc/apps/interchain_accounts/host/v1/params"; + } +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto b/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto new file mode 100644 index 000000000..5a8073bc9 --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.host.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "ibc/applications/interchain_accounts/host/v1/host.proto"; + +// Msg defines the 27-interchain-accounts/host Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgUpdateParams defines the payload for Msg/UpdateParams +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the 27-interchain-accounts/host parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response for Msg/UpdateParams +message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/interchain_accounts/v1/account.proto b/third_party/proto/ibc/interchain_accounts/v1/account.proto new file mode 100644 index 000000000..4a6947c1c --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/v1/account.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/auth/v1beta1/auth.proto"; + +// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain +message InterchainAccount { + option (gogoproto.goproto_getters) = false; + option (gogoproto.goproto_stringer) = false; + option (cosmos_proto.implements_interface) = "ibc.applications.interchain_accounts.v1.InterchainAccountI"; + + cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; + string account_owner = 2; +} diff --git a/third_party/proto/ibc/interchain_accounts/v1/metadata.proto b/third_party/proto/ibc/interchain_accounts/v1/metadata.proto new file mode 100644 index 000000000..df72b41eb --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/v1/metadata.proto @@ -0,0 +1,23 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; + +// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring +// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning +message Metadata { + // version defines the ICS27 protocol version + string version = 1; + // controller_connection_id is the connection identifier associated with the controller chain + string controller_connection_id = 2; + // host_connection_id is the connection identifier associated with the host chain + string host_connection_id = 3; + // address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step + // NOTE: the address field is empty on the OnChanOpenInit handshake step + string address = 4; + // encoding defines the supported codec format + string encoding = 5; + // tx_type defines the type of transactions the interchain account can execute + string tx_type = 6; +} diff --git a/third_party/proto/ibc/interchain_accounts/v1/packet.proto b/third_party/proto/ibc/interchain_accounts/v1/packet.proto new file mode 100644 index 000000000..f75a1463e --- /dev/null +++ b/third_party/proto/ibc/interchain_accounts/v1/packet.proto @@ -0,0 +1,31 @@ +syntax = "proto3"; + +package ibc.applications.interchain_accounts.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; + +import "google/protobuf/any.proto"; +import "gogoproto/gogo.proto"; + +// Type defines a classification of message issued from a controller chain to its associated interchain accounts +// host +enum Type { + option (gogoproto.goproto_enum_prefix) = false; + + // Default zero value enumeration + TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + // Execute a transaction on an interchain accounts host chain + TYPE_EXECUTE_TX = 1 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; +} + +// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. +message InterchainAccountPacketData { + Type type = 1; + bytes data = 2; + string memo = 3; +} + +// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. +message CosmosTx { + repeated google.protobuf.Any messages = 1; +} diff --git a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto index fb2f076a4..9dc2690c5 100644 --- a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto +++ b/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto @@ -16,11 +16,11 @@ message ClientState { // latest sequence of the client state uint64 sequence = 1; // frozen sequence of the solo machine - bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + bool is_frozen = 2; + ConsensusState consensus_state = 3; // when set to true, will allow governance to update a solo machine client. // The client will be unfrozen if it is frozen. - bool allow_update_after_proposal = 4 [(gogoproto.moretags) = "yaml:\"allow_update_after_proposal\""]; + bool allow_update_after_proposal = 4; } // ConsensusState defines a solo machine consensus state. The sequence of a @@ -29,7 +29,7 @@ message ClientState { message ConsensusState { option (gogoproto.goproto_getters) = false; // public key of the solo machine - google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""]; + google.protobuf.Any public_key = 1; // diversifier allows the same public key to be re-used across different solo // machine clients (potentially on different chains) without being considered // misbehaviour. @@ -44,18 +44,18 @@ message Header { uint64 sequence = 1; uint64 timestamp = 2; bytes signature = 3; - google.protobuf.Any new_public_key = 4 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; - string new_diversifier = 5 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; + google.protobuf.Any new_public_key = 4; + string new_diversifier = 5; } // Misbehaviour defines misbehaviour for a solo machine which consists // of a sequence and two signatures over different messages at that sequence. message Misbehaviour { option (gogoproto.goproto_getters) = false; - string client_id = 1 [(gogoproto.moretags) = "yaml:\"client_id\""]; + string client_id = 1; uint64 sequence = 2; - SignatureAndData signature_one = 3 [(gogoproto.moretags) = "yaml:\"signature_one\""]; - SignatureAndData signature_two = 4 [(gogoproto.moretags) = "yaml:\"signature_two\""]; + SignatureAndData signature_one = 3; + SignatureAndData signature_two = 4; } // SignatureAndData contains a signature and the data signed over to create that @@ -63,7 +63,7 @@ message Misbehaviour { message SignatureAndData { option (gogoproto.goproto_getters) = false; bytes signature = 1; - DataType data_type = 2 [(gogoproto.moretags) = "yaml:\"data_type\""]; + DataType data_type = 2; bytes data = 3; uint64 timestamp = 4; } @@ -72,7 +72,7 @@ message SignatureAndData { // signature. message TimestampedSignatureData { option (gogoproto.goproto_getters) = false; - bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""]; + bytes signature_data = 1; uint64 timestamp = 2; } @@ -84,7 +84,7 @@ message SignBytes { uint64 timestamp = 2; string diversifier = 3; // type of the data used - DataType data_type = 4 [(gogoproto.moretags) = "yaml:\"data_type\""]; + DataType data_type = 4; // marshaled data bytes data = 5; } @@ -121,9 +121,9 @@ message HeaderData { option (gogoproto.goproto_getters) = false; // header public key - google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""]; + google.protobuf.Any new_pub_key = 1; // header diversifier - string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; + string new_diversifier = 2; } // ClientStateData returns the SignBytes data for client state verification. @@ -131,7 +131,7 @@ message ClientStateData { option (gogoproto.goproto_getters) = false; bytes path = 1; - google.protobuf.Any client_state = 2 [(gogoproto.moretags) = "yaml:\"client_state\""]; + google.protobuf.Any client_state = 2; } // ConsensusStateData returns the SignBytes data for consensus state @@ -140,7 +140,7 @@ message ConsensusStateData { option (gogoproto.goproto_getters) = false; bytes path = 1; - google.protobuf.Any consensus_state = 2 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + google.protobuf.Any consensus_state = 2; } // ConnectionStateData returns the SignBytes data for connection state @@ -185,5 +185,5 @@ message PacketReceiptAbsenceData { // sequence to be received. message NextSequenceRecvData { bytes path = 1; - uint64 next_seq_recv = 2 [(gogoproto.moretags) = "yaml:\"next_seq_recv\""]; + uint64 next_seq_recv = 2; } diff --git a/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto index 38f9328c7..194905b38 100644 --- a/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto +++ b/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto @@ -14,8 +14,8 @@ message ClientState { // latest sequence of the client state uint64 sequence = 1; // frozen sequence of the solo machine - bool is_frozen = 2 [(gogoproto.moretags) = "yaml:\"is_frozen\""]; - ConsensusState consensus_state = 3 [(gogoproto.moretags) = "yaml:\"consensus_state\""]; + bool is_frozen = 2; + ConsensusState consensus_state = 3; } // ConsensusState defines a solo machine consensus state. The sequence of a @@ -24,7 +24,7 @@ message ClientState { message ConsensusState { option (gogoproto.goproto_getters) = false; // public key of the solo machine - google.protobuf.Any public_key = 1 [(gogoproto.moretags) = "yaml:\"public_key\""]; + google.protobuf.Any public_key = 1; // diversifier allows the same public key to be re-used across different solo // machine clients (potentially on different chains) without being considered // misbehaviour. @@ -38,8 +38,8 @@ message Header { uint64 timestamp = 1; bytes signature = 2; - google.protobuf.Any new_public_key = 3 [(gogoproto.moretags) = "yaml:\"new_public_key\""]; - string new_diversifier = 4 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; + google.protobuf.Any new_public_key = 3; + string new_diversifier = 4; } // Misbehaviour defines misbehaviour for a solo machine which consists @@ -48,8 +48,8 @@ message Misbehaviour { option (gogoproto.goproto_getters) = false; uint64 sequence = 1; - SignatureAndData signature_one = 2 [(gogoproto.moretags) = "yaml:\"signature_one\""]; - SignatureAndData signature_two = 3 [(gogoproto.moretags) = "yaml:\"signature_two\""]; + SignatureAndData signature_one = 2; + SignatureAndData signature_two = 3; } // SignatureAndData contains a signature and the data signed over to create that @@ -68,7 +68,7 @@ message SignatureAndData { message TimestampedSignatureData { option (gogoproto.goproto_getters) = false; - bytes signature_data = 1 [(gogoproto.moretags) = "yaml:\"signature_data\""]; + bytes signature_data = 1; uint64 timestamp = 2; } @@ -93,7 +93,7 @@ message HeaderData { option (gogoproto.goproto_getters) = false; // header public key - google.protobuf.Any new_pub_key = 1 [(gogoproto.moretags) = "yaml:\"new_pub_key\""]; + google.protobuf.Any new_pub_key = 1; // header diversifier - string new_diversifier = 2 [(gogoproto.moretags) = "yaml:\"new_diversifier\""]; + string new_diversifier = 2; } diff --git a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto index bb21775dc..505361222 100644 --- a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto @@ -19,29 +19,21 @@ message ClientState { option (gogoproto.goproto_getters) = false; string chain_id = 1; - Fraction trust_level = 2 [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trust_level\""]; + Fraction trust_level = 2 [(gogoproto.nullable) = false]; // duration of the period since the LastestTimestamp during which the // submitted headers are valid for upgrade - google.protobuf.Duration trusting_period = 3 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"trusting_period\""]; + google.protobuf.Duration trusting_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; // duration of the staking unbonding period - google.protobuf.Duration unbonding_period = 4 [ - (gogoproto.nullable) = false, - (gogoproto.stdduration) = true, - (gogoproto.moretags) = "yaml:\"unbonding_period\"" - ]; + google.protobuf.Duration unbonding_period = 4 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; // defines how much new (untrusted) header's Time can drift into the future. - google.protobuf.Duration max_clock_drift = 5 - [(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"max_clock_drift\""]; + google.protobuf.Duration max_clock_drift = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; // Block height when the client was frozen due to a misbehaviour - ibc.core.client.v1.Height frozen_height = 6 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"frozen_height\""]; + ibc.core.client.v1.Height frozen_height = 6 [(gogoproto.nullable) = false]; // Latest height the client was updated to - ibc.core.client.v1.Height latest_height = 7 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"latest_height\""]; + ibc.core.client.v1.Height latest_height = 7 [(gogoproto.nullable) = false]; // Proof specifications used in verifying counterparty state - repeated cosmos.ics23.v1.ProofSpec proof_specs = 8 [(gogoproto.moretags) = "yaml:\"proof_specs\""]; + repeated cosmos.ics23.v1.ProofSpec proof_specs = 8; // Path at which next upgraded client will be committed. // Each element corresponds to the key for a single CommitmentProof in the @@ -50,13 +42,12 @@ message ClientState { // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using // the default upgrade module, upgrade_path should be []string{"upgrade", // "upgradedIBCState"}` - repeated string upgrade_path = 9 [(gogoproto.moretags) = "yaml:\"upgrade_path\""]; + repeated string upgrade_path = 9; // allow_update_after_expiry is deprecated - bool allow_update_after_expiry = 10 [deprecated = true, (gogoproto.moretags) = "yaml:\"allow_update_after_expiry\""]; + bool allow_update_after_expiry = 10 [deprecated = true]; // allow_update_after_misbehaviour is deprecated - bool allow_update_after_misbehaviour = 11 - [deprecated = true, (gogoproto.moretags) = "yaml:\"allow_update_after_misbehaviour\""]; + bool allow_update_after_misbehaviour = 11 [deprecated = true]; } // ConsensusState defines the consensus state from Tendermint. @@ -67,11 +58,8 @@ message ConsensusState { // was stored. google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; // commitment root (i.e app hash) - ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; - bytes next_validators_hash = 3 [ - (gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes", - (gogoproto.moretags) = "yaml:\"next_validators_hash\"" - ]; + ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; + bytes next_validators_hash = 3 [(gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes"]; } // Misbehaviour is a wrapper over two conflicting Headers @@ -80,9 +68,9 @@ message Misbehaviour { option (gogoproto.goproto_getters) = false; // ClientID is deprecated - string client_id = 1 [deprecated = true, (gogoproto.moretags) = "yaml:\"client_id\""]; - Header header_1 = 2 [(gogoproto.customname) = "Header1", (gogoproto.moretags) = "yaml:\"header_1\""]; - Header header_2 = 3 [(gogoproto.customname) = "Header2", (gogoproto.moretags) = "yaml:\"header_2\""]; + string client_id = 1 [deprecated = true]; + Header header_1 = 2 [(gogoproto.customname) = "Header1"]; + Header header_2 = 3 [(gogoproto.customname) = "Header2"]; } // Header defines the Tendermint client consensus Header. @@ -98,13 +86,11 @@ message Misbehaviour { // hash to TrustedConsensusState.NextValidatorsHash since that is the last // trusted validator set at the TrustedHeight. message Header { - .tendermint.types.SignedHeader signed_header = 1 - [(gogoproto.embed) = true, (gogoproto.moretags) = "yaml:\"signed_header\""]; + .tendermint.types.SignedHeader signed_header = 1 [(gogoproto.embed) = true]; - .tendermint.types.ValidatorSet validator_set = 2 [(gogoproto.moretags) = "yaml:\"validator_set\""]; - ibc.core.client.v1.Height trusted_height = 3 - [(gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"trusted_height\""]; - .tendermint.types.ValidatorSet trusted_validators = 4 [(gogoproto.moretags) = "yaml:\"trusted_validators\""]; + .tendermint.types.ValidatorSet validator_set = 2; + ibc.core.client.v1.Height trusted_height = 3 [(gogoproto.nullable) = false]; + .tendermint.types.ValidatorSet trusted_validators = 4; } // Fraction defines the protobuf message type for tmmath.Fraction that only diff --git a/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto b/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto new file mode 100644 index 000000000..637ba1677 --- /dev/null +++ b/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto @@ -0,0 +1,20 @@ + +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// GenesisState defines 08-wasm's keeper genesis state +message GenesisState { + // uploaded light client wasm contracts + repeated Contract contracts = 1 [(gogoproto.nullable) = false]; +} + +// Contract stores contract code +message Contract { + option (gogoproto.goproto_getters) = false; + // contract byte code + bytes code_bytes = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/lightclients/wasm/v1/query.proto b/third_party/proto/ibc/lightclients/wasm/v1/query.proto new file mode 100644 index 000000000..bbbed29dd --- /dev/null +++ b/third_party/proto/ibc/lightclients/wasm/v1/query.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// Query service for wasm module +service Query { + // Get all Wasm checksums + rpc Checksums(QueryChecksumsRequest) returns (QueryChecksumsResponse) { + option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums"; + } + + // Get Wasm code for given checksum + rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { + option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums/{checksum}/code"; + } +} + +// QueryChecksumsRequest is the request type for the Query/Checksums RPC method. +message QueryChecksumsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryChecksumsResponse is the response type for the Query/Checksums RPC method. +message QueryChecksumsResponse { + // checksums is a list of the hex encoded checksums of all wasm codes stored. + repeated string checksums = 1; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryCodeRequest is the request type for the Query/Code RPC method. +message QueryCodeRequest { + // checksum is a hex encoded string of the code stored. + string checksum = 1; +} + +// QueryCodeResponse is the response type for the Query/Code RPC method. +message QueryCodeResponse { + bytes data = 1; +} diff --git a/third_party/proto/ibc/lightclients/wasm/v1/tx.proto b/third_party/proto/ibc/lightclients/wasm/v1/tx.proto new file mode 100644 index 000000000..d2fc46591 --- /dev/null +++ b/third_party/proto/ibc/lightclients/wasm/v1/tx.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +import "cosmos/msg/v1/msg.proto"; + +// Msg defines the ibc/08-wasm Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // StoreCode defines a rpc handler method for MsgStoreCode. + rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); + + // RemoveChecksum defines a rpc handler method for MsgRemoveChecksum. + rpc RemoveChecksum(MsgRemoveChecksum) returns (MsgRemoveChecksumResponse); + + // MigrateContract defines a rpc handler method for MsgMigrateContract. + rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse); +} + +// MsgStoreCode defines the request type for the StoreCode rpc. +message MsgStoreCode { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // wasm byte code of light client contract. It can be raw or gzip compressed + bytes wasm_byte_code = 2; +} + +// MsgStoreCodeResponse defines the response type for the StoreCode rpc +message MsgStoreCodeResponse { + // checksum is the sha256 hash of the stored code + bytes checksum = 1; +} + +// MsgRemoveChecksum defines the request type for the MsgRemoveChecksum rpc. +message MsgRemoveChecksum { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // checksum is the sha256 hash to be removed from the store + bytes checksum = 2; +} + +// MsgStoreChecksumResponse defines the response type for the StoreCode rpc +message MsgRemoveChecksumResponse {} + +// MsgMigrateContract defines the request type for the MigrateContract rpc. +message MsgMigrateContract { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // the client id of the contract + string client_id = 2; + // checksum is the sha256 hash of the new wasm byte code for the contract + bytes checksum = 3; + // the json encoded message to be passed to the contract on migration + bytes msg = 4; +} + +// MsgMigrateContractResponse defines the response type for the MigrateContract rpc +message MsgMigrateContractResponse {} diff --git a/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto b/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto new file mode 100644 index 000000000..b6a45e3d8 --- /dev/null +++ b/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto @@ -0,0 +1,43 @@ + +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "gogoproto/gogo.proto"; +import "ibc/core/client/v1/client.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// Wasm light client's Client state +message ClientState { + option (gogoproto.goproto_getters) = false; + // bytes encoding the client state of the underlying light client + // implemented as a Wasm contract. + bytes data = 1; + bytes checksum = 2; + ibc.core.client.v1.Height latest_height = 3 [(gogoproto.nullable) = false]; +} + +// Wasm light client's ConsensusState +message ConsensusState { + option (gogoproto.goproto_getters) = false; + // bytes encoding the consensus state of the underlying light client + // implemented as a Wasm contract. + bytes data = 1; +} + +// Wasm light client message (either header(s) or misbehaviour) +message ClientMessage { + option (gogoproto.goproto_getters) = false; + + bytes data = 1; +} + +// Checksums defines a list of all checksums that are stored +// +// Deprecated: This message is deprecated in favor of storing the checksums +// using a Collections.KeySet. +message Checksums { + option deprecated = true; + + repeated bytes checksums = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/localhost/v2/localhost.proto b/third_party/proto/ibc/localhost/v2/localhost.proto new file mode 100644 index 000000000..635db8521 --- /dev/null +++ b/third_party/proto/ibc/localhost/v2/localhost.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package ibc.lightclients.localhost.v2; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost;localhost"; + +import "ibc/core/client/v1/client.proto"; +import "gogoproto/gogo.proto"; + +// ClientState defines the 09-localhost client state +message ClientState { + option (gogoproto.goproto_getters) = false; + + // the latest block height + ibc.core.client.v1.Height latest_height = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/solomachine/v2/solomachine.proto b/third_party/proto/ibc/solomachine/v2/solomachine.proto new file mode 100644 index 000000000..9dc2690c5 --- /dev/null +++ b/third_party/proto/ibc/solomachine/v2/solomachine.proto @@ -0,0 +1,189 @@ +syntax = "proto3"; + +package ibc.lightclients.solomachine.v2; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7"; + +import "ibc/core/connection/v1/connection.proto"; +import "ibc/core/channel/v1/channel.proto"; +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +// ClientState defines a solo machine client that tracks the current consensus +// state and if the client is frozen. +message ClientState { + option (gogoproto.goproto_getters) = false; + // latest sequence of the client state + uint64 sequence = 1; + // frozen sequence of the solo machine + bool is_frozen = 2; + ConsensusState consensus_state = 3; + // when set to true, will allow governance to update a solo machine client. + // The client will be unfrozen if it is frozen. + bool allow_update_after_proposal = 4; +} + +// ConsensusState defines a solo machine consensus state. The sequence of a +// consensus state is contained in the "height" key used in storing the +// consensus state. +message ConsensusState { + option (gogoproto.goproto_getters) = false; + // public key of the solo machine + google.protobuf.Any public_key = 1; + // diversifier allows the same public key to be re-used across different solo + // machine clients (potentially on different chains) without being considered + // misbehaviour. + string diversifier = 2; + uint64 timestamp = 3; +} + +// Header defines a solo machine consensus header +message Header { + option (gogoproto.goproto_getters) = false; + // sequence to update solo machine public key at + uint64 sequence = 1; + uint64 timestamp = 2; + bytes signature = 3; + google.protobuf.Any new_public_key = 4; + string new_diversifier = 5; +} + +// Misbehaviour defines misbehaviour for a solo machine which consists +// of a sequence and two signatures over different messages at that sequence. +message Misbehaviour { + option (gogoproto.goproto_getters) = false; + string client_id = 1; + uint64 sequence = 2; + SignatureAndData signature_one = 3; + SignatureAndData signature_two = 4; +} + +// SignatureAndData contains a signature and the data signed over to create that +// signature. +message SignatureAndData { + option (gogoproto.goproto_getters) = false; + bytes signature = 1; + DataType data_type = 2; + bytes data = 3; + uint64 timestamp = 4; +} + +// TimestampedSignatureData contains the signature data and the timestamp of the +// signature. +message TimestampedSignatureData { + option (gogoproto.goproto_getters) = false; + bytes signature_data = 1; + uint64 timestamp = 2; +} + +// SignBytes defines the signed bytes used for signature verification. +message SignBytes { + option (gogoproto.goproto_getters) = false; + + uint64 sequence = 1; + uint64 timestamp = 2; + string diversifier = 3; + // type of the data used + DataType data_type = 4; + // marshaled data + bytes data = 5; +} + +// DataType defines the type of solo machine proof being created. This is done +// to preserve uniqueness of different data sign byte encodings. +enum DataType { + option (gogoproto.goproto_enum_prefix) = false; + + // Default State + DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; + // Data type for client state verification + DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"]; + // Data type for consensus state verification + DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"]; + // Data type for connection state verification + DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"]; + // Data type for channel state verification + DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"]; + // Data type for packet commitment verification + DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"]; + // Data type for packet acknowledgement verification + DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"]; + // Data type for packet receipt absence verification + DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"]; + // Data type for next sequence recv verification + DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"]; + // Data type for header verification + DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"]; +} + +// HeaderData returns the SignBytes data for update verification. +message HeaderData { + option (gogoproto.goproto_getters) = false; + + // header public key + google.protobuf.Any new_pub_key = 1; + // header diversifier + string new_diversifier = 2; +} + +// ClientStateData returns the SignBytes data for client state verification. +message ClientStateData { + option (gogoproto.goproto_getters) = false; + + bytes path = 1; + google.protobuf.Any client_state = 2; +} + +// ConsensusStateData returns the SignBytes data for consensus state +// verification. +message ConsensusStateData { + option (gogoproto.goproto_getters) = false; + + bytes path = 1; + google.protobuf.Any consensus_state = 2; +} + +// ConnectionStateData returns the SignBytes data for connection state +// verification. +message ConnectionStateData { + option (gogoproto.goproto_getters) = false; + + bytes path = 1; + ibc.core.connection.v1.ConnectionEnd connection = 2; +} + +// ChannelStateData returns the SignBytes data for channel state +// verification. +message ChannelStateData { + option (gogoproto.goproto_getters) = false; + + bytes path = 1; + ibc.core.channel.v1.Channel channel = 2; +} + +// PacketCommitmentData returns the SignBytes data for packet commitment +// verification. +message PacketCommitmentData { + bytes path = 1; + bytes commitment = 2; +} + +// PacketAcknowledgementData returns the SignBytes data for acknowledgement +// verification. +message PacketAcknowledgementData { + bytes path = 1; + bytes acknowledgement = 2; +} + +// PacketReceiptAbsenceData returns the SignBytes data for +// packet receipt absence verification. +message PacketReceiptAbsenceData { + bytes path = 1; +} + +// NextSequenceRecvData returns the SignBytes data for verification of the next +// sequence to be received. +message NextSequenceRecvData { + bytes path = 1; + uint64 next_seq_recv = 2; +} diff --git a/third_party/proto/ibc/solomachine/v3/solomachine.proto b/third_party/proto/ibc/solomachine/v3/solomachine.proto new file mode 100644 index 000000000..194905b38 --- /dev/null +++ b/third_party/proto/ibc/solomachine/v3/solomachine.proto @@ -0,0 +1,99 @@ +syntax = "proto3"; + +package ibc.lightclients.solomachine.v3; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine;solomachine"; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; + +// ClientState defines a solo machine client that tracks the current consensus +// state and if the client is frozen. +message ClientState { + option (gogoproto.goproto_getters) = false; + // latest sequence of the client state + uint64 sequence = 1; + // frozen sequence of the solo machine + bool is_frozen = 2; + ConsensusState consensus_state = 3; +} + +// ConsensusState defines a solo machine consensus state. The sequence of a +// consensus state is contained in the "height" key used in storing the +// consensus state. +message ConsensusState { + option (gogoproto.goproto_getters) = false; + // public key of the solo machine + google.protobuf.Any public_key = 1; + // diversifier allows the same public key to be re-used across different solo + // machine clients (potentially on different chains) without being considered + // misbehaviour. + string diversifier = 2; + uint64 timestamp = 3; +} + +// Header defines a solo machine consensus header +message Header { + option (gogoproto.goproto_getters) = false; + + uint64 timestamp = 1; + bytes signature = 2; + google.protobuf.Any new_public_key = 3; + string new_diversifier = 4; +} + +// Misbehaviour defines misbehaviour for a solo machine which consists +// of a sequence and two signatures over different messages at that sequence. +message Misbehaviour { + option (gogoproto.goproto_getters) = false; + + uint64 sequence = 1; + SignatureAndData signature_one = 2; + SignatureAndData signature_two = 3; +} + +// SignatureAndData contains a signature and the data signed over to create that +// signature. +message SignatureAndData { + option (gogoproto.goproto_getters) = false; + + bytes signature = 1; + bytes path = 2; + bytes data = 3; + uint64 timestamp = 4; +} + +// TimestampedSignatureData contains the signature data and the timestamp of the +// signature. +message TimestampedSignatureData { + option (gogoproto.goproto_getters) = false; + + bytes signature_data = 1; + uint64 timestamp = 2; +} + +// SignBytes defines the signed bytes used for signature verification. +message SignBytes { + option (gogoproto.goproto_getters) = false; + + // the sequence number + uint64 sequence = 1; + // the proof timestamp + uint64 timestamp = 2; + // the public key diversifier + string diversifier = 3; + // the standardised path bytes + bytes path = 4; + // the marshaled data bytes + bytes data = 5; +} + +// HeaderData returns the SignBytes data for update verification. +message HeaderData { + option (gogoproto.goproto_getters) = false; + + // header public key + google.protobuf.Any new_pub_key = 1; + // header diversifier + string new_diversifier = 2; +} diff --git a/third_party/proto/ibc/tendermint/v1/tendermint.proto b/third_party/proto/ibc/tendermint/v1/tendermint.proto new file mode 100644 index 000000000..505361222 --- /dev/null +++ b/third_party/proto/ibc/tendermint/v1/tendermint.proto @@ -0,0 +1,101 @@ +syntax = "proto3"; + +package ibc.lightclients.tendermint.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint;tendermint"; + +import "tendermint/types/validator.proto"; +import "tendermint/types/types.proto"; +import "cosmos/ics23/v1/proofs.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/core/commitment/v1/commitment.proto"; +import "gogoproto/gogo.proto"; + +// ClientState from Tendermint tracks the current validator set, latest height, +// and a possible frozen height. +message ClientState { + option (gogoproto.goproto_getters) = false; + + string chain_id = 1; + Fraction trust_level = 2 [(gogoproto.nullable) = false]; + // duration of the period since the LastestTimestamp during which the + // submitted headers are valid for upgrade + google.protobuf.Duration trusting_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // duration of the staking unbonding period + google.protobuf.Duration unbonding_period = 4 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // defines how much new (untrusted) header's Time can drift into the future. + google.protobuf.Duration max_clock_drift = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; + // Block height when the client was frozen due to a misbehaviour + ibc.core.client.v1.Height frozen_height = 6 [(gogoproto.nullable) = false]; + // Latest height the client was updated to + ibc.core.client.v1.Height latest_height = 7 [(gogoproto.nullable) = false]; + + // Proof specifications used in verifying counterparty state + repeated cosmos.ics23.v1.ProofSpec proof_specs = 8; + + // Path at which next upgraded client will be committed. + // Each element corresponds to the key for a single CommitmentProof in the + // chained proof. NOTE: ClientState must stored under + // `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored + // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using + // the default upgrade module, upgrade_path should be []string{"upgrade", + // "upgradedIBCState"}` + repeated string upgrade_path = 9; + + // allow_update_after_expiry is deprecated + bool allow_update_after_expiry = 10 [deprecated = true]; + // allow_update_after_misbehaviour is deprecated + bool allow_update_after_misbehaviour = 11 [deprecated = true]; +} + +// ConsensusState defines the consensus state from Tendermint. +message ConsensusState { + option (gogoproto.goproto_getters) = false; + + // timestamp that corresponds to the block height in which the ConsensusState + // was stored. + google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + // commitment root (i.e app hash) + ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; + bytes next_validators_hash = 3 [(gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes"]; +} + +// Misbehaviour is a wrapper over two conflicting Headers +// that implements Misbehaviour interface expected by ICS-02 +message Misbehaviour { + option (gogoproto.goproto_getters) = false; + + // ClientID is deprecated + string client_id = 1 [deprecated = true]; + Header header_1 = 2 [(gogoproto.customname) = "Header1"]; + Header header_2 = 3 [(gogoproto.customname) = "Header2"]; +} + +// Header defines the Tendermint client consensus Header. +// It encapsulates all the information necessary to update from a trusted +// Tendermint ConsensusState. The inclusion of TrustedHeight and +// TrustedValidators allows this update to process correctly, so long as the +// ConsensusState for the TrustedHeight exists, this removes race conditions +// among relayers The SignedHeader and ValidatorSet are the new untrusted update +// fields for the client. The TrustedHeight is the height of a stored +// ConsensusState on the client that will be used to verify the new untrusted +// header. The Trusted ConsensusState must be within the unbonding period of +// current time in order to correctly verify, and the TrustedValidators must +// hash to TrustedConsensusState.NextValidatorsHash since that is the last +// trusted validator set at the TrustedHeight. +message Header { + .tendermint.types.SignedHeader signed_header = 1 [(gogoproto.embed) = true]; + + .tendermint.types.ValidatorSet validator_set = 2; + ibc.core.client.v1.Height trusted_height = 3 [(gogoproto.nullable) = false]; + .tendermint.types.ValidatorSet trusted_validators = 4; +} + +// Fraction defines the protobuf message type for tmmath.Fraction that only +// supports positive values. +message Fraction { + uint64 numerator = 1; + uint64 denominator = 2; +} diff --git a/third_party/proto/ibc/transfer/v1/authz.proto b/third_party/proto/ibc/transfer/v1/authz.proto new file mode 100644 index 000000000..e7561b070 --- /dev/null +++ b/third_party/proto/ibc/transfer/v1/authz.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; + +// Allocation defines the spend limit for a particular port and channel +message Allocation { + // the port on which the packet will be sent + string source_port = 1; + // the channel by which the packet will be sent + string source_channel = 2; + // spend limitation on the channel + repeated cosmos.base.v1beta1.Coin spend_limit = 3 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + // allow list of receivers, an empty allow list permits any receiver address + repeated string allow_list = 4; + // allow list of packet data keys, an empty list prohibits all packet data keys; + // a list only with "*" permits any packet data key + repeated string allowed_packet_data = 5; +} + +// TransferAuthorization allows the grantee to spend up to spend_limit coins from +// the granter's account for ibc transfer on a specific channel +message TransferAuthorization { + option (cosmos_proto.implements_interface) = "cosmos.authz.v1beta1.Authorization"; + + // port and channel amounts + repeated Allocation allocations = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/transfer/v1/genesis.proto b/third_party/proto/ibc/transfer/v1/genesis.proto new file mode 100644 index 000000000..f7d707f6c --- /dev/null +++ b/third_party/proto/ibc/transfer/v1/genesis.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +import "ibc/applications/transfer/v1/transfer.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "gogoproto/gogo.proto"; + +// GenesisState defines the ibc-transfer genesis state +message GenesisState { + string port_id = 1; + repeated DenomTrace denom_traces = 2 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false]; + Params params = 3 [(gogoproto.nullable) = false]; + // total_escrowed contains the total amount of tokens escrowed + // by the transfer module + repeated cosmos.base.v1beta1.Coin total_escrowed = 4 + [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/transfer/v1/query.proto b/third_party/proto/ibc/transfer/v1/query.proto new file mode 100644 index 000000000..788296718 --- /dev/null +++ b/third_party/proto/ibc/transfer/v1/query.proto @@ -0,0 +1,121 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +import "gogoproto/gogo.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "ibc/applications/transfer/v1/transfer.proto"; +import "google/api/annotations.proto"; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +// Query provides defines the gRPC querier service. +service Query { + // DenomTraces queries all denomination traces. + rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/denom_traces"; + } + + // DenomTrace queries a denomination trace information. + rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/denom_traces/{hash=**}"; + } + + // Params queries all parameters of the ibc-transfer module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/params"; + } + + // DenomHash queries a denomination hash information. + rpc DenomHash(QueryDenomHashRequest) returns (QueryDenomHashResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/denom_hashes/{trace=**}"; + } + + // EscrowAddress returns the escrow address for a particular port and channel id. + rpc EscrowAddress(QueryEscrowAddressRequest) returns (QueryEscrowAddressResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address"; + } + + // TotalEscrowForDenom returns the total amount of tokens in escrow based on the denom. + rpc TotalEscrowForDenom(QueryTotalEscrowForDenomRequest) returns (QueryTotalEscrowForDenomResponse) { + option (google.api.http).get = "/ibc/apps/transfer/v1/denoms/{denom=**}/total_escrow"; + } +} + +// QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC +// method +message QueryDenomTraceRequest { + // hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. + string hash = 1; +} + +// QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC +// method. +message QueryDenomTraceResponse { + // denom_trace returns the requested denomination trace information. + DenomTrace denom_trace = 1; +} + +// QueryConnectionsRequest is the request type for the Query/DenomTraces RPC +// method +message QueryDenomTracesRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryConnectionsResponse is the response type for the Query/DenomTraces RPC +// method. +message QueryDenomTracesResponse { + // denom_traces returns all denominations trace information. + repeated DenomTrace denom_traces = 1 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false]; + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryParamsRequest is the request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is the response type for the Query/Params RPC method. +message QueryParamsResponse { + // params defines the parameters of the module. + Params params = 1; +} + +// QueryDenomHashRequest is the request type for the Query/DenomHash RPC +// method +message QueryDenomHashRequest { + // The denomination trace ([port_id]/[channel_id])+/[denom] + string trace = 1; +} + +// QueryDenomHashResponse is the response type for the Query/DenomHash RPC +// method. +message QueryDenomHashResponse { + // hash (in hex format) of the denomination trace information. + string hash = 1; +} + +// QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. +message QueryEscrowAddressRequest { + // unique port identifier + string port_id = 1; + // unique channel identifier + string channel_id = 2; +} + +// QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. +message QueryEscrowAddressResponse { + // the escrow account address + string escrow_address = 1; +} + +// QueryTotalEscrowForDenomRequest is the request type for TotalEscrowForDenom RPC method. +message QueryTotalEscrowForDenomRequest { + string denom = 1; +} + +// QueryTotalEscrowForDenomResponse is the response type for TotalEscrowForDenom RPC method. +message QueryTotalEscrowForDenomResponse { + cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/transfer/v1/transfer.proto b/third_party/proto/ibc/transfer/v1/transfer.proto new file mode 100644 index 000000000..7f7723762 --- /dev/null +++ b/third_party/proto/ibc/transfer/v1/transfer.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +// DenomTrace contains the base denomination for ICS20 fungible tokens and the +// source tracing information path. +message DenomTrace { + // path defines the chain of port/channel identifiers used for tracing the + // source of the fungible token. + string path = 1; + // base denomination of the relayed fungible token. + string base_denom = 2; +} + +// Params defines the set of IBC transfer parameters. +// NOTE: To prevent a single token from being transferred, set the +// TransfersEnabled parameter to true and then set the bank module's SendEnabled +// parameter for the denomination to false. +message Params { + // send_enabled enables or disables all cross-chain token transfers from this + // chain. + bool send_enabled = 1; + // receive_enabled enables or disables all cross-chain token transfers to this + // chain. + bool receive_enabled = 2; +} diff --git a/third_party/proto/ibc/transfer/v1/tx.proto b/third_party/proto/ibc/transfer/v1/tx.proto new file mode 100644 index 000000000..42c70d3be --- /dev/null +++ b/third_party/proto/ibc/transfer/v1/tx.proto @@ -0,0 +1,79 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +import "amino/amino.proto"; +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "ibc/core/client/v1/client.proto"; +import "ibc/applications/transfer/v1/transfer.proto"; + +// Msg defines the ibc/transfer Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // Transfer defines a rpc handler method for MsgTransfer. + rpc Transfer(MsgTransfer) returns (MsgTransferResponse); + + // UpdateParams defines a rpc handler for MsgUpdateParams. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between +// ICS20 enabled chains. See ICS Spec here: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +message MsgTransfer { + option (amino.name) = "cosmos-sdk/MsgTransfer"; + option (cosmos.msg.v1.signer) = "sender"; + + option (gogoproto.goproto_getters) = false; + + // the port on which the packet will be sent + string source_port = 1; + // the channel by which the packet will be sent + string source_channel = 2; + // the tokens to be transferred + cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + // the sender address + string sender = 4; + // the recipient address on the destination chain + string receiver = 5; + // Timeout height relative to the current block height. + // The timeout is disabled when set to 0. + ibc.core.client.v1.Height timeout_height = 6 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; + // Timeout timestamp in absolute nanoseconds since unix epoch. + // The timeout is disabled when set to 0. + uint64 timeout_timestamp = 7; + // optional memo + string memo = 8; +} + +// MsgTransferResponse defines the Msg/Transfer response type. +message MsgTransferResponse { + option (gogoproto.goproto_getters) = false; + + // sequence number of the transfer packet sent + uint64 sequence = 1; +} + +// MsgUpdateParams is the Msg/UpdateParams request type. +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "signer"; + + option (gogoproto.goproto_getters) = false; + + // signer address + string signer = 1; + + // params defines the transfer parameters to update. + // + // NOTE: All parameters must be supplied. + Params params = 2 [(gogoproto.nullable) = false]; +} + +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. +message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/transfer/v2/packet.proto b/third_party/proto/ibc/transfer/v2/packet.proto new file mode 100644 index 000000000..bff35bdd6 --- /dev/null +++ b/third_party/proto/ibc/transfer/v2/packet.proto @@ -0,0 +1,21 @@ +syntax = "proto3"; + +package ibc.applications.transfer.v2; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; + +// FungibleTokenPacketData defines a struct for the packet payload +// See FungibleTokenPacketData spec: +// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures +message FungibleTokenPacketData { + // the token denomination to be transferred + string denom = 1; + // the token amount to be transferred + string amount = 2; + // the sender address + string sender = 3; + // the recipient address on the destination chain + string receiver = 4; + // optional memo + string memo = 5; +} diff --git a/third_party/proto/ibc/types/v1/genesis.proto b/third_party/proto/ibc/types/v1/genesis.proto new file mode 100644 index 000000000..4b34f6889 --- /dev/null +++ b/third_party/proto/ibc/types/v1/genesis.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +package ibc.core.types.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/types"; + +import "gogoproto/gogo.proto"; +import "ibc/core/client/v1/genesis.proto"; +import "ibc/core/connection/v1/genesis.proto"; +import "ibc/core/channel/v1/genesis.proto"; + +// GenesisState defines the ibc module's genesis state. +message GenesisState { + // ICS002 - Clients genesis state + ibc.core.client.v1.GenesisState client_genesis = 1 [(gogoproto.nullable) = false]; + // ICS003 - Connections genesis state + ibc.core.connection.v1.GenesisState connection_genesis = 2 [(gogoproto.nullable) = false]; + // ICS004 - Channel genesis state + ibc.core.channel.v1.GenesisState channel_genesis = 3 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/wasm/v1/genesis.proto b/third_party/proto/ibc/wasm/v1/genesis.proto new file mode 100644 index 000000000..637ba1677 --- /dev/null +++ b/third_party/proto/ibc/wasm/v1/genesis.proto @@ -0,0 +1,20 @@ + +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// GenesisState defines 08-wasm's keeper genesis state +message GenesisState { + // uploaded light client wasm contracts + repeated Contract contracts = 1 [(gogoproto.nullable) = false]; +} + +// Contract stores contract code +message Contract { + option (gogoproto.goproto_getters) = false; + // contract byte code + bytes code_bytes = 1; +} \ No newline at end of file diff --git a/third_party/proto/ibc/wasm/v1/query.proto b/third_party/proto/ibc/wasm/v1/query.proto new file mode 100644 index 000000000..bbbed29dd --- /dev/null +++ b/third_party/proto/ibc/wasm/v1/query.proto @@ -0,0 +1,46 @@ +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// Query service for wasm module +service Query { + // Get all Wasm checksums + rpc Checksums(QueryChecksumsRequest) returns (QueryChecksumsResponse) { + option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums"; + } + + // Get Wasm code for given checksum + rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { + option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums/{checksum}/code"; + } +} + +// QueryChecksumsRequest is the request type for the Query/Checksums RPC method. +message QueryChecksumsRequest { + // pagination defines an optional pagination for the request. + cosmos.base.query.v1beta1.PageRequest pagination = 1; +} + +// QueryChecksumsResponse is the response type for the Query/Checksums RPC method. +message QueryChecksumsResponse { + // checksums is a list of the hex encoded checksums of all wasm codes stored. + repeated string checksums = 1; + + // pagination defines the pagination in the response. + cosmos.base.query.v1beta1.PageResponse pagination = 2; +} + +// QueryCodeRequest is the request type for the Query/Code RPC method. +message QueryCodeRequest { + // checksum is a hex encoded string of the code stored. + string checksum = 1; +} + +// QueryCodeResponse is the response type for the Query/Code RPC method. +message QueryCodeResponse { + bytes data = 1; +} diff --git a/third_party/proto/ibc/wasm/v1/tx.proto b/third_party/proto/ibc/wasm/v1/tx.proto new file mode 100644 index 000000000..d2fc46591 --- /dev/null +++ b/third_party/proto/ibc/wasm/v1/tx.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +import "cosmos/msg/v1/msg.proto"; + +// Msg defines the ibc/08-wasm Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // StoreCode defines a rpc handler method for MsgStoreCode. + rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); + + // RemoveChecksum defines a rpc handler method for MsgRemoveChecksum. + rpc RemoveChecksum(MsgRemoveChecksum) returns (MsgRemoveChecksumResponse); + + // MigrateContract defines a rpc handler method for MsgMigrateContract. + rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse); +} + +// MsgStoreCode defines the request type for the StoreCode rpc. +message MsgStoreCode { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // wasm byte code of light client contract. It can be raw or gzip compressed + bytes wasm_byte_code = 2; +} + +// MsgStoreCodeResponse defines the response type for the StoreCode rpc +message MsgStoreCodeResponse { + // checksum is the sha256 hash of the stored code + bytes checksum = 1; +} + +// MsgRemoveChecksum defines the request type for the MsgRemoveChecksum rpc. +message MsgRemoveChecksum { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // checksum is the sha256 hash to be removed from the store + bytes checksum = 2; +} + +// MsgStoreChecksumResponse defines the response type for the StoreCode rpc +message MsgRemoveChecksumResponse {} + +// MsgMigrateContract defines the request type for the MigrateContract rpc. +message MsgMigrateContract { + option (cosmos.msg.v1.signer) = "signer"; + + // signer address + string signer = 1; + // the client id of the contract + string client_id = 2; + // checksum is the sha256 hash of the new wasm byte code for the contract + bytes checksum = 3; + // the json encoded message to be passed to the contract on migration + bytes msg = 4; +} + +// MsgMigrateContractResponse defines the response type for the MigrateContract rpc +message MsgMigrateContractResponse {} diff --git a/third_party/proto/ibc/wasm/v1/wasm.proto b/third_party/proto/ibc/wasm/v1/wasm.proto new file mode 100644 index 000000000..b6a45e3d8 --- /dev/null +++ b/third_party/proto/ibc/wasm/v1/wasm.proto @@ -0,0 +1,43 @@ + +syntax = "proto3"; +package ibc.lightclients.wasm.v1; + +import "gogoproto/gogo.proto"; +import "ibc/core/client/v1/client.proto"; + +option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; + +// Wasm light client's Client state +message ClientState { + option (gogoproto.goproto_getters) = false; + // bytes encoding the client state of the underlying light client + // implemented as a Wasm contract. + bytes data = 1; + bytes checksum = 2; + ibc.core.client.v1.Height latest_height = 3 [(gogoproto.nullable) = false]; +} + +// Wasm light client's ConsensusState +message ConsensusState { + option (gogoproto.goproto_getters) = false; + // bytes encoding the consensus state of the underlying light client + // implemented as a Wasm contract. + bytes data = 1; +} + +// Wasm light client message (either header(s) or misbehaviour) +message ClientMessage { + option (gogoproto.goproto_getters) = false; + + bytes data = 1; +} + +// Checksums defines a list of all checksums that are stored +// +// Deprecated: This message is deprecated in favor of storing the checksums +// using a Collections.KeySet. +message Checksums { + option deprecated = true; + + repeated bytes checksums = 1; +} \ No newline at end of file diff --git a/x/interchaintxs/keeper/msg_server.go b/x/interchaintxs/keeper/msg_server.go index 54c64e9e8..53f47483d 100644 --- a/x/interchaintxs/keeper/msg_server.go +++ b/x/interchaintxs/keeper/msg_server.go @@ -66,7 +66,7 @@ func (k Keeper) RegisterInterchainAccount(goCtx context.Context, msg *ictxtypes. Owner: icaOwner, ConnectionId: msg.ConnectionId, Version: "", // FIXME: empty version string doesn't look good - // underlying controller uses ORDER_ORDERED as default in case msg's ordering is NONE + // underlying controller uses ORDER_ORDERED as default in case msg's ordering is NONE // TODO: check now Ordering: msg.Ordering, }) if err != nil { diff --git a/x/interchaintxs/keeper/msg_server_test.go b/x/interchaintxs/keeper/msg_server_test.go index afd182224..5cecf14fa 100644 --- a/x/interchaintxs/keeper/msg_server_test.go +++ b/x/interchaintxs/keeper/msg_server_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "fmt" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "testing" "time" @@ -12,8 +13,6 @@ import ( wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - feerefundertypes "github.com/neutron-org/neutron/v4/x/feerefunder/types" "github.com/neutron-org/neutron/v4/x/interchaintxs/keeper" diff --git a/x/interchaintxs/types/tx.pb.go b/x/interchaintxs/types/tx.pb.go index 4b18fd1a1..8db65cb59 100644 --- a/x/interchaintxs/types/tx.pb.go +++ b/x/interchaintxs/types/tx.pb.go @@ -341,56 +341,56 @@ var fileDescriptor_50f087790e59c806 = []byte{ 0xbd, 0xa3, 0xa1, 0xb1, 0x66, 0x77, 0xc7, 0xeb, 0x11, 0xd9, 0x19, 0x33, 0x33, 0x6b, 0xc5, 0x1d, 0xa2, 0x42, 0x54, 0x34, 0x14, 0x74, 0x57, 0x22, 0x0a, 0x94, 0x82, 0x1f, 0x40, 0x79, 0xe5, 0x89, 0x8a, 0x2a, 0xa0, 0xa4, 0x08, 0xf5, 0x15, 0xd4, 0x68, 0x76, 0x67, 0x1c, 0xdb, 0x3a, 0x5b, 0x11, - 0x8d, 0x3d, 0xef, 0xbd, 0x6f, 0xde, 0x37, 0xf3, 0xbe, 0x37, 0x6f, 0xc1, 0x1e, 0xc5, 0xa9, 0xe4, - 0x8c, 0x7a, 0x84, 0x4a, 0xcc, 0xc3, 0x21, 0x22, 0x54, 0x9e, 0x0b, 0x6f, 0xdc, 0xf6, 0xe4, 0x39, - 0x1c, 0x71, 0x26, 0x99, 0xed, 0x68, 0x08, 0x9c, 0x83, 0xc0, 0x71, 0xbb, 0xf6, 0x2e, 0x4a, 0x08, - 0x65, 0x5e, 0xf6, 0x9b, 0x83, 0x6b, 0xf5, 0x90, 0x89, 0x84, 0x09, 0x2f, 0x40, 0x02, 0x7b, 0xe3, - 0x76, 0x80, 0x25, 0x6a, 0x7b, 0x21, 0x23, 0x54, 0xc7, 0xb7, 0x75, 0x3c, 0x11, 0xb1, 0x22, 0x49, - 0x44, 0xac, 0x03, 0xd5, 0x3c, 0xd0, 0xcf, 0x2c, 0x2f, 0x37, 0x74, 0x68, 0x2b, 0x66, 0x31, 0xcb, - 0xfd, 0x6a, 0xa5, 0xbd, 0x3b, 0x31, 0x63, 0xf1, 0x19, 0xf6, 0xd0, 0x88, 0x78, 0x88, 0x52, 0x26, - 0x91, 0x24, 0x8c, 0x9a, 0x3d, 0x0f, 0x67, 0xa2, 0x43, 0x29, 0x47, 0x86, 0x45, 0xbb, 0x33, 0x2b, - 0x48, 0x07, 0x1e, 0xa2, 0x13, 0x1d, 0xda, 0x35, 0x95, 0x18, 0x60, 0xcc, 0xf1, 0x20, 0xa5, 0x11, - 0xe6, 0x6a, 0xad, 0xc3, 0x8f, 0x96, 0x16, 0x6a, 0x84, 0x38, 0x4a, 0x0c, 0xef, 0x1e, 0x09, 0x42, - 0x2f, 0x64, 0x1c, 0x7b, 0xe1, 0x10, 0x51, 0x8a, 0xcf, 0x14, 0x42, 0x2f, 0x73, 0x88, 0xfb, 0x53, - 0x11, 0xec, 0x9c, 0x8a, 0xd8, 0xc7, 0x31, 0x11, 0x12, 0xf3, 0xde, 0x34, 0xdf, 0x49, 0x18, 0xb2, - 0x94, 0x4a, 0x7b, 0x0f, 0x6c, 0x0e, 0x38, 0x4b, 0xfa, 0x28, 0x8a, 0x38, 0x16, 0xc2, 0xb1, 0x9a, - 0x56, 0xab, 0xec, 0x57, 0x94, 0xef, 0x24, 0x77, 0xd9, 0x9f, 0x80, 0xb7, 0x42, 0x46, 0x29, 0x0e, - 0xd5, 0x9d, 0xfb, 0x24, 0x72, 0xd6, 0x14, 0xa6, 0xeb, 0xbc, 0xbe, 0x6c, 0x6c, 0x4d, 0x50, 0x72, - 0x76, 0xec, 0xce, 0x85, 0x5d, 0x7f, 0xf3, 0xd6, 0xee, 0x45, 0xf6, 0x73, 0xf0, 0xf0, 0xf6, 0x1a, - 0x7d, 0x94, 0xf3, 0xaa, 0x34, 0xc5, 0x2c, 0x4d, 0xf3, 0xf5, 0x65, 0x63, 0x27, 0x4f, 0xf3, 0x46, - 0x98, 0xeb, 0x3f, 0x20, 0x8b, 0xa7, 0xee, 0x45, 0x36, 0x05, 0x9b, 0x5c, 0x5f, 0xaa, 0x3f, 0xc0, - 0xd8, 0x29, 0x35, 0x8b, 0xad, 0x4a, 0xa7, 0x0a, 0xb5, 0x98, 0xaa, 0x25, 0xa0, 0x6e, 0x09, 0xf8, - 0x98, 0x11, 0xda, 0x3d, 0x7c, 0x79, 0xd9, 0x28, 0xfc, 0xf2, 0x57, 0xa3, 0x15, 0x13, 0x39, 0x4c, - 0x03, 0x18, 0xb2, 0x44, 0x2b, 0xaf, 0xff, 0x0e, 0x44, 0xf4, 0x95, 0x27, 0x27, 0x23, 0x2c, 0xb2, - 0x0d, 0xc2, 0xaf, 0x18, 0x82, 0x27, 0x18, 0xdb, 0x47, 0xe0, 0x3e, 0xe3, 0x11, 0xe6, 0x84, 0xc6, - 0xce, 0xbd, 0xa6, 0xd5, 0x7a, 0xbb, 0x53, 0x83, 0x24, 0x08, 0xa1, 0x2a, 0x3f, 0x34, 0x35, 0x1f, - 0xb7, 0xe1, 0x67, 0x0a, 0xe4, 0x4f, 0xb1, 0xc7, 0xd5, 0xef, 0x5e, 0x34, 0x0a, 0xff, 0xbc, 0x68, - 0x14, 0xbe, 0xbd, 0xb9, 0xd8, 0x9f, 0x2b, 0xb5, 0x1b, 0x81, 0xf7, 0x57, 0x49, 0xe3, 0x63, 0x31, - 0x62, 0x54, 0x60, 0x7b, 0x17, 0x00, 0x4d, 0xa0, 0xaa, 0x96, 0x0b, 0x54, 0xd6, 0x9e, 0x5e, 0x64, - 0x6f, 0x83, 0x8d, 0x11, 0xe3, 0x72, 0x2a, 0x8c, 0xbf, 0xae, 0xcc, 0x5e, 0x74, 0x5c, 0x52, 0xd4, - 0xee, 0xaf, 0x6b, 0xa0, 0x72, 0x2a, 0xe2, 0x67, 0x69, 0x90, 0x10, 0xf9, 0xfc, 0xfc, 0x2e, 0x82, - 0x77, 0x96, 0x29, 0x96, 0xe7, 0x7f, 0xa3, 0x1e, 0xef, 0x2d, 0x36, 0x49, 0xa6, 0xee, 0x42, 0x2b, - 0xb4, 0x40, 0x29, 0x11, 0xb1, 0xd0, 0x62, 0x6d, 0xc1, 0xfc, 0x81, 0x40, 0xf3, 0x40, 0xe0, 0x09, - 0x9d, 0xf8, 0x19, 0xc2, 0xb6, 0x41, 0x29, 0xc1, 0x09, 0xcb, 0x4a, 0x5d, 0xf6, 0xb3, 0xb5, 0xed, - 0x80, 0x0d, 0x49, 0x12, 0xcc, 0x52, 0xe9, 0xac, 0x37, 0xad, 0x56, 0xc9, 0x37, 0xa6, 0x7d, 0x08, - 0x8a, 0xaa, 0x07, 0x36, 0x9a, 0x56, 0xab, 0xd2, 0x71, 0xa0, 0x99, 0x21, 0x33, 0x8f, 0x0b, 0x3e, - 0xc1, 0xb8, 0x5b, 0x52, 0x2d, 0xe0, 0x2b, 0xe8, 0x2a, 0x59, 0x9e, 0x82, 0x07, 0x33, 0xf5, 0x9a, - 0xaa, 0xd0, 0x00, 0x15, 0x81, 0xbf, 0x4e, 0x31, 0x0d, 0xb1, 0x91, 0xa1, 0xe4, 0x03, 0xe3, 0xea, - 0x45, 0xea, 0x78, 0x5a, 0x14, 0x5d, 0x27, 0x63, 0xba, 0xbf, 0x5b, 0xe0, 0x9d, 0x53, 0x11, 0x7f, - 0x31, 0x8a, 0x90, 0xc4, 0x4f, 0xb3, 0x17, 0x6c, 0x1f, 0x81, 0x32, 0x4a, 0xe5, 0x90, 0x71, 0x22, - 0x27, 0xb9, 0x06, 0x5d, 0xe7, 0x8f, 0xdf, 0x0e, 0xb6, 0x74, 0xff, 0x6a, 0x29, 0x9e, 0x49, 0xd5, - 0x44, 0xfe, 0x2d, 0xd4, 0x7e, 0x0c, 0xd6, 0xf3, 0x19, 0x90, 0x91, 0x54, 0x3a, 0x4d, 0xb8, 0x6c, - 0x62, 0xc2, 0x9c, 0xa9, 0x5b, 0x56, 0xb7, 0xfe, 0xf9, 0xe6, 0x62, 0xdf, 0xf2, 0xf5, 0xd6, 0xe3, - 0x43, 0x75, 0xeb, 0xdb, 0xa4, 0xdf, 0xdf, 0x5c, 0xec, 0xef, 0xce, 0x8f, 0x9a, 0x85, 0xe3, 0xba, - 0x55, 0xb0, 0xbd, 0xe0, 0x32, 0x85, 0xe9, 0xfc, 0xbb, 0x06, 0x8a, 0xa7, 0x22, 0xb6, 0x7f, 0xb4, - 0x40, 0x75, 0xf9, 0x9c, 0x39, 0x5a, 0x7e, 0xce, 0x55, 0x8f, 0xa0, 0xf6, 0xe9, 0xff, 0xdb, 0x67, - 0x4e, 0xe7, 0x16, 0xec, 0x00, 0xdc, 0x9f, 0x36, 0xff, 0xa3, 0x95, 0xd9, 0x0c, 0xac, 0x76, 0x70, - 0x27, 0xd8, 0x0c, 0xc7, 0x19, 0xd8, 0x9c, 0x53, 0xf7, 0x83, 0x95, 0x09, 0x66, 0xa1, 0xb5, 0xf6, - 0x9d, 0xa1, 0x86, 0xaf, 0x76, 0xef, 0x1b, 0xa5, 0x66, 0xf7, 0xf3, 0x97, 0x57, 0x75, 0xeb, 0xd5, - 0x55, 0xdd, 0xfa, 0xfb, 0xaa, 0x6e, 0xfd, 0x70, 0x5d, 0x2f, 0xbc, 0xba, 0xae, 0x17, 0xfe, 0xbc, - 0xae, 0x17, 0xbe, 0xfc, 0x78, 0x66, 0xc6, 0xe9, 0xec, 0x07, 0x8c, 0xc7, 0x66, 0xed, 0x8d, 0x3f, - 0xf2, 0xce, 0x17, 0xbe, 0x2d, 0xd9, 0xe0, 0x0b, 0xd6, 0xb3, 0xa7, 0xf8, 0xe1, 0x7f, 0x01, 0x00, - 0x00, 0xff, 0xff, 0x03, 0x83, 0x36, 0x64, 0xaa, 0x07, 0x00, 0x00, + 0x8d, 0x3d, 0xef, 0xbd, 0x6f, 0xde, 0x7b, 0xf3, 0xbe, 0xf7, 0xde, 0x82, 0x3d, 0x8a, 0x53, 0xc9, + 0x19, 0xf5, 0x08, 0x95, 0x98, 0x87, 0x43, 0x44, 0xa8, 0x3c, 0x17, 0xde, 0xb8, 0xed, 0xc9, 0x73, + 0x38, 0xe2, 0x4c, 0x32, 0xdb, 0xd1, 0x10, 0x38, 0x07, 0x81, 0xe3, 0x76, 0xed, 0x5d, 0x94, 0x10, + 0xca, 0xbc, 0xec, 0x37, 0x07, 0xd7, 0xea, 0x21, 0x13, 0x09, 0x13, 0x5e, 0x80, 0x04, 0xf6, 0xc6, + 0xed, 0x00, 0x4b, 0xd4, 0xf6, 0x42, 0x46, 0xa8, 0xb6, 0x6f, 0x6b, 0x7b, 0x22, 0x62, 0x15, 0x24, + 0x11, 0xb1, 0x36, 0x54, 0x73, 0x43, 0x3f, 0x93, 0xbc, 0x5c, 0xd0, 0xa6, 0xad, 0x98, 0xc5, 0x2c, + 0xd7, 0xab, 0x93, 0xd6, 0xee, 0xc4, 0x8c, 0xc5, 0x67, 0xd8, 0x43, 0x23, 0xe2, 0x21, 0x4a, 0x99, + 0x44, 0x92, 0x30, 0x6a, 0xee, 0x3c, 0x9c, 0xb1, 0x0e, 0xa5, 0x1c, 0x99, 0x28, 0x5a, 0x9d, 0x49, + 0x41, 0x3a, 0xf0, 0x10, 0x9d, 0x68, 0xd3, 0x1e, 0x09, 0x42, 0x2f, 0x64, 0x1c, 0x7b, 0xe1, 0x10, + 0x51, 0x8a, 0xcf, 0x54, 0x7e, 0xfa, 0xa8, 0x21, 0xbb, 0xa6, 0x58, 0x03, 0x8c, 0x39, 0x1e, 0xa4, + 0x34, 0xc2, 0x5c, 0x9d, 0xb5, 0xf9, 0xd1, 0xd2, 0x5a, 0x8e, 0x10, 0x47, 0x89, 0x4e, 0xcd, 0xfd, + 0xa9, 0x08, 0x76, 0x4e, 0x45, 0xec, 0xe3, 0x98, 0x08, 0x89, 0x79, 0x6f, 0x0a, 0x3e, 0x09, 0x43, + 0x96, 0x52, 0x69, 0xef, 0x81, 0xcd, 0x01, 0x67, 0x49, 0x1f, 0x45, 0x11, 0xc7, 0x42, 0x38, 0x56, + 0xd3, 0x6a, 0x95, 0xfd, 0x8a, 0xd2, 0x9d, 0xe4, 0x2a, 0xfb, 0x13, 0xf0, 0x56, 0xc8, 0x28, 0xc5, + 0xa1, 0x7a, 0x73, 0x9f, 0x44, 0xce, 0x9a, 0xc2, 0x74, 0x9d, 0xd7, 0x97, 0x8d, 0xad, 0x09, 0x4a, + 0xce, 0x8e, 0xdd, 0x39, 0xb3, 0xeb, 0x6f, 0xde, 0xca, 0xbd, 0xc8, 0x7e, 0x0e, 0x1e, 0xde, 0xe6, + 0xd8, 0x47, 0x79, 0x5c, 0xe5, 0xa6, 0x98, 0xb9, 0x69, 0xbe, 0xbe, 0x6c, 0xec, 0xe4, 0x6e, 0xde, + 0x08, 0x73, 0xfd, 0x07, 0x64, 0x31, 0xeb, 0x5e, 0x64, 0x53, 0xb0, 0xc9, 0xf5, 0xa3, 0xfa, 0x03, + 0x8c, 0x9d, 0x52, 0xb3, 0xd8, 0xaa, 0x74, 0xaa, 0x50, 0x93, 0xa9, 0x5a, 0x02, 0xea, 0x96, 0x80, + 0x8f, 0x19, 0xa1, 0xdd, 0xc3, 0x97, 0x97, 0x8d, 0xc2, 0x2f, 0x7f, 0x35, 0x5a, 0x31, 0x91, 0xc3, + 0x34, 0x80, 0x21, 0x4b, 0x34, 0xf3, 0xfa, 0xef, 0x40, 0x44, 0x5f, 0x79, 0x72, 0x32, 0xc2, 0x22, + 0xbb, 0x20, 0xfc, 0x8a, 0x09, 0xf0, 0x04, 0x63, 0xfb, 0x08, 0xdc, 0x67, 0x3c, 0xc2, 0x9c, 0xd0, + 0xd8, 0xb9, 0xd7, 0xb4, 0x5a, 0x6f, 0x77, 0x6a, 0x90, 0x04, 0x21, 0x54, 0x24, 0x42, 0xc3, 0xdc, + 0xb8, 0x0d, 0x3f, 0x53, 0x20, 0x7f, 0x8a, 0x3d, 0xae, 0x7e, 0xf7, 0xa2, 0x51, 0xf8, 0xe7, 0x45, + 0xa3, 0xf0, 0xed, 0xcd, 0xc5, 0xfe, 0x5c, 0xa9, 0xdd, 0x08, 0xbc, 0xbf, 0x8a, 0x1a, 0x1f, 0x8b, + 0x11, 0xa3, 0x02, 0xdb, 0xbb, 0x00, 0xe8, 0x00, 0xaa, 0x6a, 0x39, 0x41, 0x65, 0xad, 0xe9, 0x45, + 0xf6, 0x36, 0xd8, 0x18, 0x31, 0x2e, 0xa7, 0xc4, 0xf8, 0xeb, 0x4a, 0xec, 0x45, 0xc7, 0x25, 0x15, + 0xda, 0xfd, 0x75, 0x0d, 0x54, 0x4e, 0x45, 0xfc, 0x2c, 0x0d, 0x12, 0x22, 0x9f, 0x9f, 0xdf, 0x85, + 0xf0, 0xce, 0x32, 0xc6, 0x72, 0xff, 0x6f, 0xe4, 0xe3, 0xbd, 0xc5, 0x26, 0xc9, 0xd8, 0x5d, 0x68, + 0x85, 0x16, 0x28, 0x25, 0x22, 0x16, 0x9a, 0xac, 0x2d, 0x98, 0x0f, 0x08, 0x34, 0x03, 0x02, 0x4f, + 0xe8, 0xc4, 0xcf, 0x10, 0xb6, 0x0d, 0x4a, 0x09, 0x4e, 0x58, 0x56, 0xea, 0xb2, 0x9f, 0x9d, 0x6d, + 0x07, 0x6c, 0x48, 0x92, 0x60, 0x96, 0x4a, 0x67, 0xbd, 0x69, 0xb5, 0x4a, 0xbe, 0x11, 0xed, 0x43, + 0x50, 0x54, 0x3d, 0xb0, 0xd1, 0xb4, 0x5a, 0x95, 0x8e, 0x03, 0xcd, 0x0e, 0x99, 0x99, 0x1c, 0xf8, + 0x04, 0xe3, 0x6e, 0x49, 0xb5, 0x80, 0xaf, 0xa0, 0xab, 0x68, 0x79, 0x0a, 0x1e, 0xcc, 0xd4, 0x6b, + 0xca, 0x42, 0x03, 0x54, 0x04, 0xfe, 0x3a, 0xc5, 0x34, 0xc4, 0x86, 0x86, 0x92, 0x0f, 0x8c, 0xaa, + 0x17, 0xa9, 0xf4, 0x34, 0x29, 0xba, 0x4e, 0x46, 0x74, 0x7f, 0xb7, 0xc0, 0x3b, 0xa7, 0x22, 0xfe, + 0x62, 0x14, 0x21, 0x89, 0x9f, 0x66, 0xe3, 0x69, 0x1f, 0x81, 0x32, 0x4a, 0xe5, 0x90, 0x71, 0x22, + 0x27, 0x39, 0x07, 0x5d, 0xe7, 0x8f, 0xdf, 0x0e, 0xb6, 0x74, 0xff, 0x6a, 0x2a, 0x9e, 0x49, 0xd5, + 0x44, 0xfe, 0x2d, 0xd4, 0x7e, 0x0c, 0xd6, 0xf3, 0x01, 0xcf, 0x82, 0x54, 0x3a, 0x4d, 0xb8, 0x6c, + 0x63, 0xc2, 0x3c, 0x52, 0xb7, 0xac, 0x5e, 0xfd, 0xf3, 0xcd, 0xc5, 0xbe, 0xe5, 0xeb, 0xab, 0xc7, + 0x87, 0xea, 0xd5, 0xb7, 0x4e, 0xbf, 0xbf, 0xb9, 0xd8, 0xdf, 0x9d, 0xdf, 0x23, 0x0b, 0xe9, 0xba, + 0x55, 0xb0, 0xbd, 0xa0, 0x32, 0x85, 0xe9, 0xfc, 0xbb, 0x06, 0x8a, 0xa7, 0x22, 0xb6, 0x7f, 0xb4, + 0x40, 0x75, 0xf9, 0x9e, 0x39, 0x5a, 0x9e, 0xe7, 0xaa, 0x21, 0xa8, 0x7d, 0xfa, 0xff, 0xee, 0x99, + 0xec, 0xdc, 0x82, 0x1d, 0x80, 0xfb, 0xd3, 0xe6, 0x7f, 0xb4, 0xd2, 0x9b, 0x81, 0xd5, 0x0e, 0xee, + 0x04, 0x9b, 0x89, 0x71, 0x06, 0x36, 0xe7, 0xd8, 0xfd, 0x60, 0xa5, 0x83, 0x59, 0x68, 0xad, 0x7d, + 0x67, 0xa8, 0x89, 0x57, 0xbb, 0xf7, 0x8d, 0x62, 0xb3, 0xfb, 0xf9, 0xcb, 0xab, 0xba, 0xf5, 0xea, + 0xaa, 0x6e, 0xfd, 0x7d, 0x55, 0xb7, 0x7e, 0xb8, 0xae, 0x17, 0x5e, 0x5d, 0xd7, 0x0b, 0x7f, 0x5e, + 0xd7, 0x0b, 0x5f, 0x7e, 0x3c, 0xb3, 0xe3, 0xb4, 0xf7, 0x03, 0xc6, 0x63, 0x73, 0xf6, 0xc6, 0x1f, + 0x79, 0xe7, 0x0b, 0x1f, 0x8e, 0x6c, 0xf1, 0x05, 0xeb, 0xd9, 0x28, 0x7e, 0xf8, 0x5f, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xda, 0x2c, 0x63, 0xb9, 0xaa, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 1f88c5c26438c2642343486c9f1fbd13476475dd Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 15 Aug 2024 15:33:03 +0400 Subject: [PATCH 12/60] fix tests --- x/interchaintxs/keeper/msg_server_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/interchaintxs/keeper/msg_server_test.go b/x/interchaintxs/keeper/msg_server_test.go index 5cecf14fa..a4aa8369f 100644 --- a/x/interchaintxs/keeper/msg_server_test.go +++ b/x/interchaintxs/keeper/msg_server_test.go @@ -113,6 +113,7 @@ func TestRegisterInterchainAccount(t *testing.T) { FromAddress: testutil.TestOwnerAddress, ConnectionId: "connection-0", InterchainAccountId: "ica0", + Ordering: channeltypes.ORDERED, } contractAddress := sdk.MustAccAddressFromBech32(msgRegAcc.FromAddress) icaOwner := types.NewICAOwnerFromAddress(contractAddress, msgRegAcc.InterchainAccountId) From 5ce70b5daaa45fdc875604275c28cec61fb09f3a Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 15 Aug 2024 15:40:38 +0400 Subject: [PATCH 13/60] lint --- x/interchaintxs/keeper/msg_server_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x/interchaintxs/keeper/msg_server_test.go b/x/interchaintxs/keeper/msg_server_test.go index a4aa8369f..d06aa20ae 100644 --- a/x/interchaintxs/keeper/msg_server_test.go +++ b/x/interchaintxs/keeper/msg_server_test.go @@ -2,10 +2,11 @@ package keeper_test import ( "fmt" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "testing" "time" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + "cosmossdk.io/math" "github.com/neutron-org/neutron/v4/app/params" @@ -13,6 +14,7 @@ import ( wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + feerefundertypes "github.com/neutron-org/neutron/v4/x/feerefunder/types" "github.com/neutron-org/neutron/v4/x/interchaintxs/keeper" From ca180052294531447cb6e573a58b2696422235cb Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Fri, 16 Aug 2024 15:02:56 +0300 Subject: [PATCH 14/60] add AddSchedule and RemoveSchedule rpc --- proto/neutron/cron/tx.proto | 39 ++ x/cron/keeper/msg_server.go | 44 +- x/cron/keeper/msg_server_test.go | 149 ++++- x/cron/types/tx.go | 93 ++- x/cron/types/tx.pb.go | 1042 ++++++++++++++++++++++++++++-- 5 files changed, 1289 insertions(+), 78 deletions(-) diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index 6bb9d3bf7..d96db6f6d 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -6,6 +6,7 @@ import "cosmos/msg/v1/msg.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "neutron/cron/params.proto"; +import "neutron/cron/schedule.proto"; // this line is used by starport scaffolding # proto/tx/import @@ -15,10 +16,48 @@ option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; service Msg { option (cosmos.msg.v1.service) = true; + // Adds new schedule. + rpc AddSchedule(MsgAddSchedule) returns (MsgAddScheduleResponse); + // Removes schedule. + rpc RemoveSchedule(MsgRemoveSchedule) returns (MsgRemoveScheduleResponse); + // Updates the module parameters. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); // this line is used by starport scaffolding # proto/tx/rpc } +// MsgAddSchedule is the MsgAddSchedule request type. +message MsgAddSchedule { + option (amino.name) = "cron/MsgAddSchedule"; + option (cosmos.msg.v1.signer) = "authority"; + + // Authority is the address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + string name = 2; + uint64 period = 3; + repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; + BlockerType blocker = 5; +} + +// MsgAddScheduleResponse defines the response structure for executing a +// MsgAddSchedule message. +message MsgAddScheduleResponse {} + +// MsgRemoveSchedule is the MsgRemoveSchedule request type. +message MsgRemoveSchedule { + option (amino.name) = "cron/MsgRemoveSchedule"; + option (cosmos.msg.v1.signer) = "authority"; + + // Authority is the address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + + string name = 2; +} + +// MsgRemoveScheduleResponse defines the response structure for executing a +// MsgRemoveSchedule message. +message MsgRemoveScheduleResponse {} + // this line is used by starport scaffolding # proto/tx/message // MsgUpdateParams is the MsgUpdateParams request type. diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index e49e578ab..399425a52 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -22,15 +22,51 @@ func NewMsgServerImpl(keeper Keeper) types.MsgServer { var _ types.MsgServer = msgServer{} +// AddSchedule adds new schedule +func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) (*types.MsgAddScheduleResponse, error) { + if err := req.Validate(); err != nil { + return nil, errors.Wrap(err, "failed to validate MsgAddSchedule") + } + + authority, reqAuthority := k.GetAuthority(), req.GetAuthority() + if authority != reqAuthority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.Keeper.AddSchedule(ctx, req.GetName(), req.GetPeriod(), req.GetMsgs(), uint64(req.GetBlocker())); err != nil { + return nil, err + } + + return &types.MsgAddScheduleResponse{}, nil +} + +// RemoveSchedule removes schedule +func (k msgServer) RemoveSchedule(goCtx context.Context, req *types.MsgRemoveSchedule) (*types.MsgRemoveScheduleResponse, error) { + if err := req.Validate(); err != nil { + return nil, errors.Wrap(err, "failed to validate MsgRemoveSchedule") + } + + authority, reqAuthority := k.GetAuthority(), req.GetAuthority() + if authority != reqAuthority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + k.Keeper.RemoveSchedule(ctx, req.GetName()) + + return &types.MsgRemoveScheduleResponse{}, nil +} + // UpdateParams updates the module parameters -func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { +func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "failed to validate MsgUpdateParams") } - authority := k.GetAuthority() - if authority != req.Authority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) + authority, reqAuthority := k.GetAuthority(), req.GetAuthority() + if authority != reqAuthority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) } ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index 17a3655ac..889bfcf13 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -6,12 +6,155 @@ import ( "github.com/stretchr/testify/require" "github.com/neutron-org/neutron/v4/testutil" - "github.com/neutron-org/neutron/v4/testutil/cron/keeper" + testkeeper "github.com/neutron-org/neutron/v4/testutil/cron/keeper" + cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" "github.com/neutron-org/neutron/v4/x/cron/types" ) +func TestMsgAddScheduleValidate(t *testing.T) { + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) + + tests := []struct { + name string + msg types.MsgAddSchedule + expectedErr string + }{ + { + "empty authority", + types.MsgAddSchedule{ + Authority: "", + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + Blocker: types.BlockerType_BEGIN, + }, + "authority is invalid", + }, + { + "invalid authority", + types.MsgAddSchedule{ + Authority: "invalid authority", + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + Blocker: types.BlockerType_BEGIN, + }, + "authority is invalid", + }, + { + "invalid name", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + Blocker: types.BlockerType_BEGIN, + }, + "name is invalid", + }, + { + "invalid period", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 0, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + Blocker: types.BlockerType_BEGIN, + }, + "period is invalid", + }, + { + "empty msgs", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{}, + Blocker: types.BlockerType_BEGIN, + }, + "msgs should not be empty", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + resp, err := msgServer.AddSchedule(ctx, &tt.msg) + require.ErrorContains(t, err, tt.expectedErr) + require.Nil(t, resp) + }) + } +} + +func TestMsgRemoveScheduleValidate(t *testing.T) { + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) + + tests := []struct { + name string + msg types.MsgRemoveSchedule + expectedErr string + }{ + { + "empty authority", + types.MsgRemoveSchedule{ + Authority: "", + Name: "name", + }, + "authority is invalid", + }, + { + "invalid authority", + types.MsgRemoveSchedule{ + Authority: "", + Name: "name", + }, + "authority is invalid", + }, + { + "invalid name", + types.MsgRemoveSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "", + }, + "name is invalid", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + resp, err := msgServer.RemoveSchedule(ctx, &tt.msg) + require.ErrorContains(t, err, tt.expectedErr) + require.Nil(t, resp) + }) + } +} + func TestMsgUpdateParamsValidate(t *testing.T) { - k, ctx := keeper.CronKeeper(t, nil, nil) + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) tests := []struct { name string @@ -57,7 +200,7 @@ func TestMsgUpdateParamsValidate(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - resp, err := k.UpdateParams(ctx, &tt.msg) + resp, err := msgServer.UpdateParams(ctx, &tt.msg) require.ErrorContains(t, err, tt.expectedErr) require.Nil(t, resp) }) diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index eb48677cb..b9d4e652f 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -1,10 +1,91 @@ package types import ( - errorsmod "cosmossdk.io/errors" + "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +var _ sdk.Msg = &MsgAddSchedule{} + +func (msg *MsgAddSchedule) Route() string { + return RouterKey +} + +func (msg *MsgAddSchedule) Type() string { + return "add-schedule" +} + +func (msg *MsgAddSchedule) GetSigners() []sdk.AccAddress { + authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) + if err != nil { // should never happen as valid basic rejects invalid addresses + panic(err.Error()) + } + return []sdk.AccAddress{authority} +} + +func (msg *MsgAddSchedule) GetSignBytes() []byte { + return ModuleCdc.MustMarshalJSON(msg) +} + +func (msg *MsgAddSchedule) Validate() error { + if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + return errors.Wrap(err, "authority is invalid") + } + + if msg.GetName() == "" { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") + } + + if msg.GetPeriod() == 0 { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "period is invalid") + } + + if len(msg.GetMsgs()) == 0 { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") + } + + return nil +} + +//---------------------------------------------------------------- + +var _ sdk.Msg = &MsgRemoveSchedule{} + +func (msg *MsgRemoveSchedule) Route() string { + return RouterKey +} + +func (msg *MsgRemoveSchedule) Type() string { + return "remove-schedule" +} + +func (msg *MsgRemoveSchedule) GetSigners() []sdk.AccAddress { + authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) + if err != nil { // should never happen as valid basic rejects invalid addresses + panic(err.Error()) + } + return []sdk.AccAddress{authority} +} + +func (msg *MsgRemoveSchedule) GetSignBytes() []byte { + return ModuleCdc.MustMarshalJSON(msg) +} + +func (msg *MsgRemoveSchedule) Validate() error { + if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + return errors.Wrap(err, "authority is invalid") + } + + if msg.GetName() == "" { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") + } + + return nil +} + +//---------------------------------------------------------------- + var _ sdk.Msg = &MsgUpdateParams{} func (msg *MsgUpdateParams) Route() string { @@ -16,7 +97,7 @@ func (msg *MsgUpdateParams) Type() string { } func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.Authority) + authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) if err != nil { // should never happen as valid basic rejects invalid addresses panic(err.Error()) } @@ -28,12 +109,12 @@ func (msg *MsgUpdateParams) GetSignBytes() []byte { } func (msg *MsgUpdateParams) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { - return errorsmod.Wrap(err, "authority is invalid") + if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + return errors.Wrap(err, "authority is invalid") } - if _, err := sdk.AccAddressFromBech32(msg.Params.SecurityAddress); err != nil { - return errorsmod.Wrap(err, "security_address is invalid") + if _, err := sdk.AccAddressFromBech32(msg.GetParams().SecurityAddress); err != nil { + return errors.Wrap(err, "security_address is invalid") } return nil diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 217bb879c..c37a063ef 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -31,6 +31,214 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// MsgAddSchedule is the MsgAddSchedule request type. +type MsgAddSchedule struct { + // Authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` + Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` + Blocker BlockerType `protobuf:"varint,5,opt,name=blocker,proto3,enum=neutron.cron.BlockerType" json:"blocker,omitempty"` +} + +func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } +func (m *MsgAddSchedule) String() string { return proto.CompactTextString(m) } +func (*MsgAddSchedule) ProtoMessage() {} +func (*MsgAddSchedule) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{0} +} +func (m *MsgAddSchedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddSchedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddSchedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddSchedule.Merge(m, src) +} +func (m *MsgAddSchedule) XXX_Size() int { + return m.Size() +} +func (m *MsgAddSchedule) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddSchedule.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddSchedule proto.InternalMessageInfo + +func (m *MsgAddSchedule) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgAddSchedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *MsgAddSchedule) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + +func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { + if m != nil { + return m.Msgs + } + return nil +} + +func (m *MsgAddSchedule) GetBlocker() BlockerType { + if m != nil { + return m.Blocker + } + return BlockerType_BEGIN +} + +// MsgAddScheduleResponse defines the response structure for executing a +// MsgAddSchedule message. +type MsgAddScheduleResponse struct { +} + +func (m *MsgAddScheduleResponse) Reset() { *m = MsgAddScheduleResponse{} } +func (m *MsgAddScheduleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAddScheduleResponse) ProtoMessage() {} +func (*MsgAddScheduleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{1} +} +func (m *MsgAddScheduleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddScheduleResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddScheduleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddScheduleResponse.Merge(m, src) +} +func (m *MsgAddScheduleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAddScheduleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddScheduleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddScheduleResponse proto.InternalMessageInfo + +// MsgRemoveSchedule is the MsgRemoveSchedule request type. +type MsgRemoveSchedule struct { + // Authority is the address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (m *MsgRemoveSchedule) Reset() { *m = MsgRemoveSchedule{} } +func (m *MsgRemoveSchedule) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveSchedule) ProtoMessage() {} +func (*MsgRemoveSchedule) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{2} +} +func (m *MsgRemoveSchedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveSchedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveSchedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveSchedule.Merge(m, src) +} +func (m *MsgRemoveSchedule) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveSchedule) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveSchedule.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveSchedule proto.InternalMessageInfo + +func (m *MsgRemoveSchedule) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgRemoveSchedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +// MsgRemoveScheduleResponse defines the response structure for executing a +// MsgRemoveSchedule message. +type MsgRemoveScheduleResponse struct { +} + +func (m *MsgRemoveScheduleResponse) Reset() { *m = MsgRemoveScheduleResponse{} } +func (m *MsgRemoveScheduleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveScheduleResponse) ProtoMessage() {} +func (*MsgRemoveScheduleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{3} +} +func (m *MsgRemoveScheduleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveScheduleResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveScheduleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveScheduleResponse.Merge(m, src) +} +func (m *MsgRemoveScheduleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveScheduleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveScheduleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveScheduleResponse proto.InternalMessageInfo + // MsgUpdateParams is the MsgUpdateParams request type. // // Since: 0.47 @@ -47,7 +255,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{0} + return fileDescriptor_c9e0a673aba8d6fd, []int{4} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -101,7 +309,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{1} + return fileDescriptor_c9e0a673aba8d6fd, []int{5} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -131,6 +339,10 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { + proto.RegisterType((*MsgAddSchedule)(nil), "neutron.cron.MsgAddSchedule") + proto.RegisterType((*MsgAddScheduleResponse)(nil), "neutron.cron.MsgAddScheduleResponse") + proto.RegisterType((*MsgRemoveSchedule)(nil), "neutron.cron.MsgRemoveSchedule") + proto.RegisterType((*MsgRemoveScheduleResponse)(nil), "neutron.cron.MsgRemoveScheduleResponse") proto.RegisterType((*MsgUpdateParams)(nil), "neutron.cron.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "neutron.cron.MsgUpdateParamsResponse") } @@ -138,28 +350,42 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 335 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0x4b, 0x2d, 0x2d, - 0x29, 0xca, 0xcf, 0xd3, 0x4f, 0x06, 0x11, 0x25, 0x15, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, - 0x3c, 0x50, 0x61, 0x3d, 0x90, 0xb0, 0x94, 0x60, 0x62, 0x6e, 0x66, 0x5e, 0xbe, 0x3e, 0x98, 0x84, - 0x28, 0x90, 0x12, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0xcf, 0x2d, 0x4e, 0xd7, 0x2f, 0x33, - 0x04, 0x51, 0x50, 0x09, 0x49, 0x88, 0x44, 0x3c, 0x98, 0xa7, 0x0f, 0xe1, 0x40, 0xa5, 0x44, 0xd2, - 0xf3, 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16, 0x4c, 0x03, 0x8a, 0x0b, 0x0a, 0x12, 0x8b, 0x12, 0x73, - 0xa1, 0x1a, 0x94, 0x56, 0x33, 0x72, 0xf1, 0xfb, 0x16, 0xa7, 0x87, 0x16, 0xa4, 0x24, 0x96, 0xa4, - 0x06, 0x80, 0x65, 0x84, 0xcc, 0xb8, 0x38, 0x13, 0x4b, 0x4b, 0x32, 0xf2, 0x8b, 0x32, 0x4b, 0x2a, - 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x9d, 0x24, 0x2e, 0x6d, 0xd1, 0x15, 0x81, 0xda, 0xe4, 0x98, - 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x1e, 0x84, 0x50, 0x2a, 0x64, - 0xce, 0xc5, 0x06, 0x31, 0x5b, 0x82, 0x49, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x44, 0x0f, 0xd9, 0x8b, - 0x7a, 0x10, 0xd3, 0x9d, 0x38, 0x4f, 0xdc, 0x93, 0x67, 0x58, 0xf1, 0x7c, 0x83, 0x16, 0x63, 0x10, - 0x54, 0xb9, 0x95, 0x7a, 0xd3, 0xf3, 0x0d, 0x5a, 0x08, 0x83, 0xba, 0x9e, 0x6f, 0xd0, 0x12, 0x01, - 0x3b, 0x15, 0xcd, 0x65, 0x4a, 0x92, 0x5c, 0xe2, 0x68, 0x42, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, - 0xc5, 0xa9, 0x46, 0x49, 0x5c, 0xcc, 0xbe, 0xc5, 0xe9, 0x42, 0x21, 0x5c, 0x3c, 0x28, 0x7e, 0x91, - 0x45, 0x75, 0x03, 0x9a, 0x6e, 0x29, 0x55, 0xbc, 0xd2, 0x30, 0xc3, 0xa5, 0x58, 0x1b, 0x40, 0xee, - 0x75, 0xf2, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, - 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xbd, 0xf4, 0xcc, - 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xa8, 0x89, 0xba, 0xf9, 0x45, 0xe9, 0x30, - 0xb6, 0x7e, 0x99, 0x89, 0x7e, 0x05, 0x34, 0xfe, 0x2b, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xa1, - 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x60, 0xa1, 0xa6, 0xeb, 0x1c, 0x02, 0x00, 0x00, + // 550 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcf, 0x8b, 0xd3, 0x40, + 0x14, 0xee, 0xb4, 0xdd, 0x4a, 0xa7, 0x4b, 0x65, 0x63, 0xed, 0xa6, 0x59, 0xcd, 0x96, 0xa2, 0x6e, + 0x2d, 0x6c, 0x82, 0x5d, 0x51, 0xe8, 0x6d, 0x23, 0x82, 0x97, 0x80, 0x66, 0xd7, 0xcb, 0x5e, 0x24, + 0x4d, 0x86, 0x69, 0x70, 0x93, 0x09, 0x33, 0x93, 0xd2, 0xde, 0xc4, 0xe3, 0x82, 0xa0, 0xff, 0x85, + 0xe0, 0xa5, 0x07, 0xff, 0x88, 0x3d, 0x2e, 0x9e, 0x3c, 0x89, 0xb4, 0x87, 0xfe, 0x1b, 0x92, 0x5f, + 0xbb, 0xc9, 0x06, 0x56, 0x10, 0xbc, 0x4c, 0x66, 0xde, 0xf7, 0xbe, 0x97, 0xef, 0x7d, 0xf3, 0x18, + 0x78, 0xd7, 0x43, 0x01, 0xa7, 0xc4, 0x53, 0xad, 0x70, 0xe1, 0x33, 0xc5, 0xa7, 0x84, 0x13, 0x61, + 0x33, 0x09, 0x2b, 0x61, 0x58, 0xda, 0x32, 0x5d, 0xc7, 0x23, 0x6a, 0xb4, 0xc6, 0x09, 0xd2, 0xb6, + 0x45, 0x98, 0x4b, 0x98, 0xea, 0x32, 0xac, 0x4e, 0x9f, 0x84, 0x9f, 0x04, 0xe8, 0xc4, 0xc0, 0xbb, + 0xe8, 0xa4, 0xc6, 0x87, 0x04, 0x6a, 0x61, 0x82, 0x49, 0x1c, 0x0f, 0x77, 0x29, 0x21, 0xa7, 0xc0, + 0x37, 0xa9, 0xe9, 0xa6, 0x84, 0x9d, 0x1c, 0xc4, 0xac, 0x09, 0xb2, 0x83, 0x53, 0x14, 0x83, 0xbd, + 0x4f, 0x65, 0xd8, 0xd4, 0x19, 0x3e, 0xb4, 0xed, 0xa3, 0x04, 0x10, 0x9e, 0xc1, 0xba, 0x19, 0xf0, + 0x09, 0xa1, 0x0e, 0x9f, 0x8b, 0xa0, 0x0b, 0xfa, 0x75, 0x4d, 0xfc, 0xf1, 0x7d, 0xbf, 0x95, 0xa8, + 0x38, 0xb4, 0x6d, 0x8a, 0x18, 0x3b, 0xe2, 0xd4, 0xf1, 0xb0, 0x71, 0x95, 0x2a, 0x08, 0xb0, 0xea, + 0x99, 0x2e, 0x12, 0xcb, 0x21, 0xc5, 0x88, 0xf6, 0x42, 0x1b, 0xd6, 0x7c, 0x44, 0x1d, 0x62, 0x8b, + 0x95, 0x2e, 0xe8, 0x57, 0x8d, 0xe4, 0x24, 0x8c, 0x60, 0xd5, 0x65, 0x98, 0x89, 0xd5, 0x6e, 0xa5, + 0xdf, 0x18, 0x76, 0x95, 0xac, 0x51, 0x8a, 0xce, 0xf0, 0xcb, 0x19, 0xb2, 0x02, 0x8e, 0x5e, 0x10, + 0x8f, 0x53, 0xd3, 0xe2, 0x5a, 0xf5, 0xfc, 0xd7, 0x6e, 0xc9, 0x88, 0x38, 0xc2, 0x01, 0xbc, 0x35, + 0x3e, 0x25, 0xd6, 0x7b, 0x44, 0xc5, 0x8d, 0x2e, 0xe8, 0x37, 0x87, 0x9d, 0x3c, 0x5d, 0x8b, 0xc1, + 0xe3, 0xb9, 0x8f, 0x8c, 0x34, 0x73, 0xf4, 0xe8, 0xe3, 0x7a, 0x31, 0xb8, 0x12, 0x7b, 0xb6, 0x5e, + 0x0c, 0xee, 0x44, 0x7e, 0xe4, 0x9b, 0xef, 0x89, 0xb0, 0x9d, 0x8f, 0x18, 0x88, 0xf9, 0xc4, 0x63, + 0xa8, 0x77, 0x06, 0xe0, 0x96, 0xce, 0xb0, 0x81, 0x5c, 0x32, 0x45, 0xff, 0xc3, 0xac, 0xd1, 0xe3, + 0xa2, 0xc6, 0x76, 0xaa, 0x31, 0xff, 0xdb, 0xde, 0x0e, 0xec, 0x14, 0x82, 0x97, 0x4a, 0xbf, 0x01, + 0x78, 0x5b, 0x67, 0xf8, 0xad, 0x6f, 0x9b, 0x1c, 0xbd, 0x8e, 0x46, 0xe1, 0x9f, 0x75, 0x3e, 0x87, + 0xb5, 0x78, 0x98, 0x22, 0xa5, 0x8d, 0x61, 0x2b, 0xef, 0x75, 0x5c, 0x5d, 0xab, 0x87, 0xd7, 0xf3, + 0x75, 0xbd, 0x18, 0x00, 0x23, 0x49, 0x1f, 0xed, 0x15, 0x9b, 0x69, 0xa5, 0xcd, 0x64, 0x95, 0xf5, + 0x3a, 0x70, 0xfb, 0x5a, 0x28, 0x6d, 0x64, 0xf8, 0xa5, 0x0c, 0x2b, 0x3a, 0xc3, 0xc2, 0x1b, 0xd8, + 0xc8, 0x0e, 0xe8, 0xbd, 0xc2, 0xb8, 0x64, 0x50, 0xe9, 0xc1, 0x4d, 0x68, 0x5a, 0x5a, 0x38, 0x81, + 0xcd, 0x6b, 0x37, 0xb9, 0x5b, 0xe0, 0xe5, 0x13, 0xa4, 0xbd, 0xbf, 0x24, 0x5c, 0xd6, 0x3e, 0x86, + 0x9b, 0x39, 0xef, 0xef, 0x17, 0x88, 0x59, 0x58, 0x7a, 0x78, 0x23, 0x9c, 0x56, 0x95, 0x36, 0x3e, + 0x84, 0xfe, 0x6a, 0xaf, 0xce, 0x97, 0x32, 0xb8, 0x58, 0xca, 0xe0, 0xf7, 0x52, 0x06, 0x9f, 0x57, + 0x72, 0xe9, 0x62, 0x25, 0x97, 0x7e, 0xae, 0xe4, 0xd2, 0x89, 0x82, 0x1d, 0x3e, 0x09, 0xc6, 0x8a, + 0x45, 0x5c, 0x35, 0xa9, 0xb8, 0x4f, 0x28, 0x4e, 0xf7, 0xea, 0xf4, 0xa9, 0x3a, 0x4b, 0x1e, 0xa8, + 0xb9, 0x8f, 0xd8, 0xb8, 0x16, 0xbd, 0x00, 0x07, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x0f, + 0x7b, 0xac, 0xbd, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -174,6 +400,11 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { + // Adds new schedule. + AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) + // Removes schedule. + RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) + // Updates the module parameters. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -185,6 +416,24 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } +func (c *msgClient) AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) { + out := new(MsgAddScheduleResponse) + err := c.cc.Invoke(ctx, "/neutron.cron.Msg/AddSchedule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) { + out := new(MsgRemoveScheduleResponse) + err := c.cc.Invoke(ctx, "/neutron.cron.Msg/RemoveSchedule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/neutron.cron.Msg/UpdateParams", in, out, opts...) @@ -196,6 +445,11 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { + // Adds new schedule. + AddSchedule(context.Context, *MsgAddSchedule) (*MsgAddScheduleResponse, error) + // Removes schedule. + RemoveSchedule(context.Context, *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) + // Updates the module parameters. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -203,6 +457,12 @@ type MsgServer interface { type UnimplementedMsgServer struct { } +func (*UnimplementedMsgServer) AddSchedule(ctx context.Context, req *MsgAddSchedule) (*MsgAddScheduleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSchedule not implemented") +} +func (*UnimplementedMsgServer) RemoveSchedule(ctx context.Context, req *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveSchedule not implemented") +} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -211,6 +471,42 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } +func _Msg_AddSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAddSchedule) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AddSchedule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/neutron.cron.Msg/AddSchedule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AddSchedule(ctx, req.(*MsgAddSchedule)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RemoveSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRemoveSchedule) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RemoveSchedule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/neutron.cron.Msg/RemoveSchedule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RemoveSchedule(ctx, req.(*MsgRemoveSchedule)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -233,6 +529,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "neutron.cron.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "AddSchedule", + Handler: _Msg_AddSchedule_Handler, + }, + { + MethodName: "RemoveSchedule", + Handler: _Msg_RemoveSchedule_Handler, + }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -242,7 +546,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "neutron/cron/tx.proto", } -func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { +func (m *MsgAddSchedule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -252,26 +556,47 @@ func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAddSchedule) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.Blocker != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Blocker)) + i-- + dAtA[i] = 0x28 + } + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x12 + if m.Period != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x18 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } if len(m.Authority) > 0 { i -= len(m.Authority) copy(dAtA[i:], m.Authority) @@ -282,7 +607,7 @@ func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgAddScheduleResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -292,12 +617,12 @@ func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAddScheduleResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAddScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -305,47 +630,634 @@ func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgRemoveSchedule) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgUpdateParams) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgRemoveSchedule) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 } - l = m.Params.Size() - n += 1 + l + sovTx(uint64(l)) - return n + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *MsgUpdateParamsResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgRemoveScheduleResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *MsgRemoveScheduleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - return n + return len(dAtA) - i, nil } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTx(x uint64) (n int) { +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAddSchedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Period != 0 { + n += 1 + sovTx(uint64(m.Period)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if m.Blocker != 0 { + n += 1 + sovTx(uint64(m.Blocker)) + } + return n +} + +func (m *MsgAddScheduleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRemoveSchedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRemoveScheduleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } +func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddSchedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddSchedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", 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 + } + m.Msgs = append(m.Msgs, MsgExecuteContract{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Blocker", wireType) + } + m.Blocker = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Blocker |= BlockerType(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddScheduleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddScheduleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveSchedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveSchedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveSchedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveScheduleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveScheduleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 From ebfc003cc2d61f29a350934dc5b4193f4f484c2d Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Fri, 16 Aug 2024 15:55:28 +0300 Subject: [PATCH 15/60] fix proto --- proto/neutron/cron/tx.proto | 6 +++--- x/cron/keeper/msg_server.go | 22 +++++++++++----------- x/cron/types/codec.go | 2 ++ x/cron/types/tx.go | 22 +++++++++++----------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index d96db6f6d..d4f385e5b 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -34,9 +34,9 @@ message MsgAddSchedule { string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; string name = 2; - uint64 period = 3; - repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - BlockerType blocker = 5; + uint64 period = 3; + repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; + BlockerType blocker = 5; } // MsgAddScheduleResponse defines the response structure for executing a diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index 399425a52..5ab7d62d4 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -28,13 +28,13 @@ func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) return nil, errors.Wrap(err, "failed to validate MsgAddSchedule") } - authority, reqAuthority := k.GetAuthority(), req.GetAuthority() - if authority != reqAuthority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) + authority := k.GetAuthority() + if authority != req.Authority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.Keeper.AddSchedule(ctx, req.GetName(), req.GetPeriod(), req.GetMsgs(), uint64(req.GetBlocker())); err != nil { + if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, uint64(req.Blocker)); err != nil { return nil, err } @@ -47,13 +47,13 @@ func (k msgServer) RemoveSchedule(goCtx context.Context, req *types.MsgRemoveSch return nil, errors.Wrap(err, "failed to validate MsgRemoveSchedule") } - authority, reqAuthority := k.GetAuthority(), req.GetAuthority() - if authority != reqAuthority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) + authority := k.GetAuthority() + if authority != req.Authority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - k.Keeper.RemoveSchedule(ctx, req.GetName()) + k.Keeper.RemoveSchedule(ctx, req.Name) return &types.MsgRemoveScheduleResponse{}, nil } @@ -64,9 +64,9 @@ func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParam return nil, errors.Wrap(err, "failed to validate MsgUpdateParams") } - authority, reqAuthority := k.GetAuthority(), req.GetAuthority() - if authority != reqAuthority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, reqAuthority) + authority := k.GetAuthority() + if authority != req.Authority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) diff --git a/x/cron/types/codec.go b/x/cron/types/codec.go index a52eff2c6..6772e97b9 100644 --- a/x/cron/types/codec.go +++ b/x/cron/types/codec.go @@ -15,6 +15,8 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgUpdateParams{}, + &MsgAddSchedule{}, + &MsgRemoveSchedule{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index b9d4e652f..1bca78a71 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -17,7 +17,7 @@ func (msg *MsgAddSchedule) Type() string { } func (msg *MsgAddSchedule) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) + authority, err := sdk.AccAddressFromBech32(msg.Authority) if err != nil { // should never happen as valid basic rejects invalid addresses panic(err.Error()) } @@ -29,19 +29,19 @@ func (msg *MsgAddSchedule) GetSignBytes() []byte { } func (msg *MsgAddSchedule) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "authority is invalid") } - if msg.GetName() == "" { + if msg.Name == "" { return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") } - if msg.GetPeriod() == 0 { + if msg.Period == 0 { return errors.Wrap(sdkerrors.ErrInvalidRequest, "period is invalid") } - if len(msg.GetMsgs()) == 0 { + if len(msg.Msgs) == 0 { return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") } @@ -61,7 +61,7 @@ func (msg *MsgRemoveSchedule) Type() string { } func (msg *MsgRemoveSchedule) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) + authority, err := sdk.AccAddressFromBech32(msg.Authority) if err != nil { // should never happen as valid basic rejects invalid addresses panic(err.Error()) } @@ -73,11 +73,11 @@ func (msg *MsgRemoveSchedule) GetSignBytes() []byte { } func (msg *MsgRemoveSchedule) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "authority is invalid") } - if msg.GetName() == "" { + if msg.Name == "" { return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") } @@ -97,7 +97,7 @@ func (msg *MsgUpdateParams) Type() string { } func (msg *MsgUpdateParams) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.GetAuthority()) + authority, err := sdk.AccAddressFromBech32(msg.Authority) if err != nil { // should never happen as valid basic rejects invalid addresses panic(err.Error()) } @@ -109,11 +109,11 @@ func (msg *MsgUpdateParams) GetSignBytes() []byte { } func (msg *MsgUpdateParams) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.GetAuthority()); err != nil { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { return errors.Wrap(err, "authority is invalid") } - if _, err := sdk.AccAddressFromBech32(msg.GetParams().SecurityAddress); err != nil { + if _, err := sdk.AccAddressFromBech32(msg.Params.SecurityAddress); err != nil { return errors.Wrap(err, "security_address is invalid") } From fd5e5e5bd6d061f19a566e71aaaeaabe59406069 Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Mon, 19 Aug 2024 11:57:38 +0300 Subject: [PATCH 16/60] make edits --- proto/neutron/cron/schedule.proto | 14 +-- proto/neutron/cron/tx.proto | 2 +- proto/neutron/cron/v1/schedule.proto | 29 ++++++ wasmbinding/bindings/msg.go | 8 +- wasmbinding/message_plugin.go | 10 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 2 +- x/cron/keeper/keeper.go | 25 ++--- x/cron/keeper/keeper_test.go | 36 ++++---- x/cron/keeper/msg_server.go | 2 +- x/cron/keeper/msg_server_test.go | 18 ++-- x/cron/migrations/v2/store.go | 8 +- x/cron/migrations/v2/store_test.go | 10 +- x/cron/module.go | 4 +- x/cron/types/schedule.pb.go | 108 +++++++++++----------- x/cron/types/tx.pb.go | 102 ++++++++++---------- x/cron/types/v1/schedule.pb.go | 68 +++++++------- 17 files changed, 240 insertions(+), 208 deletions(-) create mode 100644 proto/neutron/cron/v1/schedule.proto diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index 8b60fd950..88baf0b8a 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -5,11 +5,11 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// BlockerType defines when messages will be executed in the block -enum BlockerType { - BEGIN = 0; - END = 1; - BOTH = 2; +// ExecutionStage defines when messages will be executed in the block +enum ExecutionStage { + BEGIN_BLOCKER = 0; + END_BLOCKER = 1; + BOTH_BLOCKERS = 2; } message Schedule { @@ -21,8 +21,8 @@ message Schedule { repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; - // Blocker where the messages will be executed - BlockerType blocker = 5; + // Execution stage when messages will be executed + ExecutionStage execution_stage = 5; } message MsgExecuteContract { diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index d4f385e5b..fde954369 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -36,7 +36,7 @@ message MsgAddSchedule { string name = 2; uint64 period = 3; repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - BlockerType blocker = 5; + ExecutionStage execution_stage = 5; } // MsgAddScheduleResponse defines the response structure for executing a diff --git a/proto/neutron/cron/v1/schedule.proto b/proto/neutron/cron/v1/schedule.proto new file mode 100644 index 000000000..b1f824918 --- /dev/null +++ b/proto/neutron/cron/v1/schedule.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package neutron.cron.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/neutron-org/neutron/v4/x/cron/types/v1"; + +message Schedule { + // Name of schedule + string name = 1; + // Period in blocks + uint64 period = 2; + // Msgs that will be executed every period amount of time + repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; + // Last execution's block height + uint64 last_execute_height = 4; +} + +message MsgExecuteContract { + // Contract is the address of the smart contract + string contract = 1; + // Msg is json encoded message to be passed to the contract + string msg = 2; +} + +message ScheduleCount { + // Count is the number of current schedules + int32 count = 1; +} diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 9f38c0fb0..c1697401d 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -195,10 +195,10 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` - Blocker uint64 `json:"blocker"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` + ExecutionStage string `json:"execution_stage"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index d6fe12fdc..73c9282c9 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -985,7 +985,15 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, addSchedule.Blocker) + var executionStage crontypes.ExecutionStage + + if v, ok := crontypes.ExecutionStage_value[addSchedule.ExecutionStage]; !ok { + executionStage = crontypes.ExecutionStage_END_BLOCKER + } else { + executionStage = crontypes.ExecutionStage(v) + } + + err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, executionStage) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), diff --git a/x/cron/genesis.go b/x/cron/genesis.go index b5e0e1b01..525840e26 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, uint64(elem.Blocker)) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStage) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index f8825aca3..8f971f63d 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -134,7 +134,7 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, uint64(item.Blocker)) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 8da755a5f..0a9e8c0ce 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -67,17 +67,12 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // ExecuteReadySchedules gets all schedules that are due for execution (with limit that is equal to Params.Limit) // and executes messages in each one // NOTE that errors in contract calls rollback all already executed messages -func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, isBeginBlocker bool) { +func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.ExecutionStage) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) schedules := k.getSchedulesReadyForExecution(ctx) for _, schedule := range schedules { - if isBeginBlocker && (schedule.Blocker == types.BlockerType_BEGIN || schedule.Blocker == types.BlockerType_BOTH) { - err := k.executeSchedule(ctx, schedule) - recordExecutedSchedule(err, schedule) - } - - if !isBeginBlocker && (schedule.Blocker == types.BlockerType_END || schedule.Blocker == types.BlockerType_BOTH) { + if isExecutableAtTheStage(schedule, executionStage) { err := k.executeSchedule(ctx, schedule) recordExecutedSchedule(err, schedule) } @@ -91,7 +86,7 @@ func (k *Keeper) AddSchedule( name string, period uint64, msgs []types.MsgExecuteContract, - blocker uint64, + executionStage types.ExecutionStage, ) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) @@ -102,15 +97,11 @@ func (k *Keeper) AddSchedule( Period: period, Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block + ExecutionStage: executionStage, } - switch blocker { - case 0: - schedule.Blocker = types.BlockerType_BEGIN - case 2: - schedule.Blocker = types.BlockerType_BOTH - default: - schedule.Blocker = types.BlockerType_END + if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { + schedule.ExecutionStage = types.ExecutionStage_END_BLOCKER } k.storeSchedule(ctx, schedule) @@ -192,6 +183,10 @@ func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule return res } +func isExecutableAtTheStage(schedule types.Schedule, executionStage types.ExecutionStage) bool { + return schedule.ExecutionStage == executionStage || schedule.ExecutionStage == types.ExecutionStage_BOTH_BLOCKERS +} + // executeSchedule executes all msgs in a given schedule and changes LastExecuteHeight // if at least one msg execution fails, rollback all messages func (k *Keeper) executeSchedule(ctx sdk.Context, schedule types.Schedule) error { diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index 12f88bd60..3042e839b 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -52,7 +52,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, { Name: "2_ready1", @@ -64,7 +64,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, { Name: "3_ready2", @@ -76,14 +76,14 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, { Name: "4_unready2", Period: 10, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, - Blocker: types.BlockerType_BOTH, + ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, }, { Name: "5_ready3", @@ -95,7 +95,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - Blocker: types.BlockerType_BOTH, + ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, }, { Name: "6_ready4", @@ -107,7 +107,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - Blocker: types.BlockerType_END, + ExecutionStage: types.ExecutionStage_END_BLOCKER, }, { Name: "7_ready5", @@ -119,13 +119,13 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - Blocker: types.BlockerType_BOTH, + ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, uint64(item.Blocker)) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) } @@ -148,7 +148,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, true) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) unready1, _ := k.GetSchedule(ctx, "1_unready1") ready1, _ := k.GetSchedule(ctx, "2_ready1") @@ -181,7 +181,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, false) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_END_BLOCKER) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") @@ -206,7 +206,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, true) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) ready5, _ := k.GetSchedule(ctx, "7_ready5") @@ -221,7 +221,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, false) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_END_BLOCKER) ready5, _ = k.GetSchedule(ctx, "7_ready5") @@ -291,10 +291,10 @@ func TestAddSchedule(t *testing.T) { schedules := k.GetAllSchedules(ctx) require.Len(t, schedules, 4) - require.Equal(t, schedules[0].Blocker, types.BlockerType_BEGIN) - require.Equal(t, schedules[1].Blocker, types.BlockerType_END) - require.Equal(t, schedules[2].Blocker, types.BlockerType_BOTH) - require.Equal(t, schedules[3].Blocker, types.BlockerType_END) + require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_BEGIN_BLOCKER) + require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_END_BLOCKER) + require.Equal(t, schedules[2].ExecutionStage, types.ExecutionStage_BOTH_BLOCKERS) + require.Equal(t, schedules[3].ExecutionStage, types.ExecutionStage_END_BLOCKER) // remove schedule works k.RemoveSchedule(ctx, "a") @@ -321,10 +321,10 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), - Blocker: types.BlockerType_END, + ExecutionStage: types.ExecutionStage_END_BLOCKER, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, uint64(s.Blocker)) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStage) require.NoError(t, err) } diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index 5ab7d62d4..03f84220f 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -34,7 +34,7 @@ func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, uint64(req.Blocker)); err != nil { + if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { return nil, err } diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index 889bfcf13..c1d4b6e79 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -32,7 +32,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, "authority is invalid", }, @@ -48,7 +48,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, "authority is invalid", }, @@ -64,7 +64,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, "name is invalid", }, @@ -80,18 +80,18 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - Blocker: types.BlockerType_BEGIN, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, "period is invalid", }, { "empty msgs", types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{}, - Blocker: types.BlockerType_BEGIN, + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{}, + ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, }, "msgs should not be empty", }, diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go index a1f8008a8..0f519a64d 100644 --- a/x/cron/migrations/v2/store.go +++ b/x/cron/migrations/v2/store.go @@ -1,7 +1,7 @@ package v2 import ( - errorsmod "cosmossdk.io/errors" + "cosmossdk.io/errors" "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" @@ -11,7 +11,7 @@ import ( ) // MigrateStore performs in-place store migrations. -// The migration adds Blocker for execution to schedules. +// The migration adds execution stage for schedules. func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { return migrateSchedules(ctx, cdc, storeKey) } @@ -32,7 +32,7 @@ func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetype var schedule types.Schedule cdc.MustUnmarshal(iterator.Value(), &schedule) // Set execution in EndBlocker - schedule.Blocker = types.BlockerType_END + schedule.ExecutionStage = types.ExecutionStage_END_BLOCKER schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ key: iterator.Key(), @@ -42,7 +42,7 @@ func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetype err := iterator.Close() if err != nil { - return errorsmod.Wrap(err, "iterator failed to close during migration") + return errors.Wrap(err, "iterator failed to close during migration") } // Store the updated Schedules diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go index 75dd42e52..9757f508a 100644 --- a/x/cron/migrations/v2/store_test.go +++ b/x/cron/migrations/v2/store_test.go @@ -12,15 +12,15 @@ import ( v1types "github.com/neutron-org/neutron/v4/x/cron/types/v1" ) -type V4CronMigrationTestSuite struct { +type V2CronMigrationTestSuite struct { testutil.IBCConnectionTestSuite } func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(V4CronMigrationTestSuite)) + suite.Run(t, new(V2CronMigrationTestSuite)) } -func (suite *V4CronMigrationTestSuite) TestScheduleUpgrade() { +func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { var ( app = suite.GetNeutronZoneApp(suite.ChainA) storeKey = app.GetKey(types.StoreKey) @@ -47,7 +47,7 @@ func (suite *V4CronMigrationTestSuite) TestScheduleUpgrade() { // Run migration suite.NoError(v2.MigrateStore(ctx, cdc, storeKey)) - // Check Schedule has correct Blocker + // Check Schedule has correct ExecutionStage newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) - suite.Equal(newSchedule.Blocker, types.BlockerType_END) + suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_END_BLOCKER) } diff --git a/x/cron/module.go b/x/cron/module.go index df953c111..b865fa43a 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -156,11 +156,11 @@ func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block func (am AppModule) BeginBlock(ctx sdk.Context) { - am.keeper.ExecuteReadySchedules(ctx, true) + am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) } // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { - am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), false) + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_END_BLOCKER) return []abci.ValidatorUpdate{}, nil } diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index 3cd7cd104..d948efa4f 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -23,32 +23,32 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// BlockerType defines when messages will be executed in the block -type BlockerType int32 +// ExecutionStage defines when messages will be executed in the block +type ExecutionStage int32 const ( - BlockerType_BEGIN BlockerType = 0 - BlockerType_END BlockerType = 1 - BlockerType_BOTH BlockerType = 2 + ExecutionStage_BEGIN_BLOCKER ExecutionStage = 0 + ExecutionStage_END_BLOCKER ExecutionStage = 1 + ExecutionStage_BOTH_BLOCKERS ExecutionStage = 2 ) -var BlockerType_name = map[int32]string{ - 0: "BEGIN", - 1: "END", - 2: "BOTH", +var ExecutionStage_name = map[int32]string{ + 0: "BEGIN_BLOCKER", + 1: "END_BLOCKER", + 2: "BOTH_BLOCKERS", } -var BlockerType_value = map[string]int32{ - "BEGIN": 0, - "END": 1, - "BOTH": 2, +var ExecutionStage_value = map[string]int32{ + "BEGIN_BLOCKER": 0, + "END_BLOCKER": 1, + "BOTH_BLOCKERS": 2, } -func (x BlockerType) String() string { - return proto.EnumName(BlockerType_name, int32(x)) +func (x ExecutionStage) String() string { + return proto.EnumName(ExecutionStage_name, int32(x)) } -func (BlockerType) EnumDescriptor() ([]byte, []int) { +func (ExecutionStage) EnumDescriptor() ([]byte, []int) { return fileDescriptor_49ace1b59de613ef, []int{0} } @@ -61,8 +61,8 @@ type Schedule struct { Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` - // Blocker where the messages will be executed - Blocker BlockerType `protobuf:"varint,5,opt,name=blocker,proto3,enum=neutron.cron.BlockerType" json:"blocker,omitempty"` + // Execution stage when messages will be executed + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -126,11 +126,11 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } -func (m *Schedule) GetBlocker() BlockerType { +func (m *Schedule) GetExecutionStage() ExecutionStage { if m != nil { - return m.Blocker + return m.ExecutionStage } - return BlockerType_BEGIN + return ExecutionStage_BEGIN_BLOCKER } type MsgExecuteContract struct { @@ -233,7 +233,7 @@ func (m *ScheduleCount) GetCount() int32 { } func init() { - proto.RegisterEnum("neutron.cron.BlockerType", BlockerType_name, BlockerType_value) + proto.RegisterEnum("neutron.cron.ExecutionStage", ExecutionStage_name, ExecutionStage_value) proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") @@ -242,31 +242,31 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 371 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xcf, 0x6a, 0xdb, 0x40, - 0x10, 0xc6, 0xb5, 0x96, 0xe4, 0x3f, 0xe3, 0xb6, 0xa8, 0x5b, 0x53, 0x54, 0x17, 0x54, 0x61, 0x28, - 0x88, 0x96, 0x4a, 0x60, 0xf7, 0xd4, 0xa3, 0x5c, 0x53, 0xf7, 0x10, 0x07, 0x14, 0x9f, 0x72, 0x31, - 0xf6, 0x7a, 0x59, 0x99, 0x58, 0x5a, 0x21, 0xad, 0x82, 0xfd, 0x16, 0x79, 0x2c, 0x1f, 0x7d, 0x4b, - 0x4e, 0x21, 0xd8, 0x2f, 0x12, 0xb4, 0x92, 0x83, 0x43, 0x2e, 0xcb, 0x37, 0xfc, 0xe6, 0x63, 0xe6, - 0xdb, 0x81, 0xaf, 0x31, 0xcd, 0x45, 0xca, 0x63, 0x8f, 0x14, 0x4f, 0x46, 0x42, 0xba, 0xcc, 0xd7, - 0xd4, 0x4d, 0x52, 0x2e, 0x38, 0x7e, 0x57, 0x41, 0xb7, 0x80, 0xdd, 0x0e, 0xe3, 0x8c, 0x4b, 0xe0, - 0x15, 0xaa, 0xec, 0xe9, 0xdd, 0x23, 0x68, 0x5e, 0x55, 0x36, 0x8c, 0x41, 0x8b, 0xe7, 0x11, 0x35, - 0x91, 0x8d, 0x9c, 0x56, 0x20, 0x35, 0xfe, 0x0c, 0xf5, 0x84, 0xa6, 0x2b, 0xbe, 0x34, 0x6b, 0x36, - 0x72, 0xb4, 0xa0, 0xaa, 0xf0, 0x1f, 0xd0, 0xa2, 0x8c, 0x65, 0xa6, 0x6a, 0xab, 0x4e, 0xbb, 0x6f, - 0xbb, 0xe7, 0xb3, 0xdc, 0x8b, 0x8c, 0x8d, 0x36, 0x94, 0xe4, 0x82, 0x0e, 0x79, 0x2c, 0xd2, 0x39, - 0x11, 0xbe, 0xb6, 0x7b, 0xfc, 0xa6, 0x04, 0xd2, 0x83, 0x5d, 0xf8, 0xb4, 0x9e, 0x67, 0x62, 0x46, - 0xcb, 0x9e, 0x59, 0x48, 0x57, 0x2c, 0x14, 0xa6, 0x26, 0x07, 0x7c, 0x2c, 0x50, 0xe5, 0x1e, 0x4b, - 0x80, 0x07, 0xd0, 0x58, 0xac, 0x39, 0xb9, 0xa1, 0xa9, 0xa9, 0xdb, 0xc8, 0xf9, 0xd0, 0xff, 0xf2, - 0x7a, 0x9c, 0x5f, 0xc2, 0xe9, 0x36, 0xa1, 0xc1, 0xa9, 0xb3, 0xe7, 0x03, 0x7e, 0xbb, 0x06, 0xee, - 0x42, 0x93, 0x54, 0xba, 0x8a, 0xf9, 0x52, 0x63, 0x03, 0xd4, 0x28, 0x63, 0x32, 0x67, 0x2b, 0x28, - 0x64, 0xef, 0x3b, 0xbc, 0x3f, 0x7d, 0xce, 0x90, 0xe7, 0xb1, 0xc0, 0x1d, 0xd0, 0x49, 0x21, 0xa4, - 0x57, 0x0f, 0xca, 0xe2, 0xc7, 0x4f, 0x68, 0x9f, 0xad, 0x80, 0x5b, 0xa0, 0xfb, 0xa3, 0x7f, 0xff, - 0x27, 0x86, 0x82, 0x1b, 0xa0, 0x8e, 0x26, 0x7f, 0x0d, 0x84, 0x9b, 0xa0, 0xf9, 0x97, 0xd3, 0xb1, - 0x51, 0xf3, 0xc7, 0xbb, 0x83, 0x85, 0xf6, 0x07, 0x0b, 0x3d, 0x1d, 0x2c, 0x74, 0x77, 0xb4, 0x94, - 0xfd, 0xd1, 0x52, 0x1e, 0x8e, 0x96, 0x72, 0xed, 0xb2, 0x95, 0x08, 0xf3, 0x85, 0x4b, 0x78, 0xe4, - 0x55, 0xf9, 0x7e, 0xf1, 0x94, 0x9d, 0xb4, 0x77, 0xfb, 0xdb, 0xdb, 0x94, 0x87, 0x16, 0xdb, 0x84, - 0x66, 0x8b, 0xba, 0x3c, 0xe1, 0xe0, 0x39, 0x00, 0x00, 0xff, 0xff, 0x52, 0x99, 0x7d, 0xa1, 0x05, - 0x02, 0x00, 0x00, + // 383 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x4f, 0x6b, 0xe2, 0x40, + 0x1c, 0xcd, 0x68, 0x14, 0x1d, 0xd7, 0x7f, 0xb3, 0xb2, 0x04, 0x77, 0xc9, 0x06, 0x61, 0x21, 0x2c, + 0x6c, 0x02, 0xee, 0x9e, 0xf6, 0x18, 0x37, 0xe8, 0xd2, 0x56, 0x21, 0xf6, 0xd4, 0x4b, 0x88, 0x71, + 0x98, 0x04, 0x4c, 0x46, 0x32, 0x93, 0x62, 0xbf, 0x45, 0x3f, 0x96, 0x47, 0x8f, 0x3d, 0x95, 0xa2, + 0xa7, 0x7e, 0x8b, 0x92, 0x49, 0x22, 0x95, 0x5e, 0xc2, 0x7b, 0xbf, 0xf7, 0x1e, 0xbf, 0x3f, 0x19, + 0xf8, 0x35, 0xc6, 0x29, 0x4f, 0x68, 0x6c, 0xfa, 0xd9, 0x87, 0xf9, 0x01, 0x5e, 0xa7, 0x1b, 0x6c, + 0x6c, 0x13, 0xca, 0x29, 0xfa, 0x54, 0x88, 0x46, 0x26, 0x0e, 0x07, 0x84, 0x12, 0x2a, 0x04, 0x33, + 0x43, 0xb9, 0x67, 0xf4, 0x0a, 0x60, 0x63, 0x59, 0xc4, 0x10, 0x82, 0x72, 0xec, 0x45, 0x58, 0x01, + 0x1a, 0xd0, 0x9b, 0x8e, 0xc0, 0xe8, 0x0b, 0xac, 0x6f, 0x71, 0x12, 0xd2, 0xb5, 0x52, 0xd1, 0x80, + 0x2e, 0x3b, 0x05, 0x43, 0x7f, 0xa1, 0x1c, 0x31, 0xc2, 0x94, 0xaa, 0x56, 0xd5, 0x5b, 0x63, 0xcd, + 0x78, 0xdf, 0xcb, 0xb8, 0x61, 0xc4, 0xde, 0x61, 0x3f, 0xe5, 0x78, 0x42, 0x63, 0x9e, 0x78, 0x3e, + 0xb7, 0xe4, 0xfd, 0xf3, 0x77, 0xc9, 0x11, 0x19, 0x64, 0xc0, 0xcf, 0x1b, 0x8f, 0x71, 0x17, 0xe7, + 0x1e, 0x37, 0xc0, 0x21, 0x09, 0xb8, 0x22, 0x8b, 0x06, 0xfd, 0x4c, 0x2a, 0xd2, 0x33, 0x21, 0x20, + 0x1b, 0x76, 0x73, 0x6b, 0x48, 0x63, 0x97, 0x71, 0x8f, 0x60, 0xa5, 0xa6, 0x01, 0xbd, 0x33, 0xfe, + 0x76, 0xd9, 0xd6, 0x2e, 0x4d, 0xcb, 0xcc, 0xe3, 0x74, 0xf0, 0x05, 0x1f, 0x59, 0x10, 0x7d, 0x1c, + 0x0c, 0x0d, 0x61, 0xc3, 0x2f, 0x70, 0xb1, 0xf8, 0x99, 0xa3, 0x1e, 0xac, 0x46, 0x8c, 0x88, 0xcd, + 0x9b, 0x4e, 0x06, 0x47, 0x3f, 0x60, 0xbb, 0x3c, 0xd7, 0x84, 0xa6, 0x31, 0x47, 0x03, 0x58, 0xf3, + 0x33, 0x20, 0xb2, 0x35, 0x27, 0x27, 0x3f, 0xa7, 0xb0, 0x73, 0x39, 0x0c, 0xea, 0xc3, 0xb6, 0x65, + 0x4f, 0xff, 0xcf, 0x5d, 0xeb, 0x7a, 0x31, 0xb9, 0xb2, 0x9d, 0x9e, 0x84, 0xba, 0xb0, 0x65, 0xcf, + 0xff, 0x9d, 0x0b, 0x40, 0x78, 0x16, 0xb7, 0xb3, 0xb2, 0xb2, 0xec, 0x55, 0xac, 0xd9, 0xfe, 0xa8, + 0x82, 0xc3, 0x51, 0x05, 0x2f, 0x47, 0x15, 0x3c, 0x9e, 0x54, 0xe9, 0x70, 0x52, 0xa5, 0xa7, 0x93, + 0x2a, 0xdd, 0x19, 0x24, 0xe4, 0x41, 0xba, 0x32, 0x7c, 0x1a, 0x99, 0xc5, 0x15, 0x7e, 0xd1, 0x84, + 0x94, 0xd8, 0xbc, 0xff, 0x63, 0xee, 0xf2, 0x67, 0xc1, 0x1f, 0xb6, 0x98, 0xad, 0xea, 0xe2, 0x87, + 0xff, 0x7e, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xed, 0x05, 0x84, 0xca, 0x33, 0x02, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -289,8 +289,8 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Blocker != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.Blocker)) + if m.ExecutionStage != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.ExecutionStage)) i-- dAtA[i] = 0x28 } @@ -426,8 +426,8 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } - if m.Blocker != 0 { - n += 1 + sovSchedule(uint64(m.Blocker)) + if m.ExecutionStage != 0 { + n += 1 + sovSchedule(uint64(m.ExecutionStage)) } return n } @@ -602,9 +602,9 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { } case 5: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Blocker", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) } - m.Blocker = 0 + m.ExecutionStage = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSchedule @@ -614,7 +614,7 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Blocker |= BlockerType(b&0x7F) << shift + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index c37a063ef..16905d24b 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -34,11 +34,11 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // MsgAddSchedule is the MsgAddSchedule request type. type MsgAddSchedule struct { // Authority is the address of the governance account. - Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` - Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` - Blocker BlockerType `protobuf:"varint,5,opt,name=blocker,proto3,enum=neutron.cron.BlockerType" json:"blocker,omitempty"` + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` + Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } @@ -102,11 +102,11 @@ func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { return nil } -func (m *MsgAddSchedule) GetBlocker() BlockerType { +func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { if m != nil { - return m.Blocker + return m.ExecutionStage } - return BlockerType_BEGIN + return ExecutionStage_BEGIN_BLOCKER } // MsgAddScheduleResponse defines the response structure for executing a @@ -350,42 +350,42 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 550 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xcf, 0x8b, 0xd3, 0x40, - 0x14, 0xee, 0xb4, 0xdd, 0x4a, 0xa7, 0x4b, 0x65, 0x63, 0xed, 0xa6, 0x59, 0xcd, 0x96, 0xa2, 0x6e, - 0x2d, 0x6c, 0x82, 0x5d, 0x51, 0xe8, 0x6d, 0x23, 0x82, 0x97, 0x80, 0x66, 0xd7, 0xcb, 0x5e, 0x24, - 0x4d, 0x86, 0x69, 0x70, 0x93, 0x09, 0x33, 0x93, 0xd2, 0xde, 0xc4, 0xe3, 0x82, 0xa0, 0xff, 0x85, - 0xe0, 0xa5, 0x07, 0xff, 0x88, 0x3d, 0x2e, 0x9e, 0x3c, 0x89, 0xb4, 0x87, 0xfe, 0x1b, 0x92, 0x5f, - 0xbb, 0xc9, 0x06, 0x56, 0x10, 0xbc, 0x4c, 0x66, 0xde, 0xf7, 0xbe, 0x97, 0xef, 0x7d, 0xf3, 0x18, - 0x78, 0xd7, 0x43, 0x01, 0xa7, 0xc4, 0x53, 0xad, 0x70, 0xe1, 0x33, 0xc5, 0xa7, 0x84, 0x13, 0x61, - 0x33, 0x09, 0x2b, 0x61, 0x58, 0xda, 0x32, 0x5d, 0xc7, 0x23, 0x6a, 0xb4, 0xc6, 0x09, 0xd2, 0xb6, - 0x45, 0x98, 0x4b, 0x98, 0xea, 0x32, 0xac, 0x4e, 0x9f, 0x84, 0x9f, 0x04, 0xe8, 0xc4, 0xc0, 0xbb, - 0xe8, 0xa4, 0xc6, 0x87, 0x04, 0x6a, 0x61, 0x82, 0x49, 0x1c, 0x0f, 0x77, 0x29, 0x21, 0xa7, 0xc0, - 0x37, 0xa9, 0xe9, 0xa6, 0x84, 0x9d, 0x1c, 0xc4, 0xac, 0x09, 0xb2, 0x83, 0x53, 0x14, 0x83, 0xbd, - 0x4f, 0x65, 0xd8, 0xd4, 0x19, 0x3e, 0xb4, 0xed, 0xa3, 0x04, 0x10, 0x9e, 0xc1, 0xba, 0x19, 0xf0, - 0x09, 0xa1, 0x0e, 0x9f, 0x8b, 0xa0, 0x0b, 0xfa, 0x75, 0x4d, 0xfc, 0xf1, 0x7d, 0xbf, 0x95, 0xa8, - 0x38, 0xb4, 0x6d, 0x8a, 0x18, 0x3b, 0xe2, 0xd4, 0xf1, 0xb0, 0x71, 0x95, 0x2a, 0x08, 0xb0, 0xea, - 0x99, 0x2e, 0x12, 0xcb, 0x21, 0xc5, 0x88, 0xf6, 0x42, 0x1b, 0xd6, 0x7c, 0x44, 0x1d, 0x62, 0x8b, - 0x95, 0x2e, 0xe8, 0x57, 0x8d, 0xe4, 0x24, 0x8c, 0x60, 0xd5, 0x65, 0x98, 0x89, 0xd5, 0x6e, 0xa5, - 0xdf, 0x18, 0x76, 0x95, 0xac, 0x51, 0x8a, 0xce, 0xf0, 0xcb, 0x19, 0xb2, 0x02, 0x8e, 0x5e, 0x10, - 0x8f, 0x53, 0xd3, 0xe2, 0x5a, 0xf5, 0xfc, 0xd7, 0x6e, 0xc9, 0x88, 0x38, 0xc2, 0x01, 0xbc, 0x35, - 0x3e, 0x25, 0xd6, 0x7b, 0x44, 0xc5, 0x8d, 0x2e, 0xe8, 0x37, 0x87, 0x9d, 0x3c, 0x5d, 0x8b, 0xc1, - 0xe3, 0xb9, 0x8f, 0x8c, 0x34, 0x73, 0xf4, 0xe8, 0xe3, 0x7a, 0x31, 0xb8, 0x12, 0x7b, 0xb6, 0x5e, - 0x0c, 0xee, 0x44, 0x7e, 0xe4, 0x9b, 0xef, 0x89, 0xb0, 0x9d, 0x8f, 0x18, 0x88, 0xf9, 0xc4, 0x63, - 0xa8, 0x77, 0x06, 0xe0, 0x96, 0xce, 0xb0, 0x81, 0x5c, 0x32, 0x45, 0xff, 0xc3, 0xac, 0xd1, 0xe3, - 0xa2, 0xc6, 0x76, 0xaa, 0x31, 0xff, 0xdb, 0xde, 0x0e, 0xec, 0x14, 0x82, 0x97, 0x4a, 0xbf, 0x01, - 0x78, 0x5b, 0x67, 0xf8, 0xad, 0x6f, 0x9b, 0x1c, 0xbd, 0x8e, 0x46, 0xe1, 0x9f, 0x75, 0x3e, 0x87, - 0xb5, 0x78, 0x98, 0x22, 0xa5, 0x8d, 0x61, 0x2b, 0xef, 0x75, 0x5c, 0x5d, 0xab, 0x87, 0xd7, 0xf3, - 0x75, 0xbd, 0x18, 0x00, 0x23, 0x49, 0x1f, 0xed, 0x15, 0x9b, 0x69, 0xa5, 0xcd, 0x64, 0x95, 0xf5, - 0x3a, 0x70, 0xfb, 0x5a, 0x28, 0x6d, 0x64, 0xf8, 0xa5, 0x0c, 0x2b, 0x3a, 0xc3, 0xc2, 0x1b, 0xd8, - 0xc8, 0x0e, 0xe8, 0xbd, 0xc2, 0xb8, 0x64, 0x50, 0xe9, 0xc1, 0x4d, 0x68, 0x5a, 0x5a, 0x38, 0x81, - 0xcd, 0x6b, 0x37, 0xb9, 0x5b, 0xe0, 0xe5, 0x13, 0xa4, 0xbd, 0xbf, 0x24, 0x5c, 0xd6, 0x3e, 0x86, - 0x9b, 0x39, 0xef, 0xef, 0x17, 0x88, 0x59, 0x58, 0x7a, 0x78, 0x23, 0x9c, 0x56, 0x95, 0x36, 0x3e, - 0x84, 0xfe, 0x6a, 0xaf, 0xce, 0x97, 0x32, 0xb8, 0x58, 0xca, 0xe0, 0xf7, 0x52, 0x06, 0x9f, 0x57, - 0x72, 0xe9, 0x62, 0x25, 0x97, 0x7e, 0xae, 0xe4, 0xd2, 0x89, 0x82, 0x1d, 0x3e, 0x09, 0xc6, 0x8a, - 0x45, 0x5c, 0x35, 0xa9, 0xb8, 0x4f, 0x28, 0x4e, 0xf7, 0xea, 0xf4, 0xa9, 0x3a, 0x4b, 0x1e, 0xa8, - 0xb9, 0x8f, 0xd8, 0xb8, 0x16, 0xbd, 0x00, 0x07, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x0f, - 0x7b, 0xac, 0xbd, 0x04, 0x00, 0x00, + // 554 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x6b, 0xdb, 0x40, + 0x14, 0xf6, 0xd9, 0x8e, 0xc1, 0xe7, 0xe0, 0x10, 0xd5, 0x75, 0x64, 0x25, 0x55, 0x8c, 0x68, 0x1b, + 0xd7, 0x10, 0x89, 0xba, 0xa5, 0x05, 0x6f, 0x71, 0x31, 0x74, 0x11, 0xb4, 0x72, 0xbb, 0x64, 0x09, + 0x8a, 0x74, 0x9c, 0x05, 0x95, 0x4e, 0xe8, 0x4e, 0xc6, 0xd9, 0x4a, 0xc7, 0x4c, 0xed, 0x5f, 0xd0, + 0xb5, 0xd0, 0xc5, 0x43, 0xff, 0x88, 0x8c, 0xa1, 0x53, 0xa7, 0x52, 0xec, 0xc1, 0xff, 0x46, 0xd1, + 0xaf, 0x44, 0x17, 0x41, 0x0a, 0x85, 0x2c, 0xa7, 0x7b, 0xef, 0xfb, 0xde, 0xd3, 0x77, 0xdf, 0x3d, + 0x0e, 0xde, 0xf7, 0x50, 0xc8, 0x02, 0xe2, 0x69, 0x56, 0xb4, 0xb0, 0xb9, 0xea, 0x07, 0x84, 0x11, + 0x61, 0x33, 0x4d, 0xab, 0x51, 0x5a, 0xda, 0x36, 0x5d, 0xc7, 0x23, 0x5a, 0xbc, 0x26, 0x04, 0x69, + 0xc7, 0x22, 0xd4, 0x25, 0x54, 0x73, 0x29, 0xd6, 0x66, 0x4f, 0xa3, 0x4f, 0x0a, 0x74, 0x12, 0xe0, + 0x24, 0x8e, 0xb4, 0x24, 0x48, 0xa1, 0x16, 0x26, 0x98, 0x24, 0xf9, 0x68, 0x97, 0x15, 0x70, 0x0a, + 0x7c, 0x33, 0x30, 0xdd, 0xac, 0x60, 0x97, 0x83, 0xa8, 0x35, 0x45, 0x76, 0xf8, 0x01, 0x25, 0xa0, + 0xf2, 0xb5, 0x0c, 0x9b, 0x3a, 0xc5, 0x47, 0xb6, 0x3d, 0x49, 0x01, 0xe1, 0x05, 0xac, 0x9b, 0x21, + 0x9b, 0x92, 0xc0, 0x61, 0x67, 0x22, 0xe8, 0x82, 0x5e, 0x7d, 0x24, 0xfe, 0xfc, 0x71, 0xd8, 0x4a, + 0x55, 0x1c, 0xd9, 0x76, 0x80, 0x28, 0x9d, 0xb0, 0xc0, 0xf1, 0xb0, 0x71, 0x4d, 0x15, 0x04, 0x58, + 0xf5, 0x4c, 0x17, 0x89, 0xe5, 0xa8, 0xc4, 0x88, 0xf7, 0x42, 0x1b, 0xd6, 0x7c, 0x14, 0x38, 0xc4, + 0x16, 0x2b, 0x5d, 0xd0, 0xab, 0x1a, 0x69, 0x24, 0x0c, 0x61, 0xd5, 0xa5, 0x98, 0x8a, 0xd5, 0x6e, + 0xa5, 0xd7, 0x18, 0x74, 0xd5, 0xbc, 0x51, 0xaa, 0x4e, 0xf1, 0x78, 0x8e, 0xac, 0x90, 0xa1, 0x57, + 0xc4, 0x63, 0x81, 0x69, 0xb1, 0x51, 0xf5, 0xe2, 0xf7, 0x7e, 0xc9, 0x88, 0x6b, 0x84, 0x31, 0xdc, + 0x42, 0x31, 0xec, 0x10, 0xef, 0x84, 0x32, 0x13, 0x23, 0x71, 0xa3, 0x0b, 0x7a, 0xcd, 0xc1, 0x1e, + 0xdf, 0x66, 0x9c, 0x91, 0x26, 0x11, 0xc7, 0x68, 0x22, 0x2e, 0x1e, 0x3e, 0xfe, 0xb4, 0x5e, 0xf4, + 0xaf, 0xe5, 0x9f, 0xaf, 0x17, 0xfd, 0x7b, 0xb1, 0x43, 0xbc, 0x1d, 0x8a, 0x08, 0xdb, 0x7c, 0xc6, + 0x40, 0xd4, 0x27, 0x1e, 0x45, 0xca, 0x39, 0x80, 0xdb, 0x3a, 0xc5, 0x06, 0x72, 0xc9, 0x0c, 0xdd, + 0x85, 0x7d, 0xc3, 0x27, 0x45, 0x8d, 0xed, 0x4c, 0x23, 0xff, 0x5b, 0x65, 0x17, 0x76, 0x0a, 0xc9, + 0x2b, 0xa5, 0xdf, 0x01, 0xdc, 0xd2, 0x29, 0x7e, 0xef, 0xdb, 0x26, 0x43, 0x6f, 0xe2, 0xe1, 0xf8, + 0x6f, 0x9d, 0x2f, 0x61, 0x2d, 0x19, 0xaf, 0x58, 0x69, 0x63, 0xd0, 0xe2, 0x5d, 0x4f, 0xba, 0x8f, + 0xea, 0xd1, 0x85, 0x7d, 0x5b, 0x2f, 0xfa, 0xc0, 0x48, 0xe9, 0xc3, 0x83, 0xe2, 0x61, 0x5a, 0xd9, + 0x61, 0xf2, 0xca, 0x94, 0x0e, 0xdc, 0xb9, 0x91, 0xca, 0x0e, 0x32, 0xf8, 0x52, 0x86, 0x15, 0x9d, + 0x62, 0xe1, 0x2d, 0x6c, 0xe4, 0x47, 0x76, 0xaf, 0x30, 0x40, 0x39, 0x54, 0x7a, 0x78, 0x1b, 0x9a, + 0xb5, 0x16, 0x8e, 0x61, 0xf3, 0xc6, 0x4d, 0xee, 0x17, 0xea, 0x78, 0x82, 0x74, 0xf0, 0x0f, 0xc2, + 0x55, 0xef, 0x77, 0x70, 0x93, 0xf3, 0xfe, 0x41, 0xa1, 0x30, 0x0f, 0x4b, 0x8f, 0x6e, 0x85, 0xb3, + 0xae, 0xd2, 0xc6, 0xc7, 0xc8, 0xdf, 0xd1, 0xeb, 0x8b, 0xa5, 0x0c, 0x2e, 0x97, 0x32, 0xf8, 0xb3, + 0x94, 0xc1, 0xe7, 0x95, 0x5c, 0xba, 0x5c, 0xc9, 0xa5, 0x5f, 0x2b, 0xb9, 0x74, 0xac, 0x62, 0x87, + 0x4d, 0xc3, 0x53, 0xd5, 0x22, 0xae, 0x96, 0x76, 0x3c, 0x24, 0x01, 0xce, 0xf6, 0xda, 0xec, 0xb9, + 0x36, 0x4f, 0x9f, 0xac, 0x33, 0x1f, 0xd1, 0xd3, 0x5a, 0xfc, 0x26, 0x3c, 0xfb, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0xf7, 0xca, 0x79, 0x29, 0xcf, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -566,8 +566,8 @@ func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Blocker != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Blocker)) + if m.ExecutionStage != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ExecutionStage)) i-- dAtA[i] = 0x28 } @@ -787,8 +787,8 @@ func (m *MsgAddSchedule) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if m.Blocker != 0 { - n += 1 + sovTx(uint64(m.Blocker)) + if m.ExecutionStage != 0 { + n += 1 + sovTx(uint64(m.ExecutionStage)) } return n } @@ -1006,9 +1006,9 @@ func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 5: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Blocker", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) } - m.Blocker = 0 + m.ExecutionStage = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -1018,7 +1018,7 @@ func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.Blocker |= BlockerType(b&0x7F) << shift + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go index cda29cf72..b2fe7d90c 100644 --- a/x/cron/types/v1/schedule.pb.go +++ b/x/cron/types/v1/schedule.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: neutron/cron/schedule.proto +// source: neutron/cron/v1/schedule.proto -package types +package v1 import ( fmt "fmt" @@ -38,7 +38,7 @@ func (m *Schedule) Reset() { *m = Schedule{} } func (m *Schedule) String() string { return proto.CompactTextString(m) } func (*Schedule) ProtoMessage() {} func (*Schedule) Descriptor() ([]byte, []int) { - return fileDescriptor_49ace1b59de613ef, []int{0} + return fileDescriptor_cd4938034d592826, []int{0} } func (m *Schedule) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -106,7 +106,7 @@ func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } func (*MsgExecuteContract) ProtoMessage() {} func (*MsgExecuteContract) Descriptor() ([]byte, []int) { - return fileDescriptor_49ace1b59de613ef, []int{1} + return fileDescriptor_cd4938034d592826, []int{1} } func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -158,7 +158,7 @@ func (m *ScheduleCount) Reset() { *m = ScheduleCount{} } func (m *ScheduleCount) String() string { return proto.CompactTextString(m) } func (*ScheduleCount) ProtoMessage() {} func (*ScheduleCount) Descriptor() ([]byte, []int) { - return fileDescriptor_49ace1b59de613ef, []int{2} + return fileDescriptor_cd4938034d592826, []int{2} } func (m *ScheduleCount) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -195,35 +195,35 @@ func (m *ScheduleCount) GetCount() int32 { } func init() { - proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") - proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") - proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") -} - -func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } - -var fileDescriptor_49ace1b59de613ef = []byte{ - // 309 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xfb, 0x30, - 0x18, 0xc6, 0x9b, 0xff, 0xba, 0xb1, 0xe5, 0xaf, 0xa0, 0x71, 0x48, 0x99, 0x10, 0x4b, 0x41, 0xe8, - 0xc5, 0x14, 0xd4, 0x93, 0xc7, 0x0e, 0x61, 0x17, 0x2f, 0xf5, 0xe6, 0x65, 0x74, 0x59, 0x48, 0x0b, - 0x6b, 0x53, 0x9a, 0x54, 0xe6, 0xb7, 0xf0, 0x33, 0xf8, 0x69, 0x76, 0xdc, 0xd1, 0x93, 0x48, 0xfb, - 0x45, 0x24, 0x69, 0x26, 0x82, 0x97, 0xf0, 0x7b, 0x78, 0xde, 0x27, 0xef, 0xfb, 0x26, 0xf0, 0xa2, - 0x64, 0x8d, 0xaa, 0x45, 0x19, 0x51, 0x7d, 0x48, 0x9a, 0xb1, 0x75, 0xb3, 0x61, 0xa4, 0xaa, 0x85, - 0x12, 0xe8, 0xc8, 0x9a, 0x44, 0x9b, 0xb3, 0x29, 0x17, 0x5c, 0x18, 0x23, 0xd2, 0xd4, 0xd7, 0x04, - 0xef, 0x00, 0x8e, 0x9f, 0x6c, 0x0c, 0x21, 0xe8, 0x96, 0x69, 0xc1, 0x3c, 0xe0, 0x83, 0x70, 0x92, - 0x18, 0x46, 0xe7, 0x70, 0x54, 0xb1, 0x3a, 0x17, 0x6b, 0xef, 0x9f, 0x0f, 0x42, 0x37, 0xb1, 0x0a, - 0xdd, 0x43, 0xb7, 0x90, 0x5c, 0x7a, 0x03, 0x7f, 0x10, 0xfe, 0xbf, 0xf1, 0xc9, 0xef, 0x5e, 0xe4, - 0x51, 0xf2, 0x87, 0x2d, 0xa3, 0x8d, 0x62, 0x73, 0x51, 0xaa, 0x3a, 0xa5, 0x2a, 0x76, 0x77, 0x9f, - 0x97, 0x4e, 0x62, 0x32, 0x88, 0xc0, 0xb3, 0x4d, 0x2a, 0xd5, 0x92, 0xf5, 0x35, 0xcb, 0x8c, 0xe5, - 0x3c, 0x53, 0x9e, 0x6b, 0x1a, 0x9c, 0x6a, 0xcb, 0xa6, 0x17, 0xc6, 0x08, 0x62, 0x88, 0xfe, 0xde, - 0x88, 0x66, 0x70, 0x4c, 0x2d, 0xdb, 0x89, 0x7f, 0x34, 0x3a, 0x81, 0x83, 0x42, 0x72, 0x33, 0xf2, - 0x24, 0xd1, 0x18, 0x5c, 0xc1, 0xe3, 0xc3, 0x9e, 0x73, 0xd1, 0x94, 0x0a, 0x4d, 0xe1, 0x90, 0x6a, - 0x30, 0xd9, 0x61, 0xd2, 0x8b, 0x78, 0xb1, 0x6b, 0x31, 0xd8, 0xb7, 0x18, 0x7c, 0xb5, 0x18, 0xbc, - 0x75, 0xd8, 0xd9, 0x77, 0xd8, 0xf9, 0xe8, 0xb0, 0xf3, 0x4c, 0x78, 0xae, 0xb2, 0x66, 0x45, 0xa8, - 0x28, 0x22, 0xbb, 0xec, 0xb5, 0xa8, 0xf9, 0x81, 0xa3, 0x97, 0xbb, 0x68, 0xdb, 0x7f, 0x83, 0x7a, - 0xad, 0x98, 0x5c, 0x8d, 0xcc, 0x03, 0xdf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x19, 0x38, - 0x8d, 0xa3, 0x01, 0x00, 0x00, + proto.RegisterType((*Schedule)(nil), "neutron.cron.v1.Schedule") + proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.v1.MsgExecuteContract") + proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.v1.ScheduleCount") +} + +func init() { proto.RegisterFile("neutron/cron/v1/schedule.proto", fileDescriptor_cd4938034d592826) } + +var fileDescriptor_cd4938034d592826 = []byte{ + // 316 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xc1, 0x4a, 0xc3, 0x30, + 0x18, 0xc7, 0x1b, 0xd7, 0x8d, 0x2d, 0x22, 0x6a, 0x1c, 0x52, 0x76, 0x88, 0x63, 0x22, 0xec, 0x62, + 0x42, 0xd5, 0xab, 0x97, 0x0d, 0x41, 0x10, 0x2f, 0xf5, 0xe6, 0x65, 0x6c, 0x59, 0x48, 0x07, 0x6b, + 0x53, 0x9a, 0xb4, 0xcc, 0xb7, 0xf0, 0x25, 0x7c, 0x97, 0x1d, 0x77, 0xf4, 0x24, 0xd2, 0xbe, 0x88, + 0x24, 0xcd, 0x3c, 0xe8, 0x25, 0xfc, 0xfe, 0xfc, 0xbf, 0x7f, 0xbe, 0xef, 0x4b, 0x20, 0x4e, 0x79, + 0xa1, 0x73, 0x99, 0x52, 0x66, 0x8e, 0x32, 0xa4, 0x8a, 0xc5, 0x7c, 0x59, 0xac, 0x39, 0xc9, 0x72, + 0xa9, 0x25, 0x3a, 0x76, 0x3e, 0x31, 0x3e, 0x29, 0xc3, 0x41, 0x5f, 0x48, 0x21, 0xad, 0x47, 0x0d, + 0x35, 0x65, 0xa3, 0x0f, 0x00, 0xbb, 0x2f, 0x2e, 0x89, 0x10, 0xf4, 0xd3, 0x79, 0xc2, 0x03, 0x30, + 0x04, 0xe3, 0x5e, 0x64, 0x19, 0x9d, 0xc3, 0x4e, 0xc6, 0xf3, 0x95, 0x5c, 0x06, 0x07, 0x43, 0x30, + 0xf6, 0x23, 0xa7, 0xd0, 0x3d, 0xf4, 0x13, 0x25, 0x54, 0xd0, 0x1a, 0xb6, 0xc6, 0x87, 0x37, 0x97, + 0xe4, 0x4f, 0x3b, 0xf2, 0xac, 0xc4, 0xc3, 0x86, 0xb3, 0x42, 0xf3, 0xa9, 0x4c, 0x75, 0x3e, 0x67, + 0x7a, 0xe2, 0x6f, 0xbf, 0x2e, 0xbc, 0xc8, 0xc6, 0x10, 0x81, 0x67, 0xeb, 0xb9, 0xd2, 0x33, 0xde, + 0xd4, 0xcc, 0x62, 0xbe, 0x12, 0xb1, 0x0e, 0x7c, 0xdb, 0xe3, 0xd4, 0x58, 0x2e, 0xfd, 0x68, 0x8d, + 0xd1, 0x04, 0xa2, 0xff, 0x37, 0xa2, 0x01, 0xec, 0x32, 0xc7, 0x6e, 0xe8, 0x5f, 0x8d, 0x4e, 0x60, + 0x2b, 0x51, 0xc2, 0x4e, 0xdd, 0x8b, 0x0c, 0x8e, 0xae, 0xe0, 0xd1, 0x7e, 0xd5, 0xa9, 0x2c, 0x52, + 0x8d, 0xfa, 0xb0, 0xcd, 0x0c, 0xd8, 0x6c, 0x3b, 0x6a, 0xc4, 0xe4, 0x69, 0x5b, 0x61, 0xb0, 0xab, + 0x30, 0xf8, 0xae, 0x30, 0x78, 0xaf, 0xb1, 0xb7, 0xab, 0xb1, 0xf7, 0x59, 0x63, 0xef, 0x35, 0x14, + 0x2b, 0x1d, 0x17, 0x0b, 0xc2, 0x64, 0x42, 0xdd, 0xbe, 0xd7, 0x32, 0x17, 0x7b, 0xa6, 0xe5, 0x1d, + 0xdd, 0x34, 0xff, 0xa1, 0xdf, 0x32, 0xae, 0x68, 0x19, 0x2e, 0x3a, 0xf6, 0x99, 0x6f, 0x7f, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x4d, 0x2d, 0x47, 0x23, 0xaf, 0x01, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { From b25dfebc41122d2b849827d1bef4a476f83e9d5e Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 22 Aug 2024 14:43:06 +0400 Subject: [PATCH 17/60] unordered test --- wasmbinding/message_plugin.go | 11 +++--- wasmbinding/test/custom_message_test.go | 49 +++++++++++++++++++++++- wasmbinding/testdata/reflect.wasm | Bin 422710 -> 579620 bytes 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 81e05eed0..89307562a 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -7,7 +7,7 @@ import ( "strings" "time" - types1 "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" "github.com/cosmos/gogoproto/proto" @@ -868,15 +868,16 @@ func (m *CustomMessenger) registerInterchainAccount(ctx sdk.Context, contractAdd func (m *CustomMessenger) performRegisterInterchainAccount(ctx sdk.Context, contractAddr sdk.AccAddress, reg *bindings.RegisterInterchainAccount) (*ictxtypes.MsgRegisterInterchainAccountResponse, error) { // parse incoming ordering. If nothing passed, use ORDERED by default - var orderValue types1.Order + var orderValue channeltypes.Order if reg.Ordering == "" { - orderValue = types1.ORDERED + orderValue = channeltypes.ORDERED } else { - orderValueInt, ok := types1.Order_value[reg.Ordering] + orderValueInt, ok := channeltypes.Order_value[reg.Ordering] + if !ok { return nil, fmt.Errorf("failed to register interchain account: incorrect order value passed: %s", reg.Ordering) } - orderValue = types1.Order(orderValueInt) + orderValue = channeltypes.Order(orderValueInt) } msg := ictxtypes.MsgRegisterInterchainAccount{ diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 760417c16..e6726d219 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -102,13 +102,23 @@ func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccount() { } bankKeeper := suite.neutron.BankKeeper + channelKeeper := suite.neutron.IBCKeeper.ChannelKeeper senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() err = bankKeeper.SendCoins(suite.ctx, senderAddress, suite.contractAddress, sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(1_000_000)))) suite.NoError(err) // Dispatch RegisterInterchainAccount message - _, err = suite.executeNeutronMsg(suite.contractAddress, msg) + data, err := suite.executeNeutronMsg(suite.contractAddress, msg) + suite.NoError(err) + suite.NotEmpty(data) + + // default method should be ordered + var response ictxtypes.MsgRegisterInterchainAccountResponse + err = response.Unmarshal(data) suite.NoError(err) + channel, found := channelKeeper.GetChannel(suite.ctx, response.PortId, response.ChannelId) + suite.True(found) + suite.Equal(channel.Ordering, ibcchanneltypes.ORDERED) } func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccountLongID() { @@ -130,6 +140,43 @@ func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccountLongID() { suite.ErrorIs(err, ictxtypes.ErrLongInterchainAccountID) } +func (suite *CustomMessengerTestSuite) TestRegisterInterchainAccountUnordered() { + err := suite.neutron.FeeBurnerKeeper.SetParams(suite.ctx, feeburnertypes.Params{ + NeutronDenom: "untrn", + TreasuryAddress: "neutron13jrwrtsyjjuynlug65r76r2zvfw5xjcq6532h2", + }) + suite.Require().NoError(err) + + // Craft RegisterInterchainAccount message + msg := bindings.NeutronMsg{ + RegisterInterchainAccount: &bindings.RegisterInterchainAccount{ + ConnectionId: suite.Path.EndpointA.ConnectionID, + InterchainAccountId: testutil.TestInterchainID, + RegisterFee: sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(1_000_000))), + Ordering: ibcchanneltypes.Order_name[int32(ibcchanneltypes.UNORDERED)], + }, + } + + bankKeeper := suite.neutron.BankKeeper + channelKeeper := suite.neutron.IBCKeeper.ChannelKeeper + senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() + err = bankKeeper.SendCoins(suite.ctx, senderAddress, suite.contractAddress, sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(1_000_000)))) + suite.NoError(err) + + // Dispatch RegisterInterchainAccount message + data, err := suite.executeNeutronMsg(suite.contractAddress, msg) + suite.NoError(err) + suite.NotEmpty(data) + + // default method should be ordered + var response ictxtypes.MsgRegisterInterchainAccountResponse + err = response.Unmarshal(data) + suite.NoError(err) + channel, found := channelKeeper.GetChannel(suite.ctx, response.PortId, response.ChannelId) + suite.True(found) + suite.Equal(channel.Ordering, ibcchanneltypes.UNORDERED) +} + func (suite *CustomMessengerTestSuite) TestRegisterInterchainQuery() { err := testutil.SetupICAPath(suite.Path, suite.contractAddress.String()) suite.Require().NoError(err) diff --git a/wasmbinding/testdata/reflect.wasm b/wasmbinding/testdata/reflect.wasm index 174232f4b63e9248ea5719711dfc9cc8ace8254e..df893365f3253e94b0369edb5598cc4fc88bafcc 100644 GIT binary patch literal 579620 zcmeFa3%Ffnb?-fI>$cZkJ1Z9;kce|FqwXz9jV&e-X`7jcaQRA4(egZp_MwL$$q|x> z5Tm8vV*HB>-RLGacFOM56{r7a37R@9(aK(XMZRgd5AKgK)fT5Df& zZ}ogO=$>=UIp5nD;~n?+eWSBq^ny5wqWCSz(HoMBFODzP-)KX6vEAzuZHVpvyvq2= zeN7jxb-QxY@Eh)$;cn<5<)X3-_f+|^XhY<87soI2T3*I8tCs6nS%=!NCiytI_+|VJ zEvoR#^tL_tR9&Ap^i#JyS~%@dcznbxkHag~Ou^d4FXLa7>`LaRo6dhp?d<2haNG7M z(|u>-^UgYd(?#3Qddb;aU%V-*=~=scwq?^F_>%@twrx6lqyK91>-V>vw|!F->+_bq ze8CG}vdOE|$1ghP?DL~UZ}m$Jc+t+;8#iuKTjy;&oATD&e0xTL7oLCKIlTFQH${w*_QPu=gT zrio1(fBBiue8#gz$}B1$KJV=9=bSt8s5AM@A)&FCC&u3|7Px;vXrxL2)UuXK1D(oNaT0Q*DmuQ1T$KXrB#oj*lpM|gYBfI2(oWP!qh^%UlC*XN zUjgVe>LjYZ-d=p9}Tu8{HY#wr#p#>mNj)iL)2Ic;gGBzmFR)IPdw}^!;b!?zT-AzWBUtn_k2m zeew2fFFZebW70f(>(&>ZqxWA)#x`!Me%+tUufAsTQ^O0l@%f+%I&U(gNFMfHh7r!#si(_Yh@ylne%7IFLf_B;QEBmV7<=m*k=3;pCCz+sX02`s>F%`&qyCo#fHv zyUD*MAB#T~|7Co0{Lk4f@viuj@n6L^#ka;Ej(?h*^M>Su@s9KZ@ypY?tRd~f{4_?z($ z;xEPjC%!!STzq5l^fxE(O|DC>NIsCfFZqk)w?C6ypL{5JbM`@~_S)oz0XOukP&KZ^e?xhnaS(ck7A4z}vQ|bTa z-LClN^p^Cy@rTn7rGHDY5AgES>7D6K>EESy@cxGMs$_Ti4elOJ|0R7WeSo_M`TsrH zPxdte+L}_I{ej{Fk1x zq|dcz{^pW?T3r01;)yTm#gxgiwRw_ftCFR8QpBs0#r&ddv?^IN9=CbM-C|vvn^g-p zi#B)vI?j{HWV~mW=6b4#@^n>_aiNN6JZaO?%XjS9anXsLI9HD-n-ty6RNQ?PT(tXY z{_rHOX_3c62<~J_B@t!##mAx%RLAUG&sjgV;SRS$h{hXj#nT_*XA`E>D2{V-SwNg zWGCuH-t5lz*G*pLO(CfS6u$+~Y&M4RBX3#mpL9hmM@dNNtm zeG3zVw^8?#X`7;Jw=9e1wTt^GUaaQ#uWv4{xSsn*`O|$b%0HI6AZd2H84r8~OH-+7?>DV0` z!EV#B`(P4hfd%{mLl#oXP6O=#xckmjgd|Ycy6=EM_YUc7I;6ANAbo3+#Ll3qnbh5! zC*7;lWUc>a^Tpl5EIxNi{A@rHk=9kxMHv?xAcFZAzLil3}`=}z>%T)n&7((?TyQFi7l>^u!-0t zmqEX20ydX`T{M^nCSb=UU>A>2^>hKdQd-#C#?f37X)c$?TTI59>XIdue9I)?YMMa0 z>mvk$d_z4zOxbI634Td3)xX4=Sz>Y`$KP4Z1DLMT|XT2WboeB;${E&SY4)TM#w zMFTNq%?(QRf27R*HOrOyU3B75xl|s*6o6t*(ha(}S zd}(o)LD{9BECycm8hYRCAuvXeFhGIsfWXNns7e@}8a_{p+oR3JV{{l<)$A^|VkV=6 zQGffnOL>ci6W$tLtt(Vatt+BagPcl>2d$7WQ;D16KAxG3G0Ag5zp*;qKwlcGlha*7 z>4Q;p-fK_Fz7FvDI~6`pcS6|D_9Ug~%4u9DlhZU1BSKhpMTE1>IZaTTT0<0hV1(2x z38^(JA$vNKQ(NXOfcH3+KAM0BS@>Ow6>nAJVw(I=2`S z#1J#|?o7lnnQTPs2=u6*8~SEGoNIQ2EZW2k2cT?(yLJm-gXbZ#U=9zc;&f5P8mEf! z@w8oF7E%KKo)r<)r8b(KL~kk^M1(tPgivCoNNH~kO@@X<4vb2c?x15*kH*!VQLzBI zVt4i6sjy)b9!gyvOEmnKQCkcfwM&7|-ZY+lGiqPTY^C5I%Tx;r zei&Os0p^aW>*`(}I+!6qt%KMM)+uC>xjOJ+4fmD;TZ)=kkzUkcMbk?4YsFhGt7KZO zpq{t$`{|MSF|5#F>{grU3wj}aVOnjazF@C|z5r@)V&MWQkqFDMnLcE+%nHC9SPZ-& z0wCZUH9;P#m2Rd-qn}e{Eh*)I{7jNTVk}%mM<^5zy`}~*hd+Ht@yN@PS{SWBRHL`oLDcKj(ziSIh}Cty3@&CQt0++* zm6gwNoLQOD_OV(_$>qZ-ycB4aD=CC7Y0QPHc!~(iU4n5zw1q0rF~xu~8EEA*4-L## z?b=YS3gGe6C(uCnUd@qIK0vNB-Q74ni4~?IeG^$fk#9 zol#2V7&toc%^w;^$AVIJE}T_%-uFjCHq^Y$#Y6nA93Loyy9e)OoG%>ok)OfauNV8| z_^3;oWdnvlc);Xn-DM}nIZux534E!TflPT!^+w4P1TA>N0E8pvXT=kEUul?xI;>Hw z^{Xtlv9g2aL`#^qnxzRukH(l5>Gqf=6LUx}a@8bH#EXn8z@QF7H&Ju=1qpMgxen2Hl!H=Ra5j+yK2$6D5RB@8l!j?- zB_$uK!R7k3N|4us5I50j{-dP>USVQ*k;E`2wAhmI85|Y^Nhqdda(U6;vlWi}$Tg)yvfJR7=U_@v%WgGH9Sj925_T!*wG$gQ~ zZH%g*X-H7HrlAxIsxiY`nucXrl$u6Unnrl(nudLD9Kb(RIz~<*C1H?VAWdUGk~XCD z0x@gXHH|M1rFKb!4(2!OCS@Jp~c<0NKDx5*<$Sceo~BW-BPUFc3jjd#*&MR z7F0EMN+&u>Zo*>h0(;fO^OO}|kABmiXT|R5{PJA`k5g7W*a&5GTfM6jy~>Kq|30c- za$mhAK*!swUth1@a$mj8FsHL(*CoGNz2&}oiFn<-^2Sp9FIK$otXOUdFaXO$c3S{c&2#AYONfKCM+gsAv*fX4Y9Jh@qZ5&1|bs+SB$h>-h+id@ZLfI~p zM^Qf$3u4)LRLu2Cf^wHDDJ+NJKWVI zNhES-;WVG@*J)Bua~eWBFOpsgC^I>xc-j-;@TS*Tm-NQ?e>+|4og4aFIrc?b{bsTJ zB$;}}Pa<8-PDh5fNLX1QWp>BQE~E*|HM4iL+2!4Qh|aqzqdRo!NSdb?i`BP|xx3Xu ztLT%>Tr8v-N|MC+ljy`wcYL1Q;k@s`MtiA#Ci0|}b#=o4vz{D{+4zJFaDLIJm&F7< z;6dnteCqY?|DtULpDntu0Z$6Q&Xk98GC8B47KdweH7c6dHoeDT$9U(RgzL0fd}PP2 zsF>G%K!z_3ra0J&1Qy&Z{-%7hgr{*E38efYibY2i@X(=>dZIG5p)ze?(v+4}Q`noD zC5r$mqu)lJIRKa-m>EZaE6K-Kr>Al0tY#u6d3#;N|C8q~S)HDokMRSHK6i;h!r}<^ z?i+2)HoOx%2>|>tph%E?Vj|-3Jex|+T%Bx}7gEImLV^lXc6w@jTyS>?KFwg&q0XuF z++IhQ4ZSf%NYsn6WB|w1IPTHWlCl=9D6t(CZL4Tf+^IfICg)mzire&yx2wH(;AmB{ zc6>}9614!2$LQk=gfWJs$6g}YZY8`njk6jd3G{0AorBeKlbxG+~)_Q9{fc=sUWJUJRIaPqv3)ec*(P)^#H!z8`I=9Mk2SVO`1G4-jW+P5keUS z=zR{P3~*2DsX-w%?!F@TI)o z!;}@tKyGT5XpvO0bQnf+)mnm2z1v|K5@*M;(wE6wwB&THK_EJBRnwcLo0Xmqd*o&k{e{#d?wZ_9YDf&FdpZ|O&$}cm)ALY8hB)^dLnOu-qiAj= z)6rlQ*zcQYMZA}oiZQeVB=BRZ__i~4XMYj{#dRM71ZnqjgY`^o zGk1w0cBhJrg?H*jr}VtQzlpA|*fNndV`B&s2IKWM>`o@sGq#8}i`FTfjE7(ZDh53m zF+vaMO9tkRVaL3vd-+T&Hrg7eDAj1W#YIoKv;z@Czb2PzAnN*cKaF3}tBXO&3W~c| z*kA(B*SL;^L|2{y{Gat3+kirlXqs~CqIIyb?l%DHRN6gFoR+~`LIrthSe_L023|^* zWaD?4koEz*F@h3GG9_1np3-GK*Yu;yVHr)?WnO4)PDCfQKB4`&c}dItVfPcSGg?zf zCJ6AEGIGWf1&-H12ARFluV+CnUy8O&Jc-4n@t*$G;<_=G{+5Y$5|#gIJQK}21gTFP zhzZJFtCs;@Vm&AF=gZNF+qfVzw{;p0Oy-B6&X=N3E|D`YK?C*?jV}yvsqw&|K+HX$ z5}9r}<{G(*nwafaEt0JrQei~bp1&1KsGZwJjNQbnO(MssLJ z$|*;>)1$?RR4QBw5PF$26QAdN+F+PaH?9t!yiTT&1!UT5raa|&Q;qfOt_alyab#)M ztBc0+I;u;9g-1+}hR=9rnyOVD10}^i;K}?RlE^AlJrMXp${PO%3=J1h}@q(I4fc2whn zXc^~%Xkj%}4rK9F=d6vA+S1sJD%O=a5<3>JtVE1KKhI9;w1gB>SSORUVvi?v#wyzQ z;{k1$Wbx*~6q9i(Io*AvcwNe*J2h*3iNy<|3vtdsg;JZ>t7_MqPwIf~Ko{fc!klzL zMS(6RRh#HSkTZfmmFEIXMIF#KcSp)KTD`J3{d7&a9<*ds z7gOj&A$1Tg?U>a{Gl^xsl+kj=2}?$H&7d6@UC4%6zJ%iFDE87+VgsVpVc3FqRS zrE0AA5X3+==0Rv47&n4uyv9{x{C+O%AeWPv`1SRur`t5u>On!3Lj(o2h_~Tjuz6^z zrB&rpb5MbxMJSv>!a<^t5Y_ql-KgQOLc!=edn75X>9HVXqsUyllu&q(^W=2?#iY8*X! zoV&KoJBwaOtDdVGC^S^lthC%q&|*x>EmgYefe+(^p(%}09~5vGw3RA6OP5Wvur6Z& zP1mT)wuV$}4Qo$riFw>_83_+Ie(uxx_83Ea^xjuKR$mnXLMHsd#Sjf7w$36CxqBjt z4Vu_Sn;WGZbEiCf=FxGHQulx&f62@H2PNF0mf`DR&iZ;|Ta;!MpsiUJfmo}l3d^Y# z2bET}Fy(Yd$_y6^8<1mECVMc~`8AsCQLfft)`sr}GQ^I~jC zKuEf?Ts;*DS+H)nl%rxQFz)EQDqD|n+X9bN_SkakYou$)+-Njb4Tb{jdORB4%7 z2oZV|D<}2~{0=#>R_LJO!vVK2!>h1b26!Fd?@JZ_7J)wtMtU0a1{^WKS+<}h@9z=N zW!|AUs;%$XhcY5BOIiZgrq4+K;j6!o>}FmLE+@&+>zKdFJJ@KIBic`#Nlm;{JGZ zJ`ZKc{S~D>b3e>A=z?YrqauAZ#`Ek>QayrS@bK}tKTo<^K2NH2_c$KpT@4WHW)T)f z5`1;mw3|8iT7&L`zAx^ve4x0CM~H}fV{=1~_T;XzCsA)cUTItINW=di6Lr2c@p)8m zce1&sjPBiB#i(u|@iW`j(-s5p6o-E^S*~0Z>d~KfH1#-_96I-{9W`|Ih6wI_4(t6@x_Yh)_9<*^CWn&fd#kj#r_2DM?w0Q1n6<{GNhrWQPTn|P-0L|Ut07niyGgcl3m`U-8 zq*PMPD7i6N&Bj6M-D$-SNY=w2QsV6Wez?v3Vn48~1RDmpEon;=~R$EzK7PLR~6Qh+3UctKP$fdpj|E zL_n@$geg2Vj$g&PU(UE+De{FEt~IZwW+M zx2(;uFhw}w7akW~qAL@6hpuS$KaRO}iirOwC$T}C=?~KKZ0cz92b3=c zYy(J&TM~<}+Bi(tpfof124MZ;*aQ3GuptOul8`}K!v-z8Eng%t*dzsNPDT8Xrg{@} z7$!jjj+Ycc$qBHpl$?BmAdUR+15HOfz5Fkrq6&!KGNjesBCS?+uZTW6Y-=<$D@@l> zx(mS~={kdSm!Ru3+v7)9y3P$&t=kwkqKVR*Yj`9&h)Z?n2&9Mkey>rxNNRq2%y32Y z7co>rI~VrG)6z1KI%AnC5R$1gr42AXtjhuS7-d)K%KdoUX+CWE;YhnueSE3 z(UjE(jm8>K?gtvp5jnwH5x;%YOVMbKkZ&|8t{kfJ%5o^Ywc&XB&fDTrsj)IaPBC@p zOJx{XjEHGtjDTqa&}`Z$Is@FjJz$UuRO&kJZAGKUi&tFU^zFE>+bD*;~ zEGUpK%9jMbF5M$vQt|bQjROS24<;Gm5-LWwoqU^J6D%+llO;fBfuM3D=2CzTp96%W z3>A|wx#=IaMPp)=_i1J?ScN>|$`ZA^b%jIRm3Weh=4aF6c+5}hJQOjf@T&^fH9Kk* zFATUSdEvBft22hw2>~aflDT>Y52I(wewphNMMn6JB-wB)S-JtUAp4?cUBpod$KT$ayKe{DT$%+l?13nBN8F>zils2DlZ z#aK+o*?1?oaw;~C!HwqZiZ^RAMV0mrw%6qyQZsYgl-K~bZk(RyvgBNAU36$o)XEe^ zOk4Eg8cm(pX%6DBV&iR}LJFCbm2FThG>7f4VOhj-MRaz_#4SxH^g*PM4VbtQIBW_K zneJmW3lf8ON4iwaT7&{x&d6(wuBI8%DgIshrkpxr`e()FERaa4uuNu;F3$n^o-BTHOo#^}b~{@yQ1=3> zb(ZQZ7pu!yt0F8VUHpy{*%?4lIfcq`63aA!)RE#5>__C2{cQKTKJMNVWqLwuvoly2 ztBI#hV6fJsVFs&IUavQwR=y5K;>aI-BK$26W8UJ{#vEQKhbZc z&UX2dE@Bi*!i}<7S!z#@Zh{_)o0BR(1|vwl=^ZV$0p1q6YgvKMrbV8f)R`w;R^S`Moka)I+ml{T z*u2dx57*coe6F$^_?{j;z}Lk$r}Z9F&U%k2w@`kY%*_?ihmUtfbTe);l7Y%a0D-P6v)kdrojm>N5;%*Lp1@08Vb#*2WF-m?TNO+5EhS6gBkU5 zjpY?Q8kkWd2oql)LxoT!`fPrw6_~v?-|GQCW=K)e3@N7Oz+|DF`KBnmT#Cqg3=~ro zOkSIfH?|)0ZW~kB99hqMqn!9RC1_9x4{<{N|%;v+?_k<8$ej~zupx8AI7fq zXdeGG4im-e|A`q?Q`o9LWQIC>{lWDP0=mzReiCXTJY>mXJbmJ7>JWO4i_G2yeLswI zC6*Q+{u3mTB0BV|`%Io;)mpGu$)i;jkt%NGkt}KUiPijE&SjqG>*9sT`GwW34Z@&_ z#az&9wFfp$k8`2rCKvb}NrrM#!Bq*3X7@26NF-#Mu4>bT-f_`to>4t3MvR%Vlbu1ErvUwUE|=b* z?C3Sz(ah;IW6=uFCr^siq(`4&4;ORCG6R`e30bh+)6L&m_6_WYzA2I8-YhW?%-%Z` zC|das?j7?}j5pI9fHfpaErTrL?p^SK^&R{UxT2|j zw{pyfmaz-h5JkjLp}jIwR|+e+M}r5`i)f~aA4UT9UNXA`@I?SP5)PJnGFojY87=X{ z3kreZRa#1s6t+K}yo% zxfR1-$%;?{eaD?5Q@Wy3VYXsW>GkWzUe>Rpd+lWM)OTtt8Dbfdlv;&X`z>jvQDOaL zR#7$Rs}lSIIaU-Cc)Gr>5cjUckDnm5Hd_{{r{3FOuDHB{QsV)o!kI*=_=jkcRCBiZ zgHn~?3*%apXMQSywxY7`4xLIskGro)842TN$D-9N0zvSga{F#Z>S)%*XvoBKMX5RO zkPtosgbK1nOTZXRa0C3g_*tW`wkQ1rEgf~6wMVzePQnkN(X z#3|#1e$6BcdxWv`!g0|FZqf#CD|+s9X$Xz06K)z$s$uuPE?0iAz{d2Q?6>I-T31b- z@&D9;d_aah>|{+11zEM=tk+GePs<`)<&E{Ei7LO|7aFz*25XTaZVEF<$<#I$-eP=8 zp~e7cdmq8FdZYG_q){%O#SaP1k&ZEL=@=HWV4|0WyXw5bQ!5HnTlq%9ekt2)dJvk_ zO0;&c)?exg(-*1f$z;0+mD#G;-L10J8+6w~LbB8YuUTMUWYQYKxL>utd0Vidu1u4l@9j#)d4#~mRXbluBu)at!7`FBa4a*qAK@;qJ zTWnZ|oD6h5IW{a^-90t!;Fi6>l}d>vGA;Q#yxtB*v3+&2QEbceD98mayBESj4!_b{ z>$Mqo^%v%>eW?e2wqtSu*Na&2!^J*DR34SrdmS^ZCzEL(DqqAGw~2XjdpA9lpyF1^ z8ANTkl~g+wV2{Z{^kAmC8Gt^mo8EHMF=}Q414L;xHZd5xDPxv%+3uo@kzLE0034B~ z;%)Wx`g1)|XCpyOGpNuQprm8`YjaNmHt#5K+~}&DdoG)H4?xS8i6l>ARpLvk2_S2jIEbb z)>>kfi5e9;(Cl?9bl|h#*3cn6j@?D1$H`@)RQxl!@Uiq#K9tT%f6+~a&{GGF724lA zsImf_YB-h2(=eM&*ed5bOQ^&s#GoYSJW6kn|0nuXxvZ^+*!JonAW=7<8+8MTajLpu z7U^>!A)BRkNKF$;9w+O#*B~7MU%A8tkCY*3QlbG91t_%5uA8(j?_7gCEl?QT3?Qnr z9(Mv}?zSO=HZb&Qi#+LsxH=#>!`0W*-Gg(QWBpVZ5^I!j7mhu%iE19t6coV20tzI(Lwlfrb=MUNhC5S{8k|C;MsP={ z2Jt7O2)ssYIR`@IVRfG=!E1Vk5w|UZg)*c;AXuagai=9teg^^KisG4wNm@k*(yA=g z`PMZ8*tYWZTg{|%ajL{m?I7w}X+GVG7?r$W0GjrNbFnXwGRtW8odpV8IENQJSRIJb za!Y}wPCAQ?9^g33^JE=+;w@v;49k*uf={WGnL2t)0U<4L)9&k%`*2sLhn9k>o57P_ zrI7h5I;fG)SZ;&lYe1QhK!|Drt1`fO4f9`{lhm}BBI8uJHk)YyP|dj=`6=va)|&tvb-Kd( zBN@{=*rT>xDyUT?RabNcWO%D9uwW?>H-4-ddMoy<)K@!Jt>%6Yzz%Im@~49%;?zAW zIsJ&Z3?{@XCPui-#lmu}LRV0}wp~Yl&6B~KxX2t<<-@lT<$k-UHii_O*R%XQ5ehr`@--l(i47mCL zFo+blwCRC7WZp;dGPBbVz$|{gIrS3{586;u{;H^V4~803h{gOdQ|MwdrZgk9uRcrR zVT^bxw0u7b4UDphzt_C>C>eKaCta0o*l7?HF$mk}A*JwzTc^(BV-mF1`z>eRX4 z=Hr5>xb$7S*p{UDAs1VkH+XdEyJtMQa^|CJWM&>fH5S!?##OgL9eOldZx5oHpydZu+mvXwLXHiGUblqaQX6J2 zxb{b(XTj4$P>%&Mg|ImZ$5KZ3_=S-#RA@(tY2~ibr2Tp)PQhx+)j7PvK7k}XrSkv* z?pg=y8)h1@9LZWvD-P$4CFHeqyI3GD(Xc-MA|(`e=ZEf(x1#G0UK# zGxe*iBplC;tY$0os0fwRWX@(om88=u*+dzj(PD~SOe-ZAqC-fXrq%a0~;dffR$i~CH`i)ix!OL|rmm-9I z7Zf4+{PyTl=e>{Zt8pBMO~^)BbOA>~O9=*gu4HoE9m(l)0mzhXix-4ak zj_kSHMWm_rAKzn+bQkZLIT;8LuX{N*)UL?3rYg7ck;UUL?q>@i?F^r^BU=2ydkdjX%f~D(vsB{S1cm#l> zh%!0YJ(Go9@)b#yypL{@g7p?6G`7K}>ACw?*>RyR5t+70lofLT)%-+#D&$rMP&Mrw z$exZSMm2sqThnpE>}#C^5{wdi8riK2Jx7VrUGudQHmE4~kFnjg{;gheRfRZG zgQ~?h_8+R+js?Kp^cDcCZ6ixgCUtu40l-DzRUM)bb{GP?p@pCBv=-i_jRKOjxX$bb zBGMsqw(K2k_PFSH|6Y3(6mL`_|CnkrxfKrVU5h1Qb=o&?xr}eHkRZ6BbB(O$iY2Kr z8dwn>-@Vc@1v#@Pt}4eb_fjL-sNCuccg`qzhh8T zw5zznfuTc28a44}L@4Zu&03LZY}TFK(;uR=%n+zNf*~J(mT+h|vTK;1Zj>DPP$@%y zD~>!~apZ&N#&hxG@4SbG79A{$**8_fmp)0Enm%3R>Yhe&b7~VMCw6VZrv5A5%OH+C z=t1n$oS&OPx=N%qC)21ONgsj$)jTM5J2_VZvww#MvGAY=p$hlPxXMXCjEPdO6DEGR zPlKrRy0k5WVt*&TsbtgUxXtFDt$OuX=of()ESVL&M|7oP_oiu{_+icLxc|%iQ^JY|C5ar&Tk*#=X<5-gB1bQ>D~vfXq&Nc zAZC$~@`(7`D=!l9AD~W8RtAx}Pmh-pZ% z$>~dGDEU7%YCBj~22A%|$$xcasGkf46aG9Tn$n1tKkx;RClt<;KX_$qq=}L*(XrFAK0S&EWOluAe z360o3m;8}Kjr4%PVh;iz!!^@i-13fM*F#1a*gl)JrD+fs?-l$zz&{8p>*#^9)4j^4 z0qB*BJhTldj;0x^;a*20c5JNU7tTHkv$Ehw28f01ii2f+qLYqs2S zv1M(oxXf5sso1Lr2gVi1j}J!5n}v=;#+6m?URlG{Y7(_{*j8~ta}Yo)M`TWxH_1Ur z%Gy-Arpt*U=+uX*=0l3;kv@B(_H2kgRDFL>1@}ovY2}bKT+i_U2TDpL(F9U@pXwh! zR5M%k{%lC89MLpVT6^%MG*a^b9f!~pIMPBztV<68R~oIk;z|Qja;|g`#5&T#M?_5W zDji$)T`LX_lt^uN5feWjQ@w{w{HWf&66t@4_$fzZM0%?Rr5uwqKX@V?sktJdO0caz zh(L(anLH43=ON`4s`qDuhH^xPhJj$4KBEstgSV6~quqNA&Hq^%{M=-FP#V0M$NT3^ zvLe&`ita3){&3dNgZYi7e>t14(tV!OzJ#=X_VI|1F5=Y6*p`?ad~$~N<%^3?PxoPJ zoY&ZiPzR*?D=o>AUQ*lmFD~vJPR_U{mgiATT!$TZhHeYC45Y|$(V5(%41w4e{uZN7ghDbH^6N zEGbXCb{f)7YH4v}EPbfV-6)qA)6FS*+~=gdOVxinlEq9>OA0H8`X%*QrnSS+WT4g( zS*>MOgy^aobI9NLV7!XmG%C1g^I5qjtz#vyR*nGcSUz!Jt=v2Wt8N7=v#t+xOg4WG zs^>P@lwwyxRO8VIN;r;YA_<_%%Lrk7U*M9l+yq3g)S6|X`d9!;N)?%0mgXc>v#c+m z8bbn9+iPV_Q4^@nglc7Bp6Bs!md*n~U!cep{hwwZ&y^$;{e{cR$V^4a)b*io}xE z9Oboe_^=b1BBUif^%9xg{3JcnrdXfzc(aRHth9J5OSY2r;TSqgROSp{rF3yIFtBzA zFzBHY<#hD6A3w|!OOz|2C!%Xwh+;)_L##Qdx!lX#o8*(Uf&I&r);d3Wr&UkAM3GQ}g*rK##UuQFdSrM~ zZS}zbtTw~1UI@R_`w;MJuZQqE1}2{C$W?Z+U`7UL1+&>kBji|~+URHw{qVmtZTOEJ z+ToLB`{(ditq^(#S8+JTo)+&QCUM(!td6;vC2dUf4<}-8Y~f@CSX>HCnoM{H=UC|Z zpT`8{jQD(+7>_QEZK7!V#I(3#gv*Pz-1R8-beXaFi=ZW#lF^b|8(9%`J$iKps;`by z?;%c*MXh2nr_Ql9t%zVdwsVyZ8F{O*^EGS-Mj|L>El052St2by%aE?P9(nO7f4c8w z`w9A`mAnIgEKzkD=QWJDMquM*cxmxXjkqSudOf;ThqO!(q`Hi26UjFnfKc%>w!K$v)Xq2rjQ zm11v(p^2vz+QSpi3QeocCZ1ks;!UfqWUTgjXyP#u%ZX=Pm1%2eGaw(JC^fb5V3L4C zV&SClF_Z*sk~9+%@_abKQG!%)?V;qtyDYizgK2rN8Vh1cmbMIN+xwTbo|a2%tlucc z*))^J*fjZ;;E`Xf3}!garcJW)tYXt7S4*&1CxFu_DP-@-3-f`>K-}0S%ZvJ+(+E~7p*p3!AjH|dXKCO6(aeFO{m+t8Vub z4K+$_DBw)R^15)wVWMS0kj-;LaL|TKK$o>pU`x?*{iRMaBZpK35(%Z)2^=j@Gp6 zfPa-~%YowKO24qB$7mijNod(hBGj!e|Ef&VAhjKm^nCO1A=OHwqYxFZh)$Il;>Q|x z4ATg)6?{i&Ho@4ceJZrJ#m;lK0opQzFu=6LEmSI^brp}#(4w3qW{i(s?%Vk4Mk_<( z(_|B@M#finCI)avhA16()*;sUlD(riz>8&{Y`mefyli>BmTYL^x}*gh&5l`snWPq< zu$f-a)3iu83_(f~Yv6uoRa8{SI$m~1X2~#K3iHp56|c!}wMEtG{ibsFQJE!Kr4=e$ zrYs}DOXYS;Ioj<_0*cr)}(k$%y?7xXXWYHUwSGKJ|V+xJww=p1BLOVY*SpR>Ii+i>)N6 z^FIr=!bXRgdn#F**Vw!2Vv0$SQq59I;qvCF^HJ3WEy7(92dcWbJVbfX`B88cmg>#m zDz<=ccXpJ7Bz}m4U?Avf$R;xY8d@_}>%P-e#s)Eb)Z@>~C#lEUY-(9Q)@8YDSFV$$ ztoZU<{cfUBHpK87E<2s!H}Zy77`3J|{FX8NQlo4jS{@?X`T*~(R$OdAAVreYrZ+-M zyT-~+m@>$qvWX;$k>m-R8R1GmyNHXcuiF*jVMHlN*r-{?FiUge?rZFHNdcm-KiK^$ z-w(UET2blYQ02+&gE)OBSE^El2yWZS73YN#$5{cWOOp$>IMxno7)v|BT+W`AlG0|{ z1;bCjQ{X?mU!`xn`q?9sc|O^$PRpIAvd!JMg}h`l8~n6TEu1t}v?*mj(a@w5N-o$& zISfgfpsk7pB3Q&hOO)8SJjG`q+j|!h7WCLsS&Ck+gK4aeeW}|P$<9`-RBEdYo!T}p zyCT)`OB>XEL_SSlnM$drEjRBh$DViWzsUn*9!zeAW3QF*=5B`4%8WSJ*_elWn$gXv z^Bt-AI84pc9;u$tPy15|?X!&%BV#uuHh2O*+Wse$aW|y039F9D38#)nZ%bE2&nm~T zDmhllqH==xBU%!W%jvUTL)PII_6Y{`MjOkaH=rN6<1<&i_2Dms^NOXLACv*jP(%)? z`Jx?dMg##zaxD0Nd?=SOqXe9#JNn9aD?5Cp>w93_j*b<4zQy6NBD1%po8>t!uHcH( zy3paV!v06Oc0dPai#FOY|1~?p1eO>7o%s~os7y}W5@GL!q9e7;@Kd8CElV9+xa_6&v*08 zNqa!hk7`&@^qt!3ixT?A%at^Z$4KKJqUL`HprDLRg9ocJrJ>^WOmFM{L0i^G2pp(t zbb0FDX<^OA$9o$SxC+jBp|Bb(1-2B4+zs3zD}p851VP@)d@IqnK5|9)g3 zsXa+?DW%(R9}}e#YMk)EL1E&xJLFwN9WpYii%8jHPGyGRb&{PBGW_IZ-&Sz&tn|RPYdp zb_+y2x}R%c54<9ze_u7RrO&3>6O3zU-0PCth3Xsc!jL#hkw{j@x2~j8u?p8gI6DbyTG=efD)n$5nCR8QbYw5IZtzA?$W~fknXCDe(T6NJ7fxixLZV(za1}v-; z9ZApTOUSv>vttCEp7%66B>V`Okt)r-fIa2l7q@Qw8{i`&SKu)75=u#Br(PCENhNKmx4C74u!W^vgEb^)<2 zyoPVJc_rNccrGyOHC(i}kG7N5-5Tyz+MPDKoXo|(NVYtki;gI0-;4h6pS|1J|B#f7 z%xL`|vuy8F15OM`@FbulHA_5vzxO)(@cC+XwYFOs17*U15;rF;0cjbI7N%QFs zt1Sh)zi0THxih0PH^eFaj<83eGc$j*)EzBsI10DX2~B)9$+JOiqEsFlrRr(8eWcnY zusV83@_66&FOd>ssz;LmRmp+fY19x7w-f4Al)m zLYIm%b=R66Rdxwt@Qha@nSUf3X@5Fpob8Zw3d>)aw)?v=-%{;BCT6ru^P3515HxWk z4vG+D9=LYSwjx)YuiT6LbhGNsyF!4pUml@&GEGs%x}^6Mj>Smr?A;a7Da0$W^DZ$x&PIfBFoUHq^_N$q{uA#B}kS<*{g3cJqq2uhRe6|jYhu~~tYS*XVC;@XACv2n=Ze5Idx~8zhpe03 zDLcwtPZ;vkY;ZQBsq}*03QDKv_9i*VTv*fr0bcfYm2Fej&SEe7GMI`(Fp4Mw2QIN- zo6*A#7*&g7cXe#nFwjSj-L-+CHbY7^^T|zthbJ2z+(7h}Iqzif0{`OxK{|W#$+l5_ zoAKqTkp@#Vs8)h$m%FfH`W(w4jA

Wp|FW{uo2_Nc$X+xdJpT9R8tNrx19qpZ)j;M$lVt;}aNkH9gQCRu8i;zPsZ;G<6Zc09t=R60IBsFvrK`}%o55|lgmtUud^23)P`VQk}-V#LNLT)COAR6a$ z(_R9*8RMq41ok?$F0%eD={wG6A%t_munz*XPTwUzfk?lHSwu zrPt?A^7~`*CD-SDzh9mob$#CR`^o&s>+{_2r}7o+COLql&Q%AI)bbTOp<J9?n&E*+Mvxr143IJU2w6V_f~`T`&;|i;JcfZ% zbmkDqi$pMyjuvx;W^lU3;~ylG_)QtYx>D0Pd#R~fkY}8&$psa?Ie0y9vzu+;*Nyrq zKfp?{V7fgJ>ScwpI+|gj&BmcV2N|i^Ej?ojXlNADBb1AJxJ6PqA?XQr+^-)Yv~)d3 zDCxZBZIb?nnfH>r?T5>$-AvD#z55wYw?_%BzyCT!6ZKIZsjk8S{;f#^JE1`{TZjJ_UeM z2blWB4n>%clCn~wbhjP2QR38`MrO4KUEci|R=E3na7<3U*%cK_iy?9{v=7Jzt%LqW z-hezFpd2ei=F!_@d?jE3>v%1}adWnK8hMq?;BQYY-(otL#T_vwQU(0&8Rc80@yQ+^ zdAqTE>)X>zdwW6o_VLlO?Z@IMLA@RPN3S`LubpNw_M85h*)|nLq#J+c6+igQmp=MH z^c*~;=2QC4{cnEk``6z4!H1&fB9AK%5q^ESkT|_WP%~q1$SD;ZOmXq3-p<3K15+d} zmcND_SRD0e&ZyG&l$AAyz`d^MkdmwIs zJsg26y0=vApT*eTH8i$&{RfWifh=j@c^pg|-4zfy$1iKku;$LZxvtJR1l1NVk$cg^ zl-!91)lMeInhWE2&F6k2Tbr&GV=KnDlE=>@I5HRVu_;yS#k`$0{b*c?M&zMy(E*Cs zmx^<$gh`6j0>&X#81l89o_HHhm5!2PS^!z0{RRmqdXGyE;pv(v+~-9yhdgl9PQ`40c4dbgE_|B1cRyr5Ne&sues z?PC+5But!9`?FKSGiT5K?2PcNWXezo-iuHpXbMhMC6cKPdlKoYC++qvW9HxCKCAiw!B{^D+VTv2CYURRnBo`CN2Y)qD~=3N~*)WRR>ObhE(-X|J4 zK|vz|bA`#yo|_~&pse(j8A(R&XH_L4JZswmYu?b@zGvo&O%dCY#T%ZxRohC78p}i? z^s|oMc2v-fvM{ISj?sJUd^8tz>%4^62ObkK(XnA;KBE}!B36JnbS3LNH@Qh<^ zt7oT$XDHCdgN=8c$;1Ejc_A)Yu?>T=2$N}Gm{fNL=kE}yP`^JH$C=I~XJH><0I^Is z0Tz(dZ^H2u$oee)*iL3e%zr5-U2?UPF12LHIL7DS_qnH?Qg9e{jna~+q$(;jiTTMV zIw#LSf``{mx=eH+4kukEabfHyTj`A3c>m{Hk5@4ofj@aF$nb!|TKE z4!VLUHlB>4;%lG!%(Zp=zeOSwHZJ~3Uzy6D6{)-w_SLsPb(6j#@7F^%f2*(TtZ&Q( z582$QM=8xwmz~lQ7oX)3h_jGQLm`{y%#h9d8s+vKgpxgCgC}Taz(&K=L6ud=28Uo7 zv2lkWU|SK+jU^yxAsf@*6-y!Sc{FC@=f>g%nC;xyOihiP8%zH2GQ*0U4_dHjNR5@} z#_H^P;K`HuI3OS^og2$TAtx1rELOxyc?;6ib=oT$O^e={vl|0uj^koEw2DfJ;wa@B z)4e(;wr)NW`OKQ`rCrk-Q>TxWKSW@vD{k5(ETZ5kG9)ZNhFhQ){xP6}pQB!KSw>m| zu}KccLF-KOG5k5dX6e^szov{txo7`3WD)&sp3;WgH0pZU=uF*7;sMQGD-f&sfTjf+QU)0#byOzhgUZLS4RF($u< z%IRCA0h?b5U2J+D0COqi0c5ir{%UbFfR||@m!rjxbH>L^SDAUCt0Z!JSFsax{4A19ur(ah61hg0VNnf)qJ)(a|A=bcukXxx_UIs4WuzDz`0c0;(Yx4mlRYK6jFhz| zts|zIh3=W|Exiywbd_OKH=Thmtc6NFccnWNtn3J~o(AKp?3|fRV|F{on5)NT`Bvo) zU~mw_o?Dm;4T)zI&DF8li_HZ}n^Xam`evUh z^`O8@O)SgY@5Gf8Eky5irAf{5U%;wIGFb3nI+oHDey|yVkpxp~c`O;LbB&j+A1g#4&}LQO+zzLSUy)VoR~GQ0gK{E=#DE(6znnflq$U zSDy(4lobv1LqrWD)q8ZrL9PoALi0*Ms)ww%GP}j~vop2ehppZEO;kFD)B>qHhOkv6&ZeA_yy8$KQ>b(Y$PSWLZuN7)#*W5yomsrtcJSE5ny}>=YH30(sW}+FCIj?R4)g>SIYWWGE`GTl z`4dy=hTg(;F)1O6VooM!DiCOAwDK1se`XT>S^z-0fgKg3cas)7-1}pyew^4DD(tS2 z3VPdz3gZ!;hrTvOuB5LhFmMK9m~uk`@+$%SD{5e)gJc8cted8X8wvWh8btUQoeWvv z;u*Xa23%uw4y&Ah8p9r2-y?}YY1Sp>P`T|zVW=4zt+1xi3Sf3brQA2B#0XIN!qw>- zF0^_Y7g{})%L3LR8XSdza>})Q?kc|tl^9xt0-1ROje979S28gI!j}FSDIhFmDKIyT zeaV_Kj~6q^I`~o_JES%QWg9nh#KPSI4R{l1=&O2;g`?r&H+ac$(XZQG^Ci!YepNFj zQ^|BbF&1F8(!#|42qdAUJ|T@Api?S zf}q3Gss};{BSl4Daag=a9-7N5(S+k1@i9G9GqIU>Cd|Y_y1`6zPCbX*G9v_FQ?r?t zMg^LO(K=4v-LWePYp7(k7)+*dQdOao~FFjiqZV?&(&3%_Wdz zgz+R%ph=;or(jA7)e!%XldV88Nz~L7Z&Z?~Z1_lFa!3++3+X@-r7npq?bKe9KbQ5I zmPjf|R8};QM5r>@qM(CJH5G0uLWF^6R^>R$ZS3G<5ZMat?*%aK1 z>L%J8YA)K&?57fKnuM2;mSCLSr2`WmwgG3q#B8>Xh>GRY#RD2NNuc~0@Cg@j9$69xGr7pz0(+~)26k9R(MbxqOtOQYOSem7$)QO)(CbLddFmlu2*{|q zV7koyc0sNSP4DSlFh>(zuxv@XU~GymOh`E%FQE`{Q+5HGNR2LL=}OCWp*=uD+_YxxlnN(5xHUsYpSWg{WF2 zSc^9EiGHJMBp@<0V#D1irCN=cbMQ>5J|@Pk5qhrnh;Ay6N4Jc%bovdAiW#^T`WTw-`uj=rCqLdO< zcDkZ_=qQldT%|;HMPw$D@eQ$cv4xWDWBQ2C2W_Za0Dzr}h?qS`PV$ix=piw4exMMw zN~sx1-Gw)Y{5TXdS@ab@k~4?aD}KaV`XpTgM7n=`4FhJY_r`N zYE!^+-5245cF_uDL@Q8E2|m#ZxrWcCr{W%hWr&6e-s?f;Zs~Weo`tGsBFLAz5;;%GQ;bW}IH{|% z_qyh(u6b710u{4tLHe{OCGmI>XWe3Fw(T0b5k#9=bSpF(o*;V`1BVB~VZf{ilsj=wKI^D zbJXVD&!(|0r4Slam+H8~%04}rcF}NAtSz8L zPfmeNkWhP}6d5xE@EmCAyc8U{40?#d;xVp=Q|PcXjG-J0^VTd9gnd}GrGOw-t~taO ziliGjcwqk>w+Il(>W^6Y+Rzs^5~phWh^K|c@T8Mg5yI3riCDAQio#ZLb*zZiR6|L5 zG-i$kt-kt^Y?Wf7S3aeSopRAzClGrTKn25#!j~-fxQh(yqBoQo8#+yFvJ+r^ti%vL zTWJI<`x62!5{M3`WMK=QPPtgdc;{hjCI}6f%BpqmToqe&t4oob7D5iy zF*Uzmy|8U+nW(HvYicFIgu@ojr4FehazS#*)t?R&T>1S38%ptj+B@?KR4>=I;c{hR z^A_?Q)|ZV!+W3m-$kNwm1wxZrRzDFetan%_c`~^YQ6=zP5xZV^dE7t3bzHEll@K&2 zx~VKJgdBeBB#zWkIfx(q)Ia>SIf!N7nQG&kthypHu@2S27NEm*Xa;9t zo7PZ+tR?(??B^m0R9Z{g495I@SVeB0)+abrIIbhT-8Y&FCQgk$a<`HgVekOX!$0Oy zXr3fMmp{((H4Id395IyLzM?=D=W9*P`M3<%FXl`RNms;1u9$MEugup z1r-0X1)1byra_ypLLa`AFZfVB;zNB;|MWfm+v;B#B>j`1TbK1o7Ys@$YHB%Y=lhJ8 zcLd!kufu&LxkAQ*k#n8~3wnc3&@&l{hs=$6I`U?1(tso#Rsr@4^23=ZL5-D$rC|U{ z4FlzMtG+U=^+M|@i5ptQLG(fWMxS@*dL2zx3p_G+6`If8rHZj@OZAl$$ZaDj7`G)> zOePmOQ`zpJgbREmTNz0m)2s%~GeZe1u;ZdZV5Tb%z?zp_Y7=bz4Ms9xGnFM73kcAY z8JR>>~~2CFG0 zS(WaPhjb0xBFFQA*8Hk z>id>{+jM?G2=F*4OY$@yR4$eeL1GnYNjkPR^dyM6hHv>alsT90B~0#Jb1j%D z2N)w$#AOU@9ZI3`RU>ZAnfWU7wsEkdLXI$%8L}i3Zdom`83MlM#dscRmNdC|zcty- z;dZs@?^h!KDrFXSloT22tml2OeuZ5J$`vfdtEG*ONtU7HSQeWk-a~gha24BVCuQEp zoAs3?dAJ%|q$sj~u2^eW;-O5sYxI$RE0<7WvDU^UC}Emg?DctJThVC5u$bGbC<$RN zxywVgM*9P!gSX+M6D-VVUu1u4wb)|K)i4M@TfieOKB$pdno9}5tUeU!x6b^U|! z><<)vRL)Z0AB{)LK_d5ZrSGA+DMDMuqRp%08!%ur_uA#CmEQiX&cV-hg@{9kXq_WReq z^P>-AA1eH8F{LzYxmK#9O-*|Fp@!7ak*ex4HK$c2Qmc2ZsEqi;6p4rzh1wCH7MWa03eM#;P2Y?mm;L^v- zgIMaIa7qdR`4WJpCT{g1R|JPpM$nDArxl!~sNBHntV^79GKF`C-9d|6EX`aACnx|4VeZ1@r)K+*#>Bl4oJankU zxH->`cjeXMqGom&e8BMV=MFln*zgIkOhqZ@@Tlt+E&`WfD$g3owy36iZA)FHHHX*M zA~bvJk3d>EUp;1B0^Xgk!BG!X1S6q=3%lo5Ue^%McKx;HF>SG;pugfrRj51YuhSLo z;ZQf{dpJ8f!Ijpv&XtZwll7>#!rj>Vr{rtm=}HYgx(Vqr1TXww%-kH(ODdISNT63L&EHDKkBje?o;h*W@9ci#weNlZ z+i(6ROnTs+!wFit=WIizpG7|Fl|%WgEDs03NMivQ#sd~+)x(hsL0K2wP9^)YKJ_c3 zV0JqySqmDZL)MzjX4GuP&1TX}8_f)Z+MJ({-SIcq-gD=dKB!oB12sy|hcX4rr4_|+ zreIiF5jJ-L5#`c~B5ZgG|>l!M`G*S@W+O{{H{P`tD6;0xS%Gq;rdyjB8Pw(4NhK=;^>rUVUC5tH{4X5~Vl zlg)JtNN~{;B9JjGYq@Vcqzu|rer)LrA%zvO7-9q{Hl@jMg3Fq<5L z!mXalgoxdQFt<8%PrJ`T$iW22V@2K(h%9~Ah)1&!GF$zFk!}`;X~8(haQN56N>X=9 zV-|(#aU^(pE}b=9pO1L*40rewH{h|#FQh#4IFXm#icWK`%S>QRPKUK@FB6Tck|}bk zR-n7Lq9{iEWW_VKNXsZ%zeS}J6hJ4j4slq@mh0F3G=7EBooFLh8&{B0s9JJ&mmlT7 zdeph{lun|bS@Epj&|Mf5a&By0w2uFGzX7PUQXXc3|8**D_HjX#jl8r!mXH4~evc9$ z>!Nm#p`n!ed2Ftf*1NZXXtdIhAFFjUEqTSa8&CuiTEKNh>Jz?9Z~}V@}9`` z#gsGkIm9N-{0Q3f|Hs|?hud|X^_^#*bM6n_bAOyGDT-vp_Bkg`AKe<&4$#PnL-AHo z12fYi+o8iSe>8ob`Gb-32XT3LLMH_UL?RCcWTF(gaX^5BmBb-R>w?lTR4(p=65OdW zI79)LQK$!$)(}A)P?!|v^ZmYS?Y+;r=U&N9T+^|it9|y~Yp);gde{4Vy~|=sYrs}O z0u#jdpg5Zrms~7ieIw>*zUd%GRIcQ%sqHL+s}>TFl=8G51_iD6{+0wMEdmKn$rNMx zB>*GLLjs$+Yv>cJ?bRP_J1OJ1-ao#qg_Ujhqp`^kY|d+Y4|t}2g16Teqn=~^h-t)? zmX?h3|coUTN;3@0t!@sK$YElhpQd; zKE^QdZ?aE;;8P3*Gd2{=E|O2JV@DM!uQZo4G~LH%v#T-`H1zvbXbfGnny&!$sJUB* z1$HAWaCY&P>E%#PnAylN2o`1~V_s{QmUsuX>iE4f0*=rlp#c71GeZI0*wg-BLNb5L zs27HU8Q_YWh{~AG8LH3l7%(=Dlx%eh(9Hg(w5>FZ1dO^{ep-=m-a4U}KwA!6^7GF; zsO=Am2{g^@j9Ct7s9CrDVRhXS9B0OBmLb8V>Ut$a5e!J!u?z{`at2Hk8)Wwuh6GcE zX3(E>j#~XzfU3gFHnAiy#PDaK(SJ%Kl{*Vt(4;0$Rnp`^uw+SCvTjmaCnA$tX!2k0 zwX678e3SZJSrY7nktG2_zWovLC#y;7GMPIm`4)dgOSpnkOREzti2#0Q1nj*zl)`BB zfg-&joPB%MgTE90v^OhjTPW?@!bEV#J)!tGtm}>Her4MDodgIzaM(|k`fv=iSAmCl z-+FjNR9&`g*taLkMx*r2jlNqsrl%&&L@p;qUlUqcHqaK|D0;FLGOhtzIp>@dq{%g!S5p0sQmIzV4gR6FGow`3u$-jHNIf<>RYAbilu-t`U2db^nB@drTOnEFmJ`My;{b!WjSFGt zw+8M?Y{TNBVW@ZJC2b8i^-gfMy`@hH;e|q(B#*!lZAP1J#L%osqo>WlCOL~MdM95R zgcI4o{=TrGYGZF^iw(^^8&zN*7;(&7S8Jn62R>MCI~1wnSYBZ-@Wx|tdT|v3doxGR zj1wp|J8=zcnP{$`*qFxTh^!jMjmE+ZMCdxz&L&B9GHe zGOrrg2%{YcOuTj=fHX4D*q>(sN^%C+k}NYYzf7PKa3?G?DvoTmX!`0+!NQlTS!QaP z#{0j7j!p@eEHku9zZ#aAcNLSC8EoJEFv^6}iBPZ(RK6(x;9X~>lUcJ5cT=5^p>{Vt z{%%T*M@{`ZJ-SMs>!a)X0b|{otV8v#=NHfuDd?9k{KyyOPR#LJpZrOBV&~At2BNnM zVn%eh2$67`B^S9#>p{gz$Ff=4Y(*j%KlP^Ccp7dl>I;vkR#*C#E#)dw9ozTS`PaO2 zl*W}MC^uG+Bw?79MY~^{5q`ZdcUxJY+3d=S#mcg4c}4%VR%SaZ^S#BDEh}@~mG(-p zvP67PQU10}b6bQY%RnV*%a!i^M|!(UZd?U#c-w)|(%_KegmuemLJDCRAm~ zLpheBZ%c0J*Q?TVb?IJydx^JUMrrhNF~9xkALFf!CJlqtQhxgx-iFPip{Fh9x1ZOy z%1hX^N3G81Akp6?04y0e|IG^fz>RT3ua5+cr7FOQ; zx9?t_OW7!3;+p|n1ja0ec@PZQ9MHetSta`Safzl3<>f9_>cBd=aF|ZggSqBmOIk(s zP*i80Oft6hL`ltb%z2t@vz*BAuw6xGs=&;4AjNV=8_XKDs+;qN0y)N7mp+@?-l!S% zX!{}2q^gr5e)ETV!T3DvO;9o;RzM?QL7b<%=aIN!BXAm@D^tcT5z5qE46+%-)oW%g zzh>I%*Zm`f^E)KQ{BroBexc!u`UPZym&zCQa*XZ4#@HTw3CH#T!s;FM3TiFSVgO>3 zLA@l6AwdKKkvBraAeJU?;Ebh6DISnK9aVG{3^tYYw=c`VQQu$F#_xaW5a~1RqFv{` zL%2YPsrOV%MeAe7N;|1#kH#LJ<_5)B_CR3FuPx>8W2`m4cgkgUCj{Y`?tPU#yUe@j zlc81ZmdF43S^4gc*+Aa6S6(uebh+(~@Ip)BR=&bME(IzaA+F`8R7-cf7AE~_wTOjo zQpQ$ulg%WPNyLg#HUx2L-p;)Dp<*4=5#F^F`qb$fm$&Qa#Imj2ZsNzHd_iH&CL}>M zaZ~~#15GR;FndxAP(8xf8nctVDSfq`^}B}m6=P~D+{Av&UNO^>3lk@1M_$Y|{I-Ac z$!1cT6cu>>2mrScw&SQkX7ZCi%p+?mZPY_RTa>@0QhkZZ1;K4VvM7IFk1RPeVZc&> zk+qZ@XEgm*@l|AITzuxLuUPL-Cg(k`Y;E#dY872#8fIta__sZe31|`n?p&HrJG`F%-H&|u_y6!S zkNuH@98#jAk5nii3jxATQT~!1*;bJg9W@Yz*hIOmit;yADn;I=97q3wN1=d$nSoBv zRgVfH8jMbVUOfWeg-+x+nnb4`(ou8v8sD0ON|Vzl4?cDn1zB5@%hNV3=u50^mL;xC zNZvrs5V#3HhtSAdbFo3z+V;1UAA>d9X?jX|ZPJ&B*8U&dPeMZ)**%)2U~-)PfHxr9 z1F7cJHMQeSLo(&!T~d?Z#_vw~hHsNoC%4LxYqTmr21$fyb2j4sZ+>^vlM0>daOOKt zm59ID@Mvy->u!B9n0v=)<~#loBtvx*<(5oq(@DAsl-# zehH=hUs~vC61WhNXWx*PF{D;m)zz94+A>_Z7?+M*%3#W?mh?a@z zX%%Pvj7p_w^oX;To$mKP`Ci4WV_wvnm=b6G%k%Ap@VK6@Jg!76)N()$UKSQ&v&)`q zu{uhHhrGEQnz0l_?GqD^Lyg@DSSivGBDnbmkOE#JfT&`vu~A$2bs?fLO#&tZ$OdtC>z!0HW>)bI~bQV(l1!@*n!k&)B zN95MR;;k|El!6D35@jQd^y>!cVB0;1hO4RQD^46ehD9mYzm2xNhv%bo0Q!O{7>VsI?;n!&N9!MTSi z#i`iT+DW;G$riduja;02cs6|Zvk~;jBJb9@hwb;&m!Sy13!x@*4|gm9Y2bSz*5cM7 zAvE3D#?!JwTpCFZ9dvR0_3$s4f0_5F18MDUSh|;(Qs$oq+q8n7h(`GO> zsD|W;DO3YYQ7UG6lfm$>Gu6ncm~$*o-tItraaj4m!-~M%BF(%9Pep2_!5rOm1X^`e_jxs5gPWX$jS- zmwA0_jd-}hz|RKa)p1NlJceMz`^LsXtDT;aA`HA^$1plfwJbL%ZGB9kP8)>yT3529 zHEpZj789Ad!Ing#_eeEjG&j+5O-`znSn05%On?38A3P zv^s3KJ3Gs}+5BHev}{r=0D}MqylzY^fZt7u1v5mX@bHt80;GE-+2J?yJ+eat4VSf` z&_*iIh#P`J1Pzz$TP?q+PZhU{pnIKzh9~9ebx{DU$5ef9+_RHhV^syop;z4}_g{5y&(Dv6RMngWsx3yY4lHT; z2>73ozt-Cl>q#xMH&OWTfBy8xKh#aOoT7YG#Y0&iRITOSxce7XV&WJpcjpt$?xII@U-H5U43KHa&OA#^fq+Db&V5Vt+yM7NT1VNg;&c_0^cmkKh+ak zC&U*M>SgbzhjQ$nQDRz%^vj{U{9HqK`8jCtOJ!Alyvruk8gD#Nwple!rLw6t9seZb zQEh61RmqHH0xH)5@>4uY_SY%r;2=6~yu)=c=~d4LT-cEt294C9&*)$pQ_omQFLf8h zlv5jyLC}2A6CJ$c-HtD?S23=DmF&_`194p~%3B4+7nQ`v9cy&dxyF;>JWd13Ad7~_ z<}De?$4!Y-%dviv|FHLSEb=kzVUZKkfbp<36B~+8p7Nry1u&To-=mf2jS+}?=(XBV zTz(*z1F+(9U;3H+9Za+0R$u%#ANzUK+5!fK7AMB{rFT5w~IDR@>_lw;8cmZ{6<{OA~|1gVtc0K#^9MY^B8@ zQ?J-WPMl_kW9CAcjPyvzq_xeyUfYsJC8KI2vfhuJ79a#_8PQX^8Qb8sEutM+p@s#& z?7fqS%_%x)sS&VC58Lbwa6WV_UbnPb#K!bAheTZ^ zV?e0$6^8#A7=Fk2|DXUVTVH|b+CpxfL4xgM`L!+iwfu8Qjb_#j>8xVq$A6f&j$vys z`YKH6e?P)o1;mJ^=9#Xf!qa+d$*x}6WhE7Uq?T3_qyIOQ4-pJPm21nfG6Ny=71cO# z2&kv~KW{YfS@}e;Hh%raO)in$T8cQuhxEi~xMWZ3n-VBtgNwP#;O=Ess&DUC%xTFqWvn;Vm z>2}BxKeDBm-8fhyFMwvqhGjoVc(U{%NFq;gqdZ*NvW0o||HY$G4B*zu6VrzM^U=Sh zWV61M!j*5gW9}>1l|>MPB&0$6mewm`i~Sri_vI@U)8LH;6h%g)z*>9fzA#@iRXp&P zMsLaJAL_r`Vr0aaD9G1xTEjfp2=%bR&-pPXznj1McitQ^`5kC@XA*DjZJ!dVmQF&_nfCVgp#!_F`d zze-8Q$_0D?d4?!kEZ$z&MSax)ZL&7%93u}AdDDLnj-U#Abf^NzQiz!ukVlCo3f-Zf zHAT}2<@ zs){A1r2^I=kt_;TZz<-zM6(GSvph?NgG!7LfezB4Q%<#N7AX@lY-pF1c4*Vf5h?ul zr94|h>;L_i&H(mA(Jp?Vs1*7^J|DYy1Sh2eVD`7)yqhGd5sO%bsA2-C&JBLbjzdib z+nlW5bz$hgYY!^~dIZ-HYs;jufl(s$HJ)H{sep1<6mAf)5tW z&D1j#o$lJ--(jBh^ zf>)CKH>Fv#agk~52i!To_TJHw=7(rVDs^N~3^!OD!&1;Gtg~G{4j4$5-4^nTtnqBE zeLqL?Jm$DUP~k2k>={;Q8r+)pu>*Aju&U7;o?(nmZl5Rk?M5+p=-$@%mw)6W;Z5+D zkHXPVmLejRZn=`>{hZEaw{be}>pdMkQ6=A_`aHQECG+FS+v;T5JYhy=B^StqNK^&f zv2o-O=09X64w+lOy)<>|5?dr^)B1U<1%rz`0WrRNv_&y7?O_ivn{mFyBO^!L-qt_N zuI)v-xr4t~PF*{(k`na`H#Or;Sx6#JwsV$h4GnvXL#ENIXpV4BsI%WO^gizf#CwD> zQR&&$HTC0vk_Zxc*&%Gn6Al9VpgcaKO|7OI$WGE*ydk~EAK&Hndd;XdZ0E`jR*?3P zU0`qP&b*TRMe4(85MfJNNsn`cod9;GtzeuzV9{_v*V8e#Ov{4y^t(kSOIw{yF7Kdo z07&#k|9s71m-gO+PlTu4!RPOA$_F9sdh&)^^vv7R3FdSX>I*VALHr-!|scErB_{B^|| zVnuqT?TJZX#6T{hB@@aU2nZ5OLjsJ3bHI=HYl@-7G~8~rv^ixmZH%p{o~SCL%W!Ll zFA+AFwd0-r#c+q}8N`IMlYZ3)q$uoC$z$kKdZYw0^9PbO+q9^>cSVBy}NO-Nq% zw-`9l>+r06{xp4d-~p1S%cb-Dp30_f%?`- zP~Vn8ed~(?wKF>i)F~IiG*Fwro}|o{NP2!Up}N9lJU7hR!xlymH7M3DSpXI46Vt(T z!7X+i%!wJ`8f0iGzbKZ-5nDP6)YF!qICFyVpfQ0g$si>X^uc;2Td2Wg=T)4)+BWqo z4rf}GiXhhD&_7|G&OU#In1rPGz?|8Xu#oi(-lX6lC>kju*2E9hSM7p741VkQyekDW zzg6gG4%$T7NT8r-769OsB5B}NRth6J?xRd_30@Lz$ZMpSVAC69h2@@5oHdsCuqKIA z6U8Co9V5bzrFNm%*Evf1_ENoNZB{fd2^^SW-|-{P-**Y16tb43*_ z=S4Y~dDGI)0g`8cMvOiu4uD5j=gj~CWKfzyHWnk`RmAooE|A8MC ze=|6*QcRTi>b3Q>6iY$$6+R5L6s%XAe{8T-4gSSn{^iOKA30*k3*mvY5gt3$UxH|g zANw!564G_0h~&tiFAolnW9Su-_=5UWsRv0rXr(1#krowTX^H^X${GXkoHN{n<~#u2Z*8Z#?d`72sbF+LN6%<2^lajUY<4YnN_tTNqS z(Oi{5Y^F>lXy5|>nz^2-hA8BLtZ0Y?B|oW3sr;<2%$x}n#DXFI3LneFCwg5CQMNu4 zCB9#SoGH@T1jhXc3d6*Dvfa7%SPrymj6YFK#uZ@Mp2OsdM~;KKWr`@@Ee<6wYYOvw zAm0<_=YS!O2EU&o-k4SG!us4{9y#D5@4}LyJ)IT~GD^^#lAiwM2z&ZKBkbt|FJaiz zd*q^T-x2@IlG4g19z5~(uiMh|qQY=eP!c$b#iovxvW_I$flh*n1$RkKxF4#^2z zx2h)_gbmxyoi}K~eKyGqEa|#x-EMRxVFXc`Rgsp7ckQsA{wz!TjvO>JhHVkS2An}b zBLOw652Fh+phM0G4-+d*p>N|KI(d%cy=XRiGi8@_DpgR&AaCsN_5MryrNlijZdwQt z*kvQO9e-c^Q7EQfa-~GR6_kOd}ZU_15 z$F`=5z{Yylza?l#2S&ECZ~rHw?jwWl{w?3No6auJr#u|7geEORiU|Dh|12_d;eSCDokmkf zc#y_tJ8go)b84zt?s#1edQjE(1(j>U>*2Z_i>WI2*krqBs&c&{OAeH|iOKE#Z;>m2 z8C7gy%v}(zK%y3f5u>Gy{W=@NjGL#5w;DN_G3}r5Yr=I7l_!3YvHhY#z;HG2A;;u^ zq=k`GrTQQ3y1LZ%-(WjEPL0%dRT~u@rXpHAF;=|ODthlFW(6FCBDkwUaAUfU>`W^r zjtk{YAtOE5sD)UgX#Q0y_`i>{6%lTK_n(Yr9$`x@s0yCW;|ZUcRfZRZ^5IN7fT5>= zoKji*v=3W60rXRu{=bMlYx?=I!W(b&^P@>Fk8Ye-gG<9A?#=ezfsb&sek$4k<^NFg_936(s)-Z1tYP=TajrxC9Xd;)e?oX0sB!Ah_*gt<&SfUD+}mIDi%b<$FN1wXQr> zDYC$eXW8%!3~7Y+q$G&~0L|A+lClvIcoSdHL7IliOzA{>N+${sKYD=TrykJq zYMNJ#fewD6+uL8&yl!OITInwq)FJvZC;}V4mGGP&)XrO0A5XP4R~?rxPx2ct?Ej{J zpHez6*6sjbF|NmtUwT4V$-ZPdcfRO_#2~d*)D;U}TefLH$VDoM%vFsyA(Qa3`Ao8w zKCq-r`Bv|%%EQ6NWYHKY^@X=7&oDw$nb@X`ae~duFH0VdmqWAt`G#iu^8iNDyhuoB z6xf9nH;uVQvo@CuLRz8`&Cc9xu9#@iI8x)~7~8Km#`fzk;n?1bBaU@4{yzg>xMz8L zw+cv)0Cjd)7RYokyI(#VA*juLgVG#W7o2ILx7W)zuBDKq^eTMy8NJ;wGX2l=HiEmw zqfeYkw@pR4+Jg8)dg}oBVo)`t*d2G{ovKQiI#J)eTp88F`eJT8j57xu=bl=h_~=!1 zw-;+MfY>0UK!XtVY%z!!1BN;$|5c~_-CuGKz4=DH78EY&S%IQvok;-2QLGuupLN%L zCbg{k%v4C9LH=H*j7jZZQd%=JC=iC8;7$K578kH z`ebFicW?L%_g@~idcu?11?67w1W@HN8t7r1Qs*?+utFvnN9w-za~hv|rolaji|@%t z(PVyEnJ~Zz=Ie`X((`uW2)gq5%G*eP*Z6oJxyD`JZSg_>4tZr6%4@4Y5oJqajqvP9 zC-ia_Uqp%=ksS-?AYY-0dfA1V@^bHG(c$GbS*in_jz2%!#qL4e%jV5?|j00^~$ z@uy?#Bu@(|5IPlJ(K5|p;dUH|Pc)~noqvu4X{+}>JW(+qe(o5Mwk(2_=vWeLfR|*LvUMy`nyVwbSfWs&5Mc4vh=zyRTVIcDSm&Lt3yx$5%^US+8 z;wtK|P5+dYzEk2@0q=uUFx_7PU!47=qa%Ri804$lSno8+N|SKrNF=(xB_NaBtAeSb z54wc(I4*+{M>_H~u-h5mFuQPAMUuk72$LZF+dd=*aosV*isri?TlbC($LETGEvtjV zteuSi_V#$~q$k36)=l*u63G)*Z+@Z`a}Hu+>UeD{Mswp8qtl23gqyDzK48TN8#wh` zQE|l(ywh2Nl4IF-h$~Mqdd{ua=V)b5vrF}|b~peic) zChGX+T!pll0RLaIp;3mIL1CAn+ks#8zfTS$Qtj9q)saK)FsLHWJ&rf{rM*)o59M$C zG%RsQ^%}_E>uz6ou8edYnCL!0s*g{Jqi6e_JOm3af+2I z&pn*)9^>xe>h2k4D;2xIPoJd#8RjQR^fk5T`N^^A`uP+;`x%Mh4QWcx^0-s}Ob5~z z<<9URe(G%Xa~kuGeQ*b^_yr%<6~Ev~UGeJUFC_7j{e?bz`5&VFp(_ty&49h)yTx!jTA*+_Jn0apXK< zuF$ATZJL27mVZK}ds?m6F_Aa}50(Fk`?XeUpYQvJ%HM0=V=esc=KcRw-IUNzHNas4 zxH~apm4D7Vv@>DIZ270$q*k=KyF3f)Nc5srp5ey4f6t&bkS&9ttt5FMi45i_I9kx9 zJ6PDQ36M?;V^$6D<(7_n;as8z0jkekpX;CGCtSUd5UO9t(d3RIa#G-gSI8S$_jBvg zE#Xyp^4(`q83Dmf{a2)Kb9GVRqja+5Ab4U(Qvnc|zH1$q51EsXQof-hJd2+L#&x_H zfdi-2`YZOe-{JHw4#lKj>eF7j(tocz{B}H=ip#}z)mK_6e$4m>O{mgnC?>0gr9@Bi zco-Y~CSLe;#5&ZYen)7zr>d`kivv&l8%L>kG&`6l!NTesJEVq$qY3?bG#DNHYd~mk>vrLwz0oa2QYISW z^D$Z_ahmzTpmj^@^|u!{33_XtZ?z9Qj_qI+cd)j&e2Y$UQJNn3*ROQi9^jr4x!(AO z99O#fNF)pUj6hVaP(s83m+rm}(L1{9bCFTtEWaV;Ixepz^}?nB24#?Ozo-zWw9T2d z3;JEv=Mf3#k~uls^3+*zi)>@%uv+o!^wc>M!ZT8oTY%Xu#Z9*ZGg(Uo3iqxkd&0NB zChj1B780oh)dW77YPsK8-xIe1)l*627kGqzVd*m2Ee7oFW8^l@yv!rFFQ*%MEQD7? zPKfaCX`d?qIg)@SoXZXFqu}0gnL!b{lx&nyT;sUhaK}A7m?AdZCYoR|oqwCnAg1%= zQdOxKW8H*U;)UuRBFWTj%fk7DIKnF50i zMJMsbab-ijF4Sv@_1E0%L7%x?HNq=B%N8x9ZUFW=i&9^6#3(QQ96i4|x=|kgd2UW3`SpK6?a|XU zprjZ#n|v8bt%<-{`X3hpo$T0=x6&)0d6duh@d#zl#r_a$l z&D8Q>)xy)sS&AH+IW$_~dXl2Hwg}_lnl{ZSxU>4Gs6RR^k}o@s6hI2wG_z6RV`GI| zgOw?!nL8%M&&}@#%UD`wN8cL8n`MzWhHzR#NW5j)c8kS)H&|ZloSb#IET5j49e$Il zczkyFxAf-h?C`sEe{Od8&AL7{JG?{B&(9A3=KvA^GG>f7%j|HP8GTzAZvgO&;4{31 z_YcR!;~BjyDGbj#>}(DlR?*>9-d z^cDjS?RsySEjWb^dSkpZ8uhu^%s<^7)z)}IS9o%!@q}*Z+xm${dJ5Pao8dVKg0itJ z>kU!J%jMZnk;v~dUyI56=$wRz)yZM7w&AHn4n4>jPRRkIZHzSF3dW z(;i#&`0!EJwWob*cF3q*_Z)_azV>14RTmFnji5Ws>+58gqsYlR1{n$wMS1+Q+CM1R zED!TzM*li(iPGR-7lYp`XQwN+ohwSN^cG*$qkfP4gqva`A$2}fc%;X)TtKp7v@i7` zcJ0wv+oz?dEF1dfs2R)38|W|?H2k|deN-)e2Bhv&m*`q-43x<~8kq|u;zJ&2 zU({CiMYR;V%(88Kf4B+h*6_71;Ye>IA%NDC)UYsdpKM_Mi+ z(ZCj58^hK%sIs6Z{gPb?2(2iw_MSH^y&-@jiwaWk zy`$F(awSI~%S_uuBM|S?9zJURUO)=Ozi0S*x&@WGz%oJ!YM<9~lB?kL2}!>-qs`HM z{Ohj|jFfPn8+%J?Obuy}l%k=37=|`Y7Q85y&#&*c*a!dkm(T^JFjYmv2=kcczvFN*KaTdoTm5J ztHH7gh9lt63E z1QdmC6k^x!WdN8de{w+_b*B8+y{vtbsQ;GMuk>y&jc9AGNVb)+2y_A-y8nL0{fdyog2nM&azpTgxNBfsS32U0Vp;g6?;jHCH(1yTX&zxYuYtHxF!#Hf)DX9Cbmv z$uo#fd9VROZCF{R;=a(~MxldLlpFaHZc5hGMSf*ws!A5$)T5^`lT;aU;;F)%w1zqr z1W>!FRBK{Z0J6Z(+n5resyONTr=D3)NMnLLVKVX0o31EaY^J;b2+5++0aP@*w{;1+3g&6jEHv}P~zNaB5w0(|84F5cU*Cg`d zTy7oLpL!$;%HvPWgJ5!su%~CHJic&fIOO_x@6d2J*I(g!1K0CQI8n=)dxrz*m-h~D z;@L&yeSTiY&r6GkhOgoJB*pir@(mbo&5Xr@!(}udbZtJd;FXF6FG?I+H4C06K8o)8 z9jMnIE{Z)b#OTj5)I7*1G#W;A)`Jxbjz-#<1uJk-EO;A4Z&Az$q-lJACIhK!Ag#K@ z-qy$G(i#{yj~#yxWG&m7J~)%*%|0<<9$|7tii#&^6$+Q?KUA0 z>gxGN&PMD3O8_F~n6Nr^v$r8n-_zf$raxYd0M{R{M0}o*E_RoTr8}!D&9SFT!1kX0 zRm}oBeLKaBls?@-M*)h&;85o1E@4Dp1kE{jL2A z`&<3r2NEc4a|eS;dKP(bW^Qyh6JG67J~+5ryOcf8A~fiGJ;otO3rV$88H`#J2e?Zx ze|q`Q;4Ya3SdILgA1r#O@{IgDPc5sr>dXFOc(-_%ow=fV<+)`GU?~Ck+MrnK*Oa$0 ziQA;eFk$8C#(Fp%>xdEUZGCKBr-7KSZ^I`H>=#6*6pgz;hat{H*r@B7IBS>k;@_** z=_%J6RO-=r1V@H^YJRu_2ncr&nl3LBjEimd64&x1#din|3L*$-{$zB8oo6T?^T0;Z z@^F{11X)SUT5E=_>f^Krkkg-0Kd4MUNl&}<&`fL>$bkg4O#s{x1m#3(SuLH2R_QFM zOK3HD#w)>To9O*ac`SD}k@{mb9oZ(`imxB23B4Wxz8wNz0r+-kEQCx8eD(^n{I}C3 zq|NWFdUe!I1o-X`B7c}i0P!d>{{j@LR0IVzb~w6i!v9VI%M^YI%s9v@?vH~gh>`yd zzAfS$U@HP_MIz4L7m2p(%qtvLA{>P@JM&7sD+pc;C|*%kqQrZ?JSSY<+q&ZQC9<5W zPuW-8K+3+deK3bIji%!=%xahYsFoEjH>$i`Qw5LOCHA)dI4N7p@lEQBD0RE0)LR9$ zvr>t@>H-xJKIVf`&-+_oAX}w)`e19R|tmvQqzk`}TpON^~^VgXVmS!$~QTvrAZs>;9}D#NP7h*X{Q z>Z?>|v9r7Y%0i3l7R&Q~a;ove6LlH&^BDa+BM71xJO>=g$4;Mx+Fs%( z`&Zk~>k%==kBREySALW$zfLVEzeuEh!Ky^Ca99`kfspWwszxhM`H#5dN%A&^> zaVz~wp(U34nhGCZGl7rRF#gJo5G2@egk6nr2vOR~$_FAK1jgIpn+4xXi^DtNy9cH0 zf@IGwf|scDflX~fg?M;uLDYqfaJ|7zgJD{xHwi3StChG^FCb7pEm;C)R)@tt69uokW(_lgJ27>OUc8xo_)9W9#Pq(pszyJKNa9Z#iWw;)-c2FE9I4sXIM`%fo{R zF=oIAeV|OiI1x+k)Ui^gVIrAnxIr={vx$B@qk(WL-UVIBlIDR?llzUsnUJE-=vCp( z=ASlsgsH>($GTKV3XlMR-neAkI;ftVUmD&C*%U`MI$(ZDG#vONun;8{bj{cW=@#He zc?^4G{hy1W%p*`Rl6W;YxKqOvsUajoylw2cj13HZo4zbWV`<~L<-uZ5uS?4j(Ze}s zMLOrqV`1^z5ro&DSO?BIL+s%H`NlbCxar>tDJJdMhd%w+y?V||4lkmlO@ zmOBq)lcixoH*h=*nfI(1xXx}>Wzqwv(l!jfwkSk@%_hw*5ruLSw~Jc(izd`6%K$g_o21ET5n3723b&naq5tD~ zneoCJ>=^J677V;4?*K|$fI)#J8Cqi)n}TqgC(4xVG&q%w86TSqW5(%>KGw?7!?EC4 zNLXjF8UnTHrYS2S&ia@(Yl80{)Ir zeD6~GI%Ys1jK@e<)*kM#<*Gr}L@!#2tYM5=W{uFlr?Bn~+Oh-eX+MK{uImLHXu3YV ztT7wvt(v%{)QGVPpo@lf%lnS(kQhkqn!{#jc)ttNXsj(96S%i(6YJb9t=8?u5lMQd z0JMyAEI3x`DS=qHf%h+bG(|S9{VR)9)VVi|tuVJ+sN(hlk*W)LFmfa8Li-5TlHfCk zMj#T$5k)NX{UE@aMs-j#<^mW(^quU8nNCA6fG&!ISHa2DHBc9Lq4}zFQaHkHC_F(0 zo*T0p&Wdu_ZYW|ZM-vJq5lM^u%KCWN7Z<;&vKyXoL!nYWG^fVOV>|-9C+0>gQYj0R zYx)&}I}&W}2|eR^-&lxhD@3)1DH{NM2O7;LyR7?kO@R_pV!L&*47(di)KXd9Bo!t96P#_H7ydaJrzLnfq( zD>yXsj9!_oFkT)U4>wGHg+AQd`tmHTU(Mv_DVj9-U3N3I$?tM%3X|WR%CAP{e>{tn z<#dGUS&>bCE|F&bA{C9B{4UKVlb`1d;qBt==q@CchRN@)Wb$*6lTn1G05Yl*`-U;6 zfIw^Q6AMF&2bj~5Kg@8Y*cF4VwaM@Cp41KXWq+9b?$l!OVsA)@a=j+Y!&(rRn8Q%= zK~VGmJeRDdGIUDKWh=!{t7#}n3wAKG)_U*4zSa|fNqnC^m}y;N{#SyXU&0n87Ab`# zv{AOoINUN<4YE{d5_M=NS(bX}UPfF?Jpx6-l%%i3!V=m|fQQP|M}!XgMjl!P6lzI8$&FJfg5z1iiBcbz6oRB- z7o?B$Mkr{Y`)6lGFmMnF7g1qYg2IU)v4*6SEv7OHiaitF^4FLdBx-M32xzlWA;I8W znxiLm#YFtLuHrklGktJ?N&VxS1~sF`G-gJPbh$8CWbX+ue=0dN&WU1hk3&*(Aau%% z8Z@dIH4|q>4J=!OCHSLvN$KDaUS#tWH%YP=h8 zq}gq_EzN{y${$)$X!%TuIMM9f89cs+S1@%FI>F49e}RNH*DP=tN#iSsVhW@RhpdqU zm+d^xbjt_lOv08R6*Aamp*M*>?GqUFojKRNTM7R(^tmX%b%JS{4EmQ+azKYAieeLaB z&=C4j_aYZE)6MUHRZs3}nN$=p=Aj4Mz`GY1pj#*hBYk3ay?@y!J%=QDWB;ESXVGgE z4`ctbCYz7#Usk}F!2sw!`~i41WwP~GwPvQ z_R0%Hp4~XwMdR*g4=Gm%fIF_Mx3~377kEagU9#oY?y+yBTA6dQ0m+ zbcqq@4yp?Fv@dptr0v7-)CC`2O&Q(`$gg&QdjkHeHDgxUUac83v3#|(X^ajnzC!!v z<5CCxGJ^ry1YkKQboyVr&{BgEQ*rBgfUrv#z~d)$C<#&z9ynXX z?-=Z2eb`^L3kht!zet|F#lO{~Zk+kO@{F57I;F11JBHP19x>1}9d^e^bWa_m!0Frv za>~;O^H&~!tYgj!F%=|zs0?EIV zozea#H7sPClOP(1z;KNi+jIrfj3A)j)(}J`JNAVCZRr&lHo<;vPN74;bN|^moTqHP ziC!Tjrq>eF+7qwY_9m}|^S6|&ivSS=y*K2VhzJ9Ls)(>&d5jQacv)&^ZO}ik1OO9o zkop;|mVK;@xq4;Lb*bLH@=?OVdgZeYa~IF2>>6Vv@wLOkrhO>kdnp%#9|`drRY;5h z_S8Gq|9U~}UI)*7%Q9Sv@?ns=mI}?IYZiz2d?_w9%Y4%A7t#~I0VcdJQd~UE5zt$!%cn0hx z9CB4b3?U#OEoTz=U?PDh)B{Pjq3v)+s7VW@y*9MQ0+Gj8PFg2kYwrV$VNO@iRL-2s z5I8CHz=~!R_uAsVu(10eS`k*OK2|H(QrPCihsMypsL=kF)`P+;8XLo$hdfP$19*B+ z?b(?MPzJjUlqT~uSO&Y&R$}v7rbN(6yjBv$8wIDMX@wZ1hSSWM>a`XEYCnFc15t|I(e6)XKR zQwB_7r90`oSgBl}ttsqOY*`MA%Y0kjw64%~H1pOYFnvwpt}vf~B^_vwP*G#`l-<*jQflzHkYA&F#!m{Y`3E zEOowSsb;0DPdecBI;Sfvbt#ArK?@js^*uwMV;%#haMT$NU$lKEnRvElN*|^f{4yZ; z*0Mfgm|5kaLJPPwOg!tWnj5c5GX30mMPlGsdA8xWglTxA7X!!965$2g5~Fsk*DNc< zlV&dL#1Fwt=O?%@(!{1*nDJ=iXC~>nlWTG%O{-Bv8=ezfyoHx#f<0Rt5UrmdXV0Dj z*z z@mbONi<|W_L<^@MxMo2C@uWX2z$*l}jl>1RAlQe|(`X8M+8iU2DN2ifQa>dw*pm}I zfMW7gI>GTS$f1CA+G}4@V40`1J zJcftlm=+#E(n4mwEH7oDW8GzFJzCfTUQtBFpSrn2}kX4&BJn7~q7Hee!m>Flt& z|3Ec3{PtwLEKem&WWJEWFmct`q-b2v%#y>AwT> zVH_T!9+$Gdz zV{p@r*IOgIQF7xM>3DFgjT>)U?!r4p2M5`WC+S?Ed8V7(ctj%EjfbwVCc7+dypXo+ z#tUg{Zm{j%kbn?sumYi^jESlV3D=|o)pL+$;2K0!*?VjlneTs>zRI?&S=}Hk-=HhP zaxJ1ZzPP#m!oiByETSUW_Z9Zw1kPGbmFS&T@>*ro%j&?SJc-n3$rUnfdD8npTN(_q zNJEswRIR5r0R$k4u1V%JP!;6WYh?Sp#AzsIW1?cWCS6AIaASsK9A{?DoSZNrYD*L2 zZX;OB*JXPo5+A~);96dcpOs_`7~}{%Em8J{4MbZ;X1>m_EZQRCPBYCd{kJFD5>&i_ zXlq063$oG$9b=xrjc3EYna!-2e!Z~~_{)s<--PT7XvSn;5*Spn?@>{+kbUplO!i&f zz+5LY-Zh!)#H19g2fCrOaZb_!BIC6KA=$$N+MAl@Ogavm9EXMGok=b^tU)v-Vv~ex z5VYkhcd8Lv;h?AC-%jgY&MKSw#zbN=%QA+BNQ^ivb068WTKI;Q(k5i#_Fo}cxZ7KN zgUF2T(5my{O(P7}=Gi&W&{ltzG`Uup82f8Yit6cqUfMI=t!;X)4e_9S znkE}=F;-Nv$vx#WFK)76D#n`4X-ec#SC?ba7!%!uMS6(LNO`&e&(nsd1Yy(-onk01 z+5}zWtmbAlz<$Mog?ahiYT}vXhYN@!-!@;7H>mNsLRRl~X#X~1jfPOC;Z1`T_T=vF z2~A>eac{Juh|aC4q+I+e)Zz;P4$0z`jp5eS%Q}Hl+Zg2e2GVdWX}M(FF&-!EXY`*c zMmJj^zOL0OTD`%|69Vy0omnZ!B!T!~h4wdRX>@pJM@^q|)3rcM{!!DA!JP!2a)>RB zeL`7nEDonJE z-K0>ro zXE@Ypus2lAS5h@Z<;65_1zJn88&Y*F!Z$6grsj9+O7nx%{0$oY_PY6>Nuy^*Urh7x z^gQ}~Y9Tjo9B1^FnQ8vI)ckgBo>zuAH&*_VfZy$}=`G4io~JQCGiGlsS`d|-y8Kv%Xo9XQ-@117w0QT?oF;an8T@XZ)%MQ(lQ%`_1+ij)hfh5`OxLB09o}fr; z(>x+0Zb(1#IBA$nxLZD9>^jvGdAA1#m{qnt7yl>>-Zyyi<_-*o2L=$c^mM4F^4&JrIkZ=I!rf$_M1;%44x+7&$)tNq+Pj2^ zj_@6>eq(fG;|q%g-1H>TL5B%bQ5@w7U9U%r(G_imWOtBnHYe*!is-LMyV*nbaa~_S zE>vCdkzLl64B&Pup%q`!Jr09sb;Y1?QCFy;JWX=`SsfQy&OtL!S%)~Ae}LUMtjxj9 zQu)Y4dRwe#LO~SsfPErI3JxZs3TZh-I(Y9say3D!GNzz_VfK_hSw1%zV?$^V3$GDl z^SB>0Vr-uDgGP)EF-UyUh_QLv4{og~M#R|Ig$P)zEav!-Y-a&1RvH0|;weidz02;W zlailA$1o%+H^G?uNpVUkVun>P9x=l^Ma(eXS8uL@r-Igsl>@J-0iLLZ$4L$F!55_g zqGu)zP`UMTG|2JL0F}ayc|KNYfY&93DQSR_&JHc7)&TDl@lYp4ORNDlw8l*}Kr3O) zos_SY(EL`WXnqJU(=@+1s0<`O$*Rhomo>k4CUSOIy-J$jE3BuDYk#TfDSF@aLeVQE zK+9DsZCt3~q4vGX)d?lO{~EMDi=l8~3uu#CpEkWVw7wPMGJbkY>(hO3r)$>wq={MU zn_HGgVuoN2D}935n3kr=4&6-I`ZibkaCp`tbfxqmSl2S)#!8=3NM~Rk6fi^QyYmI9 ze5+<(O}#FN$#j*^(s))pCsaPgecUiuW$)yUQ2D&Gtf$nowaTZ&Zz^P!53r%~3B{we zDo{iUv#3L<6o7e%-&5lYuCM7DpO9W2kXMAlx3W&*L)slv_*e+W_LZ!4C52BZ1-t!P z;rs4r-1?q`BGL&WFjwjxj~eP;y@ZtTZ(QAbi?lt4yw>^7>B=5fM-Zr?M1-8I{3{K0 z=iO)Js9TeKJ`H+O_K;I^z>mTtC>LU`_=VkPQ`CoLwT<{c&=ujsvJk?@b~!kAcuE=) z@meM01FPobU9EY?jYacg+LlG?hPGvGhURx@^tHB?Row|dS>m>y2wkuO)X=sDo9V@y zfy#kQ(bun6gIP0NNT9kYfyxo!^wm2or)pXP`g)NwDYhCR0e^!VcB5g}nwGYDOZrC! z*;v!ERIhotil#N>$f)g2O>3Hpgrt%c2(Tb45MKC@Ss3yXutkX(>=-qDH{&|e*epy^ zX9+73x;!9+vRb`qDmN2a;HEXU2fHyOk&be3{m>kLGZkkcRGcFD<+Xy=V~+X^JsX5@ z&-C|`rZYgY#tN`1u{bmvG@VMbK^P`VL>gM8eD5!OL$W+3H<`S#Cph0 zjpH7VXbqp!syAK)RPwCtNOXOwFbgl=a`5;-z5G@8q7B98r{$}x`0#6 zzm7s5N^;ohpbhc?h@953S3@zq6elvMgV2X`g#NH>b&?$Vwp-X1N^jOpt zC-M??RdjOPm7=a1`@9Iom&X;(xvfkLH$`1_C2I39cxQ^b5{$}@U9=6+e_9(;qprqU z5V+^Y>zB8asH<*lEUV+yJw*t^_u{idd9;q>s4GLC4RT$^Zn-VMR*8Gg*dkNuX4}RX ze28z-?HilZHmdPz&I-r5j|Z$frOX!19WgiqU5UZ5P)3+|Uz_ul=D3QQNpM=TA<+6q zBM4u0Q5bPFOVH~==BpiTbrg_$00DOoEEduO^KN>uAfNwu98z*wzy_T;D&+V^FEAWk ztrx&G$0AvfCKgFwNfC4}Y<8j-mJb{*?;WNAxtmppFFb>;>4f;zX8Y=}@el|^Bstr- zSqA-$!{t2#tR`E_k){wZtQL2hyX)X^Ee4?QAgo6EsUF}};Ad>16V!GLQ;-`iE^H#c zQuSEC5L1xF*Sw|~<;Fs5HYr%^pv%@qAONeXx6R^r=1dHh$VS9MkkJp4A*>w5%z#;%sj?e$HI^prOac>%ZhnyQp6y;jdipX&@n9{hqf@iF&$>UDhS8R;KcZr z!HEMw;6#d`J+_m|8B7QYM1Nv0;={Ha{#B0U2UZ&dJZYi4ux*Lf?Nkt187iOf>yuiJO3kR^>^bd@-DUxaaI&Ujs8_Sm1cC>ly zk)!TR>b!|!^TH-Ga7|~m?#XzO+547|4dxlMRFp7cZmpMq$zF~7H8GRb{&-g&6lYb6 z;HRx)!B1Nw_-WFfJ&c7aDWBvX>~~Zu&TT0IN)8nn*RS27vR#^ESRGMxq=zK+BXW1( zFd>v`Tcxttg)>PWbRbw>yf0u!C2L;E7GBi0N--Kv93t^T&cb0Mvo?^(Ojv&L#8VOX$7E3#~IDL+Cx9n{(GbHhFk|=Vm&>4~`^bnCFzlw9PkZ*-ND^6Xz zRL(}4^{16|3YVDhXr_FMyH%Ye<+~@j^SM&Kdz`y|_3kn5=Bv9$xtq&(15TBAkdBn^ z{J|5{v z7@e}lu(ruV;_Y$k&sYeMM2eX`?MO!xXJSYqP1!}B!a6WhKFmoPbM@}(kq^+Dt9?VG z@{J4=w_)1#G%CMQ_my{PRDPZAEBDi=yh-=f7W7ftFGaGFa$5}=@}S(_S{;l8m7QDw zit?BM6Xh`hB+6p~MCJ#h{ks*Oih&`ITZ?=Fc@_HLYL?;)it130416Ezp-5yN=hPje z`cRKJ&4UbcU$2TeFDqwANilZ9rPGE!o*VY+v9?0R(uM8k9&*iJBTPrP})UHDZ+GcT?Y3Zg6FAmKBjmv+W7ux9ur1gk4Y@SCX4M*RnQPOsP){8LXKMRmw}O!p7MQR!T%TmFRWq0UMkE zA!JYKN>P5t1`I2Ugv^9oNLp!BAqB?CGJ)UM>#K9i`jp- zOVwJNa8h=~AgLy`jU2~MQD9m@sdhG6^DPPm-_on~Qo?*KB~+Q#nZ^rFjUf;@n-$ZC z1`Bt9-%5JePgv3!wNm)W*$m7ZQ}R-v3C$DIL5TjH@_7CG<%;ox4}{Pt_cVwt&;~U6 zA9hlbnex{yBWM|!wk@bwFvYbFasi*+()zcCj*fo>``lUlGc)C%G0Qm_-0iI|vHlfi zaz$4X+$!a}!$-Jk1d>b2D+H*WThFALNWXAlTW0?L^N@34h`GELb! z-hm+S%@yysD!E%e-jfx*=zY4GNK03y-(S=CEDbRN!~!EL(*y ziNIf=|CzIVR^6kU7u<7MV1u)CGiTu(0&|vCEU;T;!==-W@6YEEM_#R#OAw7clR1mO zna)`(JA^>$B*d9AB_nJBu$SDX$Q!eoAp&dZ-m^ScbYz8<0k)fI9%j`x%%d&XcS*Wg zKKpMz^`km&gh^^k-0ha1<5+b9RFeT#{1*dkTM}Io_GoOf{$jj-RaA`EE{0Kz*DZdB z@l|=AAmytyjP_chLg``dR_JxG(i=Czpk`J-Bg99TeX@s0-b z8SF6A(Q!!x=l4ka?|QZkwkP(qP0-oi_#zUw^LFIC_9zZ?HT^up&u!^LRyTK$jpd5d zsSSWh;d9Ci&h^xCOcDo>MECN?QIx30NSs*)JZ`Sxff_6DCRyRRFsSqmfjr`|YB3-CwDJ&95@uLLiHapL zX4KQfiXzhWN}s3SnvqKEOEdco+Lneqn2elOVFj8edv%{G{7(I1g&d&X{sH32Sesj% zanI?B%QJ>P)0LsGLu2R+(^);?(3p{i%WUUonxj+8#8k5|2E@ldtt%0w=XFJhdP-LS zc1~BI^`x$V>a4DcSgl1UQ|v+Urlr3PoAd@WGYP21)r6<^OCvm4*Z!{~JTU?bPv^{X z-(z*{ocIgtxyk;;uRietgeTZ4p1hz!NqAb6E)pU_mWrMqmx|It3aO|re73>+o=Cj& ztoqmxxWpeg$I)V%L>1+T4g5+1*k(=1pfT_Eq@`~xiGeAJX6e~pARL*h)DPf-HR-I-cukUFnNA8$%&-i&!w zDGd$3HjZGetTg<`W~`zsEC@<)dM0ni9Ax<+dT}cE0{2$x#Rnzd0sObgtWiEUAF^8H ziyjVnBynvASBY!8C9Y8=V#5@nP2yTa<~Gjc)RqxPw|h^fq5|ysi46KJ-O6jo&dE6W zH0%KK-#IK2F#W6rP;xW`#-Zb)Cv&Qfj=-DzKQ$kxu5*)jWk$1vox-FWRiDVf?yhE#$kZ9nyECBOG|z>sJyE z2W3W0Hhv{(IknW$GM;OMFwNiERfiSRKYbPyFNeX;nog@$- zrfH&+HYlL8h8V^{f2orza`cB3C`kU(`_Jl_ziaKJWyJuA&NgU3g<%gd&PP(Qp`m2cv=3zeawP3Elvz`dQTZH?1R5#W{5uL`AE2J@$p!Lgd8&o zA?*R{@_`v5(`DytQj5lBWV(^7k#eTsdKu=xc7-K-BX9Z^v&qQ+XjJYTJ41uC|LxFmQQY#kBuX?@XRnk_t7$b5hw#xTzP z^X9g;n)m6a!#R=S%4(RYhvnOG&v;Ou3O3h7*%1zJgA_~UM6T#knj*{dinD#r?Fhmp zHtF>)$~ncOWka%$pRHY#QZ_0>GX1O!$?5OPeW(OCJ!owIM0Wtd%*xCuZtj#<+NW3C*MV;3bS=p+do7bV0?-!naOQzl5Z zl}(z1pnX!H@cTdh9Q(EkuQe87xBS(gKzN!7o3RYZ*o?{Z4dk=U z7;I`(wKSzFA^OsIMSNejD+BR5$7f|A?zTIHvPswW;W-~8>hprKeVEbOu?Z-yc7#|V z`cpm*HTdoKFs^wFw9pSz6o48!Q&cDW@HPop93siOu>~~FcXGT;EovoqC&bn6PRloF z23s{Bus*9Zu)abznANKJ1Xf(P&Lh1L_GSp%3+#r)YDs+APMo@7$1U9;fXLl|P+5yw z4RdgOakCyq$5GD(2c6Nym^o>SF=t<8^Q0{ZWSrL3AGW|K_WFh>j5j(#6gg)P%pd>& zVp5M0(+CP|+YuNWl{*C1woj2eHK`uZ2tQ>dd|W1>0=a~?Rzng5Mj4mfR8$!@RLrn4 zoO;l#1$morwCa(>Yi%xjN>`YunI_EDOp{)iY0?D-2U#s7X{F(7Fm=}|gh<^}cpR%6 zQ6uzVdv_%mjeU~fsev&fS>LRWo@>y6Pb3<0PPCwDP&3E7mTCnk7uIoJwFgrGO&&}D z>T%Nzj~ij+alu0py^r%!*MM{KV#b}MC?-KWnB?G;@r)_APe-(5(tZ|FmHmp$JKkk4 z2owPmCd6$3YjImgTO!Fqz{qd_jWTQa2D)SYRBKtQAVS27t~2cX8~RtDF_oLpFIL*mkF`5Wd|40*Dl{x2s~oBfFd2 zW^hIoL5}rX(Y#!eSqVljloo3T@M7&qOAXcz$|%^2$q|R&CAJKfSPn?MoUg^fiQ+;i zNW2_T=U(3gBM)~|V|?OEXKMZ;DJr0V;j!l6&CnvzNbK)UjZq25u!QX)|K3t@@6&E3 zxc6hhy-)Fo2|T@?d#fL(az9##{o->%S3;b|`1iAm@NeE0FFg-eaBk+|KbzLyN%wJz zGk6LQR}g>x{zM+zI1hhtDi4>un|XKyV&v#VFO3{#^#5}n9#E(Zl@$+v&Vu+H$`cQlH#G5Z^?*ha4?iKA6Fj`;;%Y3x z&y7W;W1dhCn?}XOVPZ`#{wPdDT>O--aB+Ks=!bPtI$>SZ!<=MKgb7ye9qF>vjb2+G zD>%4F!`vu5Yv+0oqu`&}6BCeC>swm?kF>%+@Zph;%f3+}74v5+2=k|A7=Qn7OZH5n zM)Hnr;JbzJqgEqoz%(Ul$Yh(Ny0Y;U&giHv=4dRc3;vs;x;)71xK&UW{#DJ-+(b|p zv0gU$(V|R#`x&?WlI&+Q%Ty!BMCyWBK44}kh9QT|h`Nz1%Tt1;kAVvH5}t)mT3!s^ zGHf)gkv5hRuv{i~CoPn_l|yk7R4$3WRr$4_W5NZxar_Q!E-RVpXoDu-muUJ?b$Fdj zl|a5}wL)CWR2xQx0jM!wqzpX5%8;pu3RBmn$y5z_N`kEgs`c2qS;Uy|su?i`aI6Y~ zRinX;2CvKpk|rwf4sJ{_`4%IvCL}RJ5+WMP;$8v#aGGq(cTD)*AISxk}n>#&y_`@d)mWq~8WvA{`ks`#)ZIgYedaHBIb=??;7vK5G~-Z*MgT@?i` zi7@aGG6B%Fs&J=O9K{kNRP>soz^NmjNNa{n&%IrM@h21ax~f8+Z7}ib8`RzqFvtIu zg|dzSztT~U>x8*#@Ja`C1t$b*36@Dr`f`1MmmUGYw$8y60NbD&nama>u36HxxMqnO zb7ec6sh8bUh-=SxOocA-h!J1zG$O&(gG;#wZJ136X`k=NQcuUkhU_0+nIfRc_3Lyv zoK$WDOJ9aQdblVHt7E`dWy^@{_N%31!2Qm?-_=G8_(l4bg{#l0ar$-9{gQB&8%ZZ% zt`d)&W58EKm%h;W{z4v4cen~vb!Mfi`)nsi>iL`L1{QN&^jItMXd2dMP)D>|l7Y>+ zHioUO(xAyILsirr9ZG(NhyfQI^J^jP+{A0Ru`K<0qq1z$oa4=@a_C|+Wq zAX+oZU=b7c1iBpd$juH~2e|9(AzHcg8IGLoA>_9ObwrCptO$iR%nJL2Q>=J09`@-J{>>NepgV9?Lj+tO-L<cUi%Djx_k@gr4OYOW4h{pw4f@IOl!-Rtqud7$30>rQIvYuNj%#aH~Pg`^qHD2p7 zEDIvIW0R_x2wTV0?RbKHh9Ze7veR7{aFF4$p#c?F?JlX z?DovuRoMVR-TNvwpyQC+X+sdlAq&}c95PFm18#W1!%Xf@Vj5JfI@cku(5*znpeLw3-D2ji@~u@(XZSi4na0&J!Pnf z1>{B&3n(CeVgZZT*o$zd>k#Dp{mBeXPTnkAAgwHd%|np=O=?&RbWxetfeOYZlYSN? zJjkX@iwP{;l(<0h&Y~t_Ay|ND{}!=;)$>JliU_q-{VFC7E2m77JLIcntv;s>N~g zO7dh7G0( zNPJ+i3hS|5oX80Ki%o~&17@S+d|{NDfc|tI@cN2e*tq$%;sJ65zHlA@VNKkVC*a4>Z#`5C;UoYS40N;9pj_RUx z;wQ+vEYB34dJSgpa20Q8@`f9Xnfi?`m3sCB*%1~mS))ug?68gCu)Xackd ze1Q6BCQ9Ry{(Ub>(!aGL@j9wElX#Bm6)x+jUe*>z^@<>7Vy)?}j_GYD!Wi=Ym${uF z^&80hnGSDA?2-33B=%6NM00gKZzk3p&ueU{kLS&eOb~meCJkxc$Mfdz8^`kou@8Cw z^X)9}`#6Eyp! zB=+`VO(FJK=znR5eRbTu^^`I}N#+t>%mEB>gvOzbWHi z2|9mkHD@oH&SR`f8bTF{Bm(|xDBHuQSrz4H2urG!G}N(Ycq+Hv1zl0op4OF_ zJFn6@<}`;G`G`~I4bsiArXgBWVyV)`;HF`X9m@itmX#oarkr3R!ii`|K1bS-mGG6x z=U7#j*plpt>GLQ#Ry45_s})l%i5;|y zY5#*lVM`2Ic>=g+1zf2lS*8lk{zQEkZn7g@6?6n`k>@iTV%<#G5g*4Kz_gy`k!Gbm zS`Ay~HZ*(egZy93Y;{nql&|Q?$Jm`6G6s|Cyb{_E%si7iui9%eR5k0g%nT06tWzVp zEHK#MxT4VY9MLtgHF!m~iq)iTG6;2Fc=j5z_Bm^tO3vuiw`>P&e1EbA z{ff0s(o#{~&$hDw;%`#JLhRL~Z8oMq+Y2(nr~Us05MOYc487hOOc>VeJ z_8VKfQR0f#@l+REvT8 z7i8p~8@5;nM7>%07wt&1Yk836IhfT{d_Fa_BL5kW`s6pM9+4)EN90FasvgPCl93Tl zL6s-VwrPc~585v4fW0_{MX_qm7n8m2U}^G9z)dHUqA>EYq$rS6d)+@~>*Gv$giI%O zckbt|?(cE#>H$5(T|MH5xobit_46y(Y#qGAOgZ}+?Pc??{uIqB z9{4}zTV@yQH&;Zm#%3FX!yfn(X1l?jPK4N`&4elQThpSf4m_A;`NXs@8r)xD3Y60< zuV8Opm`h2`ywVgBk+YilfkgA1*31uN6=R=CmG>?H#TtjY@9x2C#cmDiOk-FZ;k1`U zP1|U+z(fzu5S9Zb`gGN{t?%rAQPRcHf`c8dv)P>xS!Z6{v=Wms2gI9J)QMikDT$W! zamAzbgZ}8$?#%NaNId_TfZL1~uyAz^)hh5Ww$nQMT^)j{KGY$YUX%30Ym$&uC%ubs zfd>^XAXhd76bi6a=HSTI&QW4Ym-zp&_b$M8o!5QedEuV>I2ZR^ToAl@n&!v<&VX0A58th1lF8A6a#^WEO6QU)H8g&X!v_OCjMe8NXj>Xa~TIo?w0 zfZ-;B_aVb;LFNZu6Uf9_o#^$rs|k?#-i|@0&bMWW9Zw*$Gg=fgHbbWI)oHgiy!>)I z!%KN9l(vj`rVKAv_y{?Uwyy&&*9Dff8)I?JR)N}$u_zZu!go3?HxtvR zzXQGY0vHaF*!5O{#SqLoS~tI69i!VDEgDz~!ssa73@rW5=71#}(z0n7R(*wPQ$KYg z;$+=QgKJ<}Z57Dg2B-FJjZ$WrCVX6PmjLiIm(uWj07C6hoX_0C*=cM&t2YR&afxiO zL0~Z=`U6x~p&(UoAs~X8udtjM5gvs5z#4UMVZunsjga;TtSwPE5t7O{k;JKEWrq)b z3Q99B1f@B`4V2~(1Lf@!QyN368Kn_d%sL0D$&hIom@#mT)K-dZNxFKof?AXLyx87! zq(*|+C0z;JHZG%So55Lg zlQ@gSt9hafu^`X+oMto-7JmQ69RaK@B}rH-FeQAor6dt+b!T08C31b1EiJ-TCCJuL z>#K~fEQf`!0z;0WI{_^v60TY*tc9qoZwPL+>O`xQ;Ttt-DWbWr8{%SAjJR|nc(%G- z7Qcp`)<;~Q&FA~QfrzV3#s{1L^7&pL9a(48f#g}1d^*V@A57i^JhINjO1>_RO5u^p z_PZ&(gO_y@?*MmzG2w#~k0S@R0x{V9o3@*H9sAxIo#m^8ZE^&L4&Kfa-Z*%>g`l;r ziJ<*teQsh4{*I))uJLTn(HDs-bij5_$NEa!xaK^!5X2YSVLSuZNTQ!NK)`q>JR?sl zksq7FGgD1vn?f^~!m^pnCdww7!G4uNMT3GqnkeYp_0Y@`W-`MiY=w>Y;|O0s7JGOr)P`0s)=(Rcm6hx)Z8x+zZG>j7 zXZ5-vG(#BG#&)N#X*7e~=?z6Q)c4xa%zW$_@brE4(abk~?VuU#TdxP2G35S>i)I)V zqZu9C9g4eH?3wH0nU4t1D6ruT#53CYjt&$tJu;74M_+3)GV`#XS%)oWJoDisjZUj? zO*~^oMO#l0EW{~c&B#$|x|6(P+%-blgrNtS{O62&?yOcF$6_G)WN^A+n~wJ6W<*u_ ztI5fcQ)gUSj6*Jx)y~$x%iP0Csff9p5U0GtJy}?=9ai_Qa!-NAmm2r3agPwn@^VhH zT3G?Rc)1tLZUm=4gKK=bQiz`BTYV122l-Z?L-Ag|)#p&W%6_b|b0|Kq2K-;z-q(nR zrYa1r{33gMaYo&s-01xPt=xB#lq_KVF9b?h#)OduGhL)1}u`MYWVkPZhA zRs;58s7?m6$)>ue+S7dev2z)W_jSV`Oi<1n2ySr0(AQTcL@?9nW;!>+pCJ64JK7rU z=DL@^g1>|O9pdj6{@%jh5&mxF?=XM2@ppi~qx@-*?%?lE{_f)MZvO7!?_U1yKh_$3 zFMr?1-}m$Pt^=*|;_~CG-Gi;7Tb>~%;_Fs#8vdYr-{rKnp>lI5B&>UT>-iy8k9g=N zIW_CwW&iD#e}72{SG(mu8EScJsCnkCtrvz5w2$+m3ux=DvqM}>TwfYuU%Z)T_+0@X zH!D=5mEOI%N(ghaLN)Agy166-x?0SRO8IT^uaT&&~E{ zw)DE4b_-Ra>!{kB9Bo+K-1%8Zf%aa&z^#A}|I>|^l`Qbj93Va$HcUCU;lz1Vekcvf z5>`s@9$P{}P}og*^V3aeEo^>rBBwZNLVML!#^Bo)iksxzcUhj`B_`*5|MAs1CTGqk zVcfKO%kYOhIdklun~_IJlQTyW_89{4U~}G6Z_U6!|K69Hv?u;*dYra}66qPN(4rkyLF<$4#_XJ#H79pK8@C8MKUpX2@! zt{j)bYVOEp&p$_&=+jh zq>8&r!6|Ado>)mMQ9pjMo9+A_$GBKh!sn61h8W&G+mDER&D~pDzuo8E-|1I)L&K(FreIq5Qh#-R z>y~y0W`GkZR!_fPJ@$jMILePvIWsG|@p{^+o-=lUZagMIc#J9U)mVpaXc z_fkD6JfoZ#>53P4M8zYtkx~;FV{k=Ns1k6@bj#mU5-=88+Xb7v7DXg@k9fSF*;pUa zVBL8)ktxROPA?69w4yz2itML#_qndt9h?8j;ScpL(hRu7GtADh9)4BLlJ-ER-KE00 zL$xUOLgF^!^QT3+UWO8a%RI8XxtM5?D7PK^c-rOfJF6vCp6Zi8l=(QM-&rIGQTRjI zhw|}Dsh{3+I#*sy4Nzs?{G|*kd}c!!)ZyZzRK;=oUF9_Xoq6h|~?O1Aos(De> zaE%RF3Pg+Id*vz?AYKk{VQY7}vM?GIXh2#$eum?Ybe63}gLYEoBG2T`@GBkc`3XYa zD%Rq6Qd>muMa^2EAd53E9$1T6O$bdhH`m7)IO2@MLD&h^lMcB}M@C%vw;%sU{fCgu z-Uj90Bx!wEMgA>0y(6iPj%!cbV3*Q1SQ2z}s44Lq;Y#r`w&+O^pYA_a{x3gw9u~}c z#R(DYqNuqK7(zP6{^CG#KbTt_s61t!Tcd(v_@nA765DGGZaUC+x(q>7I04_;oKVyA zEH>w(&=tMmSzTF-r=5~D*iSJ$syE@KZUr-WSFt}e<1R5RwI!)Nb8>T?CY5d8-nvL2 zfP0hsclTym$2-?)9kjCUBPBT~>451+JLxk0d^nNhY0(jCwnTd5XA8C_)*{t|K{&z> zagxrQGFEz+h*~}Ffx;3uUP7_PTODn!vnu-Y6yw$ZXf4tNKa_`f&^JFuV!qCC>HRdd!x6lt-jgpX-v z&pkiYQLh*B&suQTC!&B%gUK|UuTRZ7%=wZ ziFD>&E*V#g!;y6LVPmcqf_PiP6;d9IFO(q9 zm4{{@bailbxhmw}2ssQ@NO`8O`D&mNY7NBFWtF?!JSs-RJPI!xeo)}}Twkj|G%L)c zk9+h6NM$+Lm5`KHh*WYFOOe{|&6MRSeE7Ml3rCn*qA}fOsInaY$0Iyzv%jN1KAzbkYtz&Tkrslb($=; zK#SB{uVwN1GWFJ>z!_csJX7qxZ*NQuXQgb|0cA%cDnYQe-*T4ae_q$ve;SeX)m6h|dUx-tJ!VihXdXEVO2ign-t0qdG_z`FZl zfJO%uE3*N3UNewgUKa6e<8M|t@6qSVc8q2~?A*hc3;lAml5$7KrChW=y8kWFdCl?+ zHbm0ai;ibTj~r`{9#tb58#o9w!3P~&nO39}2)fSXO6qt<)7o{=4iCexm*b^cf=i~& z!p4`B7LsRRutVkM1PyiI;X{-_aabLV3juQBI0jm_t;yk6d)(PTF!7e2h$Pe@-vb-y2Mhf8#S=|;NGTk5{Eb5mZk`-*Fh?2JRE zM7!$uke?g-ubJ%NgZ#HUJ=2x|t%a&ZoK|%}yq123q%lk_@Xf&_o{M zcF?P2Np!uz%xkeBrfy=4$5lMs6{1^|vj9RD!NcDlgpXArmB#Eq^`8hZh1vl<|(0BeNK(Ez$o61pe``MY0V<)f%yb_;Vr+W9b{!pJ6 z$zY-@iPJCZ3i|nsu0Wnkx*lf3x2}MhPw0v@?YyqUaGlW=&Uji^smi(na!zrzh2R$D zWPyTUUNX^2lAD|Y`bbuZoOl?fHT;_kMP;(1P}%ALWG&h1BvNBwfo4I!I+2G;kT{p) zAW*mHG?oyx=#;Ls=xJSPk<5qX2}oY%JkjF`kvUVx#}DL`EH=fxg$Fr@qP*r(<=4uM zQpz<=48IQlrW%2L+eXJ^XH@1jT8jxXQm*AEjrWhIy0ca1xax;HqfxdX@LRlGFyqxq zc#B(!+?Oo_uOCc$+BV5};8pO_CPp0#R@k|~Da->49qx|Z&a7H4-VF&I}3tvo$@yY@fOlX_3Ch9einCVP5g|- zM6AXN7{e~3hZ9qAII*qmU`NjQ)dWyB8Aya#MUknJBSdj2DM{85XCWaUP8^uXNw=$Z zd&zBR8WbD1f&!+#EA=eywBpfB3`FCN zqxBm;oEX&W)f{lV!oDx{vASsiv#?HX0b@Y6wQiJ#!zu-n=L(rTSBL=4T7bL{(x;@9 zJd?PAxdVL6g~KH%oOSL;{1XhrKk*2RV}jv7M9#>>@Xdc1K6nwpAoC$v*)^tHvh#NC z*i7P;V6c;0;7(Kcqg->0`4n^TEj6FC9Mz&Wzf?H1XF4P|ofiBT%7dlKZ4yiA*F6{| zas%5>Zlqk&zs^c4dJnXIjjNle?_%e=;wE`USBB>lSMQk4%rozpW?^~9v}K@7ZDO9} z@XgE<{a})L@+-^}Tz_5W8BZF8YM*^(5T8yA!n^Ge+$f^76#b+Q{;&B9~c^&jYQ02oq;_NIUYHIH%lNx@cE)L3T0Ty}k9T zTdb971`$b`7V?kjL^-DIiQJo%_*?2VKs+B}`f z<;6rUv01v_cf652In#LmOzsm*)_n?j@{u>?$vUp4H|5D2AWx7X#@=7U@U8Y*L=cKH5K32Cxt{GCB&Yp<%(>;*Vj|}QiG9PIo!e3rErIi@Jo4|Tga6Yoz+?N z6!7)FPV!2HwsJgkVp@W*m(xovd6EN-q!|%nKq1fc9vc;0MKq+m81Ydt4_Nyh>#&O} z)>2Lg+%g&->x{mKzlU87>WsaPRh4z+8-2ni0s6oJW#8nILlN+h=qBFgxzUox?dy_f zcBG+f6JXbO!LDilrK2B~3UKsbKcl?fztoI15fM@SQBAP+ zOy(+LucVcvc;Z%?M; zo=ou&`rh()=`~3O^1Hq8;b}?%uELwY-mBsvT7z3X)z9=++gs;4-QJd&{_Na5)TmS; zN7TD$U=>DShamRl@>#{uOp{d4^kf9pd4GPn4vM&CdU3+$5LVWQ3Rzwo1rHATHENp; zedv^X^w8n~b?;dnoyhexhpy@ROmDPfFyeT~s`}rQe?&1EhhAIt#X8l0U8??Is^0c$ zs$UuKh7PEW-oFs;nIowip6%vfUa$B2*QwrSae8lmA-zAGdcRGy|Gm#G(wu7Q6x>u% z5iMiw=FuKajJCC$9tm|lmSzN6@r?abkR}=szhUS8UKf~1%OmkjZvjOOvuLYm9O>B6 zsDJ-+i{cKc80;kV%j!L`1j)6$TaD5DhwU!a?jie@=z)yxyJU3#E;nXo^xZV(`_*N& z7dwMLV02GSF>jJ>Sacr&Jop8nDDM|4x2XP@r+=+^nukmvp2o;UTW7q6{H!+G<;8wE z`SitlFclCb05cJlV-;x=L=~Ze!8%HX3UcOgF8h}mPCIV0HtiMOso4;WhmbjTA$NNy zGk$IOew+NTn|KxOAMBg{!=Az3=|Aiu>%r8bZXWEO{=-d!T`;g>Hmf$X5(sM|f7G+V z&s01&@wD7Sj2#vA$u+euU53+Y|LrY&kw5i>gICTz`UoERI89m(fay^fnRMs55# z9A#4Ai|RRBPo(vaKS$We_;VS4PdrEO#-9_XwH0B!ysZ<@EpQMs!vv&n90uv(p}?EaNsP&HerM$50BR6D?mf)&Wi?InM2r**7&U)=OD!tdpPX^u@L z3(5Q58>Tbf-1sS`-dsmz%Lw!?xX!~Gw|6;%?$xjR2giEvRpOvW(~;v3A3My^H+V7Uih2UJk-OT23p*MVvFdf zvX-ooqcUkFCTzQ6mZN4sND_Xw9JRR*LAK1&uiiN7dJ@COORffk8G_;Sh4+Jud+=9e z*8FH!v14_6I-Yq>j)G@-KrRm3z~s{C6$oYohI!A}8d|$FY>*R;WjK+Ila0k=2>{c{ z%tp4eHbr%43ot?AL=D!7^n21#oe>EK_$yXc_j_%)j)WODQHPAwI`O(UI!Ha3IuGNp z-nLrQWhDTxsj^6wKPo6^ALXG=eec5+rTjBd%Jzuz2>$<&0=n!N#07?k<(u2yj0YKK zEF$*z5xZjuSF-dg4=`mSm zJh1J{_4@EJt*XwWd+aN172oq*$^U#~srbIM{JxLnhEQ%>m``@bl-A^`nK1C6;y497 z7xtHOg!R4v)BF8>$Ah5q6-9XLqTAbjZ+UUIMd}8tp<1@P7s?&1VnSOPcYo~i5$~t& zcKAqCsy?>)2mseda{nMy$GxHtE&iFcr#>RPd*pwy;+ z2@3AeIKqCD&Xza+TR#R?E6gmX;0S-V(5lS_>W+gJ~Bo@pKFSZ)z-Pmvpu zqN*pB&8&o5y|0w_{N^(j!p(iy$9V5cnT{fUVvqdpGRmeyzgI*kY%zG4o!!L_k_S}3 z?9eYlSJ@3>dwb!-zHezB_6?i#Vc!oQo7Dl|OSpVc`7tHqJ3zQQzOZx3xY1^Dlazp z^u{e#;dwNjuqy4(U>%aC%1E?;DWo-O^H;l(2uLUI67ojQB?^)sywFp;FM$kzTx&2Y zyx9d$sLeq>$_>=#iL^PWrz#XS7fvg&|JkBrb5PH@uTs1^jaGBjz!%jDuFmXWa}XYI zU=Oy?sH_v7akZU|HQZ!6_uvcT0TjzdN#3E1c!T|_9oibKu~6Y`P1ar-_Egx1){16G zLu%DlAA7C9m5%-jXQM%k{k~F|J0Uye<6RbeZ0v$z5cnR)aYSM|CMA5vxTtCA+FdZY zeQIOsmBGTPsaUfc`n{15Q>;HkC0TAv6n8z;iU5p&m)5v9 z+z|zY3EB>VH{A9QLZNmjx~{hVd`vrX`sgSMW0Tmr!Rl?)*04`hPic0>W7zPH9P7AL zzoOua+WPaaa`o=UjaRQ|!r1FH-g~rYS8o-P-rEL7_1hG@&}LDGh<(K zsfqwT2T7)wHUecSdr|Y#uiE|psBAVyB!G)xHnwl+iYnAg5}Ek%5vFTGLmR~Pchkd2 zu)K!qCV1ND-jbupqX{YuGcZh$T}5LB#=IX@L3u$5{p8Rp#an5-cZ_ZY_7@2E2!8Y~ z1xKeNK^>ir^dZE#6WWgFl<}I>WK7Altw2UM@$%w@VxMCU1-pi$<$C?* zPpC3`Yp9(TK!)0;*9NC)R3f0xZez%o4UIcTw~^AZnvg`txfGKfrQEi*sfuK8jj%|x zaShCmMmYAXQW81lQZlWLrj^pA6l_w9qeCcb`vF~5DT(lMDVeGW4Q>)i#LS>#jt(sx z>y93Q$T~vvJ*j`oFBH4#0RDrTb)nDOUMRLVZc8Z|y-*xXw*(XRzfcVFSMgQ@;Y6*u zL7B$P)Eg%JG>rtb&*9mRzB zTz%i`?DZT+$PH@ZlsP zPfJ+i!UKKB9;|pV%2$lO0Jl(iTGeTt#*_fa1+oRVRBCRLBW_ssv+M)GsY76=khUj- ztCk|m(umsu_YoNax+Z{ie?r_5nhUNb`xY-I#2v?zD$Mjj)?B`8bWWk2NKUHFCld($ zkpesqLa(v=8iejl?L}Mb@fICRJ5a!xHUkWz@#DUu0MvAcG3XK` z+BK>MbsJR!CXK3rs7BSG?lDw-D4}Xlw^8*dq3Ydl>wHQm8kBue*W2C}fv5*ka49I< z!KLsbqwl@!oY8Zj`E$C0=3mnFR(8k8S!#3zNE?-lDP~mO2tLiTnh8TI zV+@F=@EeNL9&v@ATJutb7wc#&+LR_tjW(qT#@otrk@0rUasjbA%Y~;V2TV2awqW&y zgS$e}o5b5*@X8m_#M{mn0doTSHSzXSuL*B|dxf`8xSHg}Z5wYN=N9YgM1{8xWR4F& zr2EG+@@I{*9*wyZ`hQYnU*YXv!%d3?u>5UsH#2MeeJ@vec#rDJ?{{)#-}Fd{BsRq5 zY6GiGuG;Hhb1ii}H|kJkjm^28K=C!QkYsHBcW5wu`Wdqw!D=IOP}IiA+%W5Eqny7@ z0WmuolNLZI22F*(`zuA}cxy5;m#!*g{wocCtdRMyOd@j>SqXxK%-8y3hpB<}+{Wyp z^DgVigmBTWi_Pbmw~airf-5ku5L_<_X2~^L`K898zOXq2k$r{U6O-L&TEE`Zq@E{m z9DPgM)v*ZQDtg7RVi9f6Eb~)?;|iNsyX9}J`T(_StH;w~OFb}!??D3_mvH8EwWwW@};Qp!D+~^5JH}vMD32e^%)EZTV`x`1vh5J|3=SiKS@IcI9fe%DN zH4hgnZug34Xug_~jQgAVO2+e0_S&KiKq>E_aCinE^DcT`16!*Uf1)8l5v-mPO;qs} zYgCF|AO&^?j`r8N6eft1Kyu>i8?5HX#cCGuN8H}}2@)x=c%<}8vjAJNh+FcZVv#6X zLM3aGz{HarfBIik4Dqr{4lq43)9il^;<4;MP@?X7PZ^<$`Z19|W1%1jcz zBK|))Sdlehw+1U`O<3~Qj6Pd4oHZeSYwt!NI3>-UwKMeVsfhaSbk(5bJP}h;CeR`# zfT8g-kZcb%0v%JF#$T&#q5kM0rL1JGHy zXtfGAf9^1w5n{UY_iCK2xJiuVJJ=!fhx7opY0ng@Vf7^^iWm@dV2?Cn6o;dLD?#U#$>CE=Yi3U ztPZ~|&X)S+6cGj4Kz>AA#_i7gL$WDI3m`;mBlQBv&h1|7XluwF&)=-92`HMjfYZ%> zu}f=)m`X@)*D$sL_uu6Fj>;%@ z7pB5{nntmN19QhS$TL%_0ZN#&WE8tgX21K3#nqX*B?<54GBTJm^-Pu_lNd5&1r=}S z=w9qbRevT7YegCpRKv+B(1LG`?o^n^-Nix7g-TkTMrFbpmJ!;4X{F3i%H0dcI<}C66aX>=vZX4z1A7rTR)%QF79h=?$ z;(mRf@plY=+lzbj{VspU@VBctr0+-leNSchyTjjY_`@2wTeCdfBYWvFG9E})N1yPb zZS45@DWGXZlx-3FB;=azhJ_NlA{I&pYRp2(CVkAAo$Br$O`wQeyX3K5))q?JE{P#{ zL?;b=B^JuRF7}Mj_@F=x7DxO2k%RX8V>vvo`&bTNmBsJw1V8lktq+*QU#p)Tfw|59*3l`-HB5 zs`u&&4JtWoG5bL4=X~{M%=hzACti^e6|II=oM&BV&$>Q;e8GD`)T-l4*qBRB;}LFk zqq!ORXH(-M%`80ww<(23>bY3Hv#s9D;Vnfgcgh)P!K6Q}?6u^WbyiySVJF|{!gen7 zV93R&@Mg7t_SlMwORe!f9=Iu{rm6rv6xnU7vX$MI0;xqTkTUg&^v@LAI<|d5S#1dd z{!dk`&Qplgv;ZdB&*^np*_OrmCc!&ye{`YJmQ#esWY$@eK;A&JJzN&Ys;skTT@7k7 zWxb>Wjz~nyEe+hlY8=HK^`FW06OTvz-ps-~A0fw9sLZWoSxCW^;A?4jgNWQ1FnPkr z(GHRf(hh>dLSbG+VP+=%8|ITCzX_E~Y3`P%X^j(vQQ3!88Q0T67mPquLaaTSBAZth z^)dyq;udEl?<4D*!tWOK6>4o1cPe)&jQBxLI20DL+B~afrFJMwaz|=&(3V#ZwB^;r zs)FjBIC(L20S%BFIei%ENKrW(w;vlAXsRku8`^jI#>igP3^?nrTt)`m@*CtuZ^moE*oy2=AbI?oTu zL%tw?P5q*6OjTFa~CZ-p&?>POH@gVf4zcf85Ic z+;`e^wy63%=DqUH$6q-1|F!?Y=#j3fIpJ!a?keGusNh7Zs(6H`Y>0_lAK+kDiof%n zv@6~1mEZ8~^|v&cS4rIe$g$S3`D3l&A2EeTy4U6(2F$v}TGdCoSLatBWztd;{@&^% z#iKtUU08k6(j#5pkU)2698MXB(m)eO#BWfo7!=qdECjkJKgh>+F?d4D-8}KclG>}b zs4vG9-fmWM)jd3_!mnzWa2R;-RRBeQi8J6--qYr|Oj)umz*ogzgW$*!r)MD7JoR_y zW~E6_2^`!5+P=1_(M~LlE|VtH57_qx0!AW&f)EAe$@cJbLTzv`--8AfikZEj-DBJE zG!7}WZNKPQK9=hDP0DN&9Y=JFSHRi-R3rHx7OIVFH>oSv7C=Ny_Lma78a_7sVcEyJ z=u){_W6 z(xEe%ImbCS8B#d7#*=b*k{u$*oW_cKGBL&DS`JVsEJ8%7;9_x?Vpj3f-SU?pnx$kE z36flj{vw5*mJF7gRafMbW%UwqD-X1O0g1L|;@cIncq)acRC1h`9|Ha~s0> znuX#gbxf&E?wU7_DpsB=Ta%NW)3yoOl&>Qso$x1wWDg+;GpL266aFNAc7YaVA^EZ@ zhY&BgZFPc%K}a=;EKB1$;SZpz@&5VTr-*7?lI~4$AD_=s(FuQ2#S>DI?q3;FTlM)HHuxasmkf@O2^14)BuZmjo@CVp{FZ5Wpy zwhbk`A$gkih_q0}-4^GTeqm=Z6pA(l5(=8)0;uW6ig z7+F&ZJ5%$&l#oqdzQjkZS4Z4;|=qlYEu%*=IxM=+IhL;OY6*JrQPq5P2S_ zN+3h@;Hlh}7BRX)q-ZYlXg`)a`)Iu6&Q7kJPlUm-Tb><0hLyTo{!^}pVV-SCp*2#e zDWU4ml2vvAOe%Ey1U8(UZoAOUqCKF4(mCk;8;pK9+Ae^zCloqPF6Lv<{Znc%4L|9= zNLEE9vsqSc=Z4Psx*6qedtjdvjrULFG3a3{Ry?uL5o$mstNc!?Sh8x*S`Cf{SXNn+ zgY(Y^`b1+a=3OUUS8`v=Z2ph*>^;7<+v>KV`Po`Hp@2#^Kx3RO|KJx8H#6vX+-!3* zKl#Uh^lRjoXVXC^G^4JSiTa$7v9g_YK7^vmRw2Fdk_8C-R9&w0$?gIs53*&}Ue|pw zF-XrRRu?s6TelEW)SeMMG+I<%^zBMr9D;C9ts>fvhGg1MMU;11>}yQcu2-DIBXpU? znJb8ypF=LCi!m$}h^DHfnZ z7F|SB*9jySxRzIWd=NZVhm4sru6k+~0YfBk!B(Ye-#t1&2{I*()-uh+x8}pzHLt)I zu;&4-En5{1$PPlrUOA};!3VFTdR51jOo;^OxZ6C&?axznTA@`ajdOT+%geddgkbB@ z%ee#wjb_>#&h5|6RoYO#Ee@8)lbrt3#?u8L1OM}?v6oz3(u(H5-DpMJVq`DP<$#(M zUi0W(%x%$uEiD3}SRu6KlXHwee(ZOTc5ruj?I5z~!gwfYVNdlwu#?zv<+u_(LRUAQ1#2In(Kv_SJ-AQJ_X$P5R}C@qhtlXuaMD1hjNmwh{d2L zHHti+JISx^q@F-cn#*dE-*L=Ma5Ja-VZZ?RXeH)gw8<^_49gRx6{L}Zd8oLrc3L22sh`8w>7_yvU zxsMgrno?Nknqx&tv~<*X(xtX4ljM$=2h3SdAUdJ<)t1tiw6?%2bH~Hp2p?CnZ`Q^B zVrL4}@#!X#0Ab2f2bRrNp2vQ5S{+fKDjvpZMM;pXUld+WR27}S7-Hn)qN;z0R3r@c zGmALFxt?0Y*UI(jMRoup#T2I6Eme8y`jKLY!f4a6G&Tnv#bl|l4I3cm#Iy$3%tZrk zO%1SIqXFBZnrQM-{TNMt$08*is&dpHlDur3#DXP_b4#@GyVx~qK{d;(9cy{CHxHq; zJP6NyMzb`*Av#Tnd0x0#;N&|;d!)?0q$@@*S?Hn)ty-#~ifvT|X_#^a?h_U8jwu^{ zV9NHyb9{pKtaP>Mz_oDTifiG(mAV$FesLaa#=q#wQSFC6rY7*PU*ciEL{t3|O{MpK zl)9cl*YsnEvZpymvo06&SU46?e;Vufqlq<~(|Shz5#dYT$dzUhqky1ysT;2hV%#na zMr}zVTx;SIX*$=d)`KQ^E?*q2ISdPo&?Jwp+sXvGODpP%p0w%h#i5%lpYYIWQq_S- z*RRD+es#uES>2ytHoP;PnGtJmcmV}`29*~OFQ26$`o1RyS#L_PrKW?qL&8LdaBbs0 zr(YL4Xb7@|^Wndj9GjR*Cxcw?~s^hzCmI;j1yvuszi8fmrn&lv(7)^ zHTVjt4FafLz$Lac{1Mg2V2^aYIFN6R0};xdoO{6LA-Uy{%W}&xDBA9g<41PISrIGw zQAN9Afb$F}IuVB@gy1jFGW!zvV%IN9xN|+5W}kuG70Xb*lLX_B=opE@x#~&EY|@u` zeZqobSjvb_>JuIDJcij86r9@nC<}`A!thZR6neo&H5g>Il?BE`HthJR8IyMWT(Gql zS)?ai4#_SPr7EQ$rFvUl7=RLJ%LX8`0-A5b4+O!m89fihGdWcSnkV*-oq6Kxa)3T7 zV=*IsT33er8C~h$DP8H@m{EBh55kVuWC0p(#sXwz;6^+Mgwn?xiEh$p#t?dr!uBOD z#2jfozcJP#`f6*@35Yg(8%~H=C8*GJb9BKpZ^NPWtVIVmZ7n*0VyAtGXp>8E9+Wtq z8Ni<5QISY!XYW`f3@eDaHVsX2R6!REpBxglIzlS87c<^rFSZPZhqOoR*EFIdenx39 z43%I89Cjk~v28Tll|>?-zcmYfa3B<}c43KC9pN#HYrVd|6DzzJ!Q-n-uz9!O6+IOU zX${N&w#4FrH(mhbmsAf!yCja41}EK;96ZsRyoAhSZ9`q6e36KoJu&D0F-p&t2J1NE|WqblOhMAJn;lD z+7ZKl-ma{rg~2y#V6TDTnr6joiWZVfB)MD|R0VTzVS$jqG#x*TwLunH*to2ttJ1%d zOKZZsDC?UHn900&)zyXa_NCc?09R*6Iz5_YWrbL+;`sUEworuc&Z>fi22Hq)pQ{Xx@8Bwf<2{swT4$v%lsv@I8iUrrs-*nL(lLIdxd{e>HBW@Qb%t+s}`LZDH3v0f~uuZv?u zVF`!DW47KA7M85rvgPHrsg@V{dk5cL5%L9B5)1d0SsC#G#IruqUF!`tKW51~&*S&T z0*<|4%=>w_OZXGpgw_I~tM48?1ZDT(HV>o~dEJ#5_AF+I7axMVV9T=q`QBJ@=Tgn8 zW7I4>HlE$1{?Isv~BR-Jfinb zA5lNasQw7S-_h7Jt}aIPd9%avG`ASrGaMtP@$0asfC^9NcC<$Fm)N$??GMi)e9iR4 zq2+ftJk^$^L9OjscHB>TPZl&BdH2|U+p`XpO0`f9i}GmwVN?v)i z$y&cT8+?g$c3RX6u1|cnvS;z-P`QODuvWJtKT50o)1PN~ZjsfhL-mIo5GcFUA71_V zpZ(DbANrjza<%!zk6->R9`A>ds}pBCce&I?uE`n(<29(1!Ibiad5{~_R1V27 z(L!@nxOQtqRuIh>mYFA3_gicYbf|c@r3^~JtsBN7yV1MF{l(s7__|-*O)M@MzA*6| zHmkDjDaPW6%?k$G<3(vu*DuP}vT?%~)jt%V8@tn6G)ox1W^~2wbXcaN?KaVeiR+#; zjetUSCh!nb=?=ih#hSE#7 z_0Tfu#I}tPF7CQWFISs;>Qcw8Wo{+H=^e%WX`J7oan@kRI8!iOGwek=IQj4@$MgE^ z!mh1;mqb=FIWi<}a;BPW;PT+nZVPdQOeS^L4E+~xN$m#hy4|?E&kkA9h6vkj2#{ee zRpeqR#zx6J%qnL6VKxBVDM%X)Oe38e=ru?Kty)oXo?DUDgf*cq_PtUR$cvAt z!Dl{@Sl0>h8`;}fh?0t9_O>4qH8kvPcNEA=+1sSI>9@6JzSOkm*+k+ED2J`X6ayRG z?qN-5qZ|7W+X`MtCtDWmBaGdpQ-w-Y->y$^uA>wdDFySHhfJFNa;p)*r$Sm^c_1LjX6@-R_4hZyDktRigZpe?wi zoHY;)7CM3>%`@(;Ep&n{A{Z|{qcJGNlmdn9EcWx8`5O4ln)9LSbeRr3zB+K1#kC@V zQECeFiFMi#P;*%HE1TYE=|HP27^{OVuLicJb6g}tRuV18X`HKUp!uoQJJ=w~4$gP( z;Uq~g%6IHpy`$XwlXUrx@;86^<%91mJ3l4dQf#MUHbcLyv$N>2^=9u+zOA#DPZY$= zZWm_m2_X@9z)sJ{iU%mPNBsTpUlD|TxHF(YF0)!kO9eE*n+|Fc+4RdNj~_q&GcqBm zd4AJoh2i_i%07I*QnUBiLcp#Ih7_yB1G-|OgxaZxwqQGULi}%b>mK=LjFmkd{5a$S z0irZ%9YH%vpV{LAn~<>*w#fS$mSn6vPSb_yB#WO+y3FykbdW-@sYCQ+|HxrI*iDB& zR;?yut%5z<-^=P@9Y|9%8SF&=0fX<9)GCNh!@P2bmJfAaOUvj>x-u$Px!UG&n@(({ zlMx!1h=~a3jP^~krmP@YQQ+{$6asLEh{0Uw;sS#Wbk;AazDudTPo?@UE*Lt?e)y_x zF)VHphB%rOmB|{rYed>fGA;*0ZD=9coY`o~q>?3iT%<)U0Ck@n5>Sc?M%V(^>VL+> z#T~(DRYOuBsKH)xmf2*<+VI&WepPLCAnjEjJ&(eV!JGizM#MH{Tx7q;RT!F#@SWA9 z^r@nME={FJ)@Le!5!kRSa}xBy!gH=*i%aw?6JVN?#XjL-%cH|=@;roRz+Vo5nW{HRpkea< zU-jy2_3B-zZp(58*ff)0C5;a@@V?RlXLhCtd~K5wP#N`)EsY*6TRMy(l-%7`Zu6jW zWiPhOnMaw3$k^7Wk#~)b6tjXo?Bcw;xQE|j6X=oAEyYnrVebOCY~O@^KqR-`O(pHcm5AOEAiS+I^uj;hu_#ZQP=2-a1qdre-wHmK(l+JAe5FC( zw0VG$yOlpuV~h^QD4OC2p|U{GG^i2XlX%)jh6AQBB;thOz>5bgYC1q5qSsq}X>0H5 zcpt|F=SEFbo~1ED-E_wz#^CknpqoGk52Oz6FuWa`#EA~#2oxjUS9K;W+s$`I>PC_r zU)|X<$DlKNQfKxVV{Y7;eS)q<)tM?9oJnrTu=OogR;gZ(nK2KgGo#d*!olGiccu^u zjwp!+d*A%b2t&UvGh@j@XI4^YmhDO1xHHT0+$%j&teGVGHs2X>qt~S~Im!_2NIf8c zMher$o#`aT(V(euTx3mK%HthCFsnw_Nc>@=J6KK_@5_D3QVuHv1xh`#u^mWF&2Xv- z=x!EFaR9+>R(HlWN3jC4`BhxmVp{*h2PWBM?kX;Os{(r9k@JGO;W|0s{pNQk*NO9C zYSTJf*8w1DH~T)zrqP2)B)Qen-8e*nE%JmWP)WKQdGpyN-)Uy-jGzE|b`gWhL&cr; zX(o7hY&)C$7C~q&q!qELigq9n0?CkywA-$1V@UuA-jsAI$1@fkA-tO+^NdY13FI!3 z)V1hGzK2J&u~O==eI;)f66mS9$Gp#k>AqUD*nMTvxR8SE0*-t@YP*y#;iv zD_ifc>dKb=f6gD!mOg8pjeUHE3+=RM6zVS$&m^ivJN#iB(Xu@>c7u&?0IO9L^rH}v zvEN*K(!JG?b*dd>_AFwO@P3o*VWeH!W?o)pk!9!kRV^&>8zMXVlUw!JS)RA*fng@M zT4>+-533Q^-D(j}S_EE6b!QjR71a->mT6oH9DnlY>Z989`F<6!+4S`Z)Uli2-fL-c z-t6SySJN+E#pLU|?CQd}{kgt${PGgFSY(&`t4rY=*pbZA(r}V5PE}vZEmJmp_yM(X z2Bg}}3gh=r>qPP@4?o5v$toI#r)*iwaVgB}7pYDa>6K3^CluF<=4OiMT^65eq4Ll9 zW0YRCBDTZD{_U2^r4g$SDGs;1&?xpoZYkvf!8uoDtKyP~^X%(!&dNxZeu!x)Io`na z*yyaGnI|WWMIF@Wz_MlQ2^vNnAO5(^z3qs3r~qV3KbRSZtqwhyi5nCOjH6%S0$p); zD$BpW{Ve}aL!E~c1ig=4(Ct=Ng2ggysdhA}tx>o`+q|@vD!*6#Ytgbz%+et{z~qK~mn{^Z%N}dE-%VA2i-zIMFjXoa-H|RDU8H&{Xd(M~bq3!fJ|0C?9BW6Ylz>q# zJ`Hm!#ZV(^H^?5VoTdv`x#{K-K! zrxv)ju}4+P+QzDJWy=Cr3Lu{zr9{$i(ET9z^QO#2YQ^1V;@7Z^hS@<>WD3_h(i(uk z?QSminH?<2-JGcRT%+8NriFBFjPl_eH!ncHxzJS=8mnf!P+NzT!a29|>{vN+4$BCgoBaxXG4_0L$g6zBW4Q+zaZ4tqBC>n=pMi*7rn;L71(5Yy$Y5#yQ-^8 z>vPc?tQ!k+STD+BWE0SmoHZv?|Ni|4&$r5(D&PF|`-eGWdjF74Yx^e)X-lA2fmD94 z{CU|}I3Pk@6jQz4hypsIpv8^(cVqNnvnm;{AocS)* zvE4NmLj;9BLyz&E@UBzFQeux10bX{~Y6uno#FIXdExcA_X`7YC8j*gpQcQVp-Z~^o zBT<0+D!nlhUG_#rq1{T#Jcka+c`B6->C|}PwYsV33v3tGLQr6w_-fk=#d6jmQJLGs zVdi+dZuvQ&P-Oi0LQ5Gxpj?y@D_tm4R=RL$Sm`>LlrHkJS?MCO*h&}5o|P`>`x8>W zP>;rxFI*$`TN0*hzw2g{FPuC{t^tW2iJ85w^5q~qG!42f<;&X42Fe%hvhwA4bK0Gi zFQqok%GYVJN|6>(G#e>j(y@+hk31kKt&%;JO0`Ml%O<;1sqT!qPpSS;zNC2NoFN~o zm985|qV=CtO4mtO6H3?9eF2D4=Yg=?PWE#|(YB0a)cF&+9WDE+BcPmUZb=kuDM~36 zy2OxHqM>B?n9J}LeIg;hi6mQ*+eAsWocn$$Hg~d54&LM6j1nClm*RPj)7l(c^kfoi z$KA#{e@HJjwrT5#&S86Kagi9pZ9x{-oLV^`@U@w0jD_YS+8e{xOuWA}-bob;W9E%< z@X)N3nRmjf%u~Uhop4-YyJEGePP#6?PK*aeDME?nTG|}Pe{HkagzUTp8`v%w+ADug zLVq!DjdOA;?ZmF5hNcw7hPt2UEr%v)8@2~=tRUVm*%*g^wX&emakS6~5Ms}@)peA; zZd+Tf4cFoSI-8)fU*-rOdTYCh;PggWx#-WLnY1>lWEi_%ap(mFyd*=D;RH0PqFtDa ztf$GZBE{Pf#kd95;qL%fCsPxTj{U!BG>#PWi}Ntv*;=g}@7491Q7Nkv&9LVg6jG=; zG-F;@njzJnCJ1)VjytI=q&Jy13n0mwg`yT4n|soTX0hi1Kv#^xT_`U#2rMKC{gVFKY%LG(0uxhD6Kn%qZf;xWUBR1?W!#SInkU)0sb z<`f6rBQ|(NCPRYk*(*VefwVBeE4|@eIy~-OIy~!LIy8LDeul`ImhWrsHSN~Hs43&% zS2^F8x0}2n`Mzksci>!w$7MNoRXi@_*cWFejfjnWUnujFaxAiVf%2~_$Kpu`OFQG6 zR$@%~IAIGRKw4UN(uv9|4QBj#CGYcBZn{-T-j;rV2P*ay0=QKEwHh)U2a@nUhO1tHZF?c2Hu*z{ADdmT~a#NlmrE zgG>=h{sPnT9*h;(4m`n@D5sE_3MY~u6cqdM2CU$nRIy;iu-m99i>-FI`mbXgQ6qv5ZE;|DFIyCvNnd*9KNI3u z&T+~{98;3M0AJSBvY4fMghUI#ERNR^13y-Spor7I7>amBN#?A9B2NF(pTHurQ`z7; ztnJXoB23_hSOh6tgMkW*tW%so0F;@r$nqo>F>seiAC6-Y8fPq0=-R*{wm&`coYKF* z>I??deyv*@6a{3ca-~>KRuCIzRBf_?n7akVe2d;WGqh$Zv)aS76C*e|I@_a146dv} z8+8N|=GSIYPK>?xc3R(T5p1?Bd>pYb!f9!)e0u7%p}yYO*kwFrY#cQOKqBqa7(i-= zlR4fvS`P@>aW&WDa%9SO&FBIcwJ#373Y((25wh_tbw1$q>enE*|mDMk;#;$bs* z%J^0cX#&NdLF%qrCH#b?fJuC0s%<2-728c7?%WwAt)-NhNJ%20dvWnb99Wu$47ogN zwA1@H8{kg4e68Qlhh9)%fe2Wn~DHa}oxDzdpJV z{=&sD9e)X!Z7yFPNUfy<7zk;f!7~Ds_R`q|B8#=h5to$=d@;$uvub`5jUho}HLy^o zfjoXrC=W^gmBO*L;U3^H;8`c(u-HhwhEm^99Ja79_(qM%nKbDchn=ZWKof_3(TgGwNhraf3*vSSBK9y+jq+7o^9Co7d{)yb{ zaUAx6*B^&1)Hv)$QP?vQRZE*dVH0(17K4qI|0V_tyzw=P!O~p4iNWfuG+>o1@82*C zmZsq^E(T-w#`W!5e@QSHeKiIh2;W=-dGmZ8eNL(

Zrr~p#Zp^{qut{UiHp#P1m~Luk+W7`k{&-^Q=hfh*`Np=v%@q4r z%b7;n(EByu=h9?n0CBDsZcQW3N2db_S$KZegNBVx?m5+X|5WZ%Y%R$r_k5@V z4PV`pduC-EcMhFD`9DAK8~^5&-}{|EZaqpYoL#&++Gke#u-ZpR;xqOD(ZbC*nN6SJ z^I2gIaL!H<#MoCK2Bx_$~3k!_!R52A9}_A%=7 zQ5(Oo?aRyb`kvu4_qvEN#kjmNSy^en#n=h6oDgFtwE9AfePAOoh76i6#t2Q`q!=Rs z2Hu&*%6}?xj+1IbLo#{y=w_vpJj@$}dE{Ur;#dDdoZ&OOFt|@0I-cezOP}L4muyO( zCts8FLB1vFbB%+y^BF#`auBT6;P`v_O&iNn)J8k@=(QE22|3nL8?$m?=co;DXZCN7 z+L+ZQjw2DZaV0fV^6>L&3)d@ds=}^guTeXnxH@3J5gE4y+ZKInYt57g;Q+hbDDHCZ zaXxWXzBH0_rr6T05yF((A(#A-I*7yE3@lH3>`l(Gp@S+ml=_mN7yLG$=UXMAdgcEl z!Lb$VzfN40lA3?Ee46-~9yX=Zn$U@9C$7?C)IeQ4um{15mG_x%V&JL z@{~hYpH2yQV+67tJ$cT>V#-U6LA{g*Rdx{O%bU>IuG!RiZP?V()Qs|08UswkhBUFReWwfccTt-RhD$x4PFMOf&fIv|&}7FNzt?)#{J(!@D&X_3xtUneu;| z(N39}^0~fF8&&4wnPTRxt>5fF(B}B^D4?yk&h+sHbA7%~IP6}Y;r9nxb0qU4W~G(h z-K&EvEnoNQd}n*nozS$clF3s=)~8a*fnpg?{vYtvethfv+-!elOOFhREmrP~4RN~_ z6h`tkzwsWmt6`375uU8hu(i47W^t2+v0L-1IGx=tew9uR_@oS!Iz>m%kv90zg<`k( zz)UHF+-{vpMtKKmmPwJJf10Kl*{i=80EZ`km8y~Io?SXD~@l6xEJF^Xy3f9muA#}!<|pf z1PNW75rK+JcNkuUgD;DNb&v^}B1k_@a9F?9?RL68ajaebyZ4=MWXhaZ40Jmu;Z4D3 zK9tJHyLm=Ti^-aosjkbVj(MlX$x1rol?WMh#;fp%3))XqK)DJ)n^%xQ%cpo~0e51m z$T9H*yRf0SIDbq5Xr2NyE^kO+#657aLKz^(J&PRWdzdLdGm|qpvM7%*lJ|A4ZP5_0 zahac=?LU^A?qg%76{qnY<(FHv{XhXJN`@EJpMF2oAuVa91hHwu z4HALKp4ZY8hIMLFOw=@GIW=WZYRYzP?#gc*)y)_?pI|dnYV#y>c5RCyv}Q`}NA|R) z)SNSpo$6~eXGblll6@c0kQ<&S^==i)a`GIoocMWcIi)E1DBS#arhJ}y7z&l77Kj&X z$kMOGl|s#?VLZR#bMiNkGYN|_KdXMQgaiz*voqG6Pmmwnm#>cMr5a;w8wm3uo*R zSByMs_0v4h9VtZXb3(+V5XFPRhTB^ouu=5NoOq)g1fCp zbH0X{`$W;@f)I--klv{ZzU|JEVDe$k%ZP`y0YT3p{Hu4E7ek)CB87vXGgRDy3(I0J z7p8e97uL{rE(Aynxv;_pT-dZZ%Z2sSE9b@W_iByx0E6H^^8n*NuPWoeUa?!dDZzdg zGct|l?yJY=3{3zdG&sShhFMg%5+OKSiN!@Cs$W!N$$vSEc>*fb! zY&4~yR9LRpux?%l%=QD;$!w~&tF@R-;ZwJ_PJ8UM%Ayid$DomwE96pll8rr}9)b~q zHS`$ad2P0zDP=;Xj1E)0HYn8wH{_~{JQ9xVU69hnO ztwm$PdB8pOv7F|WpeW&t|R zu-j|(Vb`I=^=rM%5>})N-sArW*9s(nAfD~t2lDeyaxn^NfO+hWD8I+F;)MDR34ZA1 z7TM>G`l^DJ)+rcXpKS-h?>upf`U1bpSinLV06#17xl&bMp*~9ysifn*xnA`ZSe&Td zSb*v?HaMu}Q2mOS&7P|IL=Vmw|5|!)nJsodQN3je)$doeaC>mGtKTE`6_8tlpMVUY zQP(>!c&2uxwr)>t9R?za-W}D=4B-Si z{EFL1_q=o&U8SpWs+w8lr}mx)!DvrXgV+q*^2%q$TjHMSuezAL^80XUWb;5Nnh%cJ zo%a+g?o@Pq%zP(lsylQ3h#W0 zG!8o$oc;7}pK^)JDo^dogUas5%aM^`nJU`|J&8q;Sc8b5ziNUi;?Z18pF3FR9w`y) z|GXmnKVu7eX8c&tnKe!#mjGbKd*kJcCRE_1nSdS6F~j#f`3<)3=S1g{-wEr8N6YHS z;VUA8v_6K0gaE^Y@(PkEl4Y?-ark?@NAlo^fom!*xP3sST@0;BU7Sd7Le{R7xJW zk(WLG4KMpEZuO00M>#igS(kIq;|T7I9c$;tR~0*Qg7X~csn_fDZWKLE0>um=Wfuf+ z{;9B~&W|Ri+dANJvhq#B$0-#HpR#GLSt(NPP51~^RZa@wP}uB7=+($%3Vz!pe9ZVw zsp?(}B>M{CW1_e>96tVlI9Y%}PTos^p$It-(BVhq{$G0dIDr6f3_hl*GkmOJV%FGz zfVP;Syv2BeCdR;HKqyx^20CjnAyAnC<*u)BKq;?mmIj|rlEvQHKVLw(>n}Z^yvV>e zq0mK%V&Pi6b4phAjyD!i7Ox|qoJBPqJo42Bls3O#NTVp|W=LoM@`W1KU_+Hs!>GR8 zt2TSYO%#dE`Il>OdEV89fB6$$E#*0G!4l5**7Yx+%dKglD@I#B%I17v%clLyoANGW zn^@PoTswKs(%$TYcu~z@XwJHY8+ez8_Ac8_bf)qCncTD3^3jrRO>rNoVq>=H&R67J z9?E+B)%7kv^;`e`xBlDz?oV2elG6Ki@h*>5Aj{%w_AX=63A@pb1g((#Ux9bIf?VUp z38`Tv3)gh3SmRwbRGQ*lwxtc9YIg6|-eqhRQ@qP|9|-Z?SoIAD?U-}hRtu`nF5MNa zL!8?KSy^lE@`?Wj-C)wY+!%?!tJkpC*cXLC&7NUEl)+RUZ>f=TJ2w2YI5N@0?4Lyq z=VN%~xP^9|oY<}=M((Jp$-ZS2`gn5_zGcP|wVPG2fp0lmdTE6LpiN-8?P{gk-thX; z!rXTImKm^3_?ELl*8|T8+1L_TwDv7G9J96rL_h6Ux}I-2&6I&zV?wMDP~G~zWoG5P ze8iK!W!f^;x6DXP@hy9@CMNkS_AU37YGy-!ZYCT=SaK7eZm`%7Cl-BLtoBVeG2{*C zHUSEkPjeGL!gzlzxQS0Oiy7dtdXbB#G=~B4J`@n|FNmAiL_FQvH_c6KZ^y~h{c&V= zvPKL6!Za>Vy=G+gH!8E=30D`$?1O>Kj&lo2II%u5JDyupBeN&}{E*qTZjH>o+zn)Q ztqaM>s1-qH2>*$=zXme9+Iat}-?LL*(W@DmeX$$wE2Hh3$m~sI_CBD|0_o7+L}qUy zGrZs#yP~rou^Lf-Zz3}}1c@(iu-MNh7JWsm_Dy8A31s&0*9bDZ%q)&0v&)*pKxUuq z+W7Vt1ewh!YGCuo%rOL)Quo0H4V&2|4S}4XfTzl4_UZ0xwV8cKh0HFxx1>dJRn zUf>q=axVinNJz;Z*-p%OXN~oj-b8sv{Y>rO#OIT@aNsSDVS^pkfyyDTd|g{M0D1<#{1`T zuX^5DA~F~Z!$!70O79e}r{pk5AMb2y*EH;Y~)?2lq(_aZ4u+Ew9r3o6v^o#Q|I z?#8Z)e8NDzslst$VfI>{FneLwC^yJyx8;Y>4jY}F2Y2Ro!1AD8Wq|WNVdj@EDp6_g&apxQ1XO4E7v^YgL{^V{3 zLX}|xVJ(9sIt9K`CUQK#o2DRrGS@4foQ6i2zSrb-Wm1K2IC|f4=;9yOjo#1U zlD3>S%rdh&`G}Z1MextdcnNzL;6#BOiPFbvc!N>;vnQl(-*pom+c`d2aA*}Xo_2~KZkb55h_3f3E zKIJMxNi4O3#OsK0!;>Mm6CBY6902Zk@uTqLNNoh1Pe3 z@b+MB#l7Mm*#X?+tGApTZjMks)Kz7DOoH-bfBw$+GA z)!y&LwwP-rruni`_8#9l+hNZn|Fscgvzg%{U^~=p)9`E-DweuRVx}h#x7b>I>F54r z<{>+@rYG!QQ^6+pOO6+woLK|d2n*4ig0{`Z9C6^dCp&=;b+OR9K(VZqF+Hj6Vl-v3D^cDfuF77Zp@xpn>CMslPX3t|=vw93nfv2ov9z!q*Af4$(U$e0{8=gzsAv z5zOOx+_D?tvk$>j;MKzO%~636kTuC1t-8ehwj8_ z_X?sS9-J8Q`6?bfqQr-ITvs5wSrEZs)B^)DNqNKIw5acD2_SM~gWq~l-x-h$i-LA) zSQm<2e2SR=y6q|In=X)SLW2*R@mY#F>ia4Ko#BLp%2f?A1@ZBVmLde{Y*+;VqsOST z>5-{HRp0nwg)7q-f=ksH8tp3(AYlvwyuS(TK=AkdTnO;KhYL>79*D>H?&pG&eCsLLaXx}jwtJ7zabgtbjlhh3U zrnt0g(C%dK8ch2K*{C!Y{LPCP&(dHbYq2|M46kT7B}w@F`A%hOXablPqdh(Og8|Gt zD*$uZr3ZldoUrFid5K$)`sI$}zO!snWtUtrI07}7>5;Ok+n?quIy~@2Mh3wbPTA~M z@+_4g^MYgGS39vMP?R8I~O zEYn;`a{0_NrZO)qU|#UXO$;fG_b=o=MJ#vQTYm_9>SULX-`RK{pxG#3#lj%PM$$2j z(1Mh-mOv-mfUfp^&Pe%-l1BZMs75A({IhbHv?hKAZfUlCS_8w*?wQIMVD-Q3ykl{T zCjfTIRuh_|tOmK1BZ3`_UZ%n}lr$gyb%C$(@MC4R*%(uZ5lWy>yr`K30pwkGKI|t4 zhoVXb2bO4?*mve+2h;er7INPGbyNhILnhpS4a^xRsJK_Zv<2${V;>5##7-LX>xiA$ z`^-!hD1*ld6_!%`Dy`HG;A^_FY$@E{TD5}5c)EO*JsP1t=LbtT4G-FQc)me#A5Ro} zUX&-rHf%T%o39n6&VGjN^v6|uGPJnn=$6K%AiIoim48OH?Yw1Os*+zqopO`?f}TbQ zJ<$3xEV0sMLyu*Evh46~*`g%^tT&qzCuE|=SYjf_USlbNeI#uhl4jb0Q^V$@uYQ{* zP1G?iY(yRO3Tf}+0QkH0oi)ST{1(co%FqCm=NPW006C|jQW4nwk^qs2ka7u`h!tsx zbX-hUG*wa(0L+-Sa5E}-`wmB>!dxRePi*0?nelE-Xr%Dr6Z^MKh-W97bhhRjS($us zIxoJCGFkKDGp-_d@$(&xRC$_PjMJIUYA=+@{hcwssu4MzThj3<)36UXaZAtX*AI7A zhhw|24R*AT3Y%?Ted~obc#5i2iC+2;AX3*;CQ&hrzJ`^fEXz4p0x#`T!+Qeoux3)^ zZ7|JLF#GNrWuDB(ZRsSC?puy*ajc*a|IZDeHE z^tvt664Q{>g;gz+a^}MF-rAAAZ&VnX&U%GaYKu3h(oLH?Q4L8I785hAs{#?xx}#~f zs@82~tuM$8urQj{{|GuPPc&%kglTMXNwoU`5Pk+BKmc$AWU6EYB4HMZD7Ia+4evVx z4&O}c;CQ3FC(}AOK1RFPUT?B!aiJYkFE!K!LjUljP9z<;)~?spHKC-iKxqvq!wcsn zr|6WetSo|&Q!}Q~zbCfAL%klP#)ZruBmZuYKkJ(=s-_YAa?dL8V7odSL%iOa*lM*x zv|j&HQ-kWgnO{Xrn?2e%F?&uX!iW#Z<2A(^fu=dVq^(s+cO^QgNM5S>G%7_;gXUy} zbdlNab3_KQ>6PgI_)>6l;UZdB^{)Sqy&u4~Ow0%7v*{(tbhl1P*g+~Sto)x<()Q_w z2(RF562^Ma2Nr4v{j!o}Os`fTV4Z5Kx8HH`t`43hx%Piq#fnsBv2&0lPX z4t-Tr4Un+|aD50^uwV@yprYCq0`$wx!vdOm3#Dv;B{xwJSqQ)K)?lKOLh_ZiWRF#f zwN@v0Ta&EuK4Ss9A@aUnw*f>(rEhKh@4&|L|CmvF!*cjjPiRWpsz!5jhNKvm3@qIu zV9%!_e-U;_{SKFYIF>qW!!OF3VSctyJbbJ;@f`E@@N-6cL6X_znt^prEP!Az!n5ZI z5suRpa0z4Fqj^@@K?S-)HUaOV-v)4bPcggdBOJ%pa4tPBkyezxY91J+0}xmy2hl#2 zd7*&MrUs_Pn~Si}1$q`S@T)dlHi|&PH>_1@z2=uwu7xl+HVo8qDI-rh7;g4s{3&*Y zxr#NoOgjo2Q#w?+0~6bRjdhh3!D&;9eGIEGUy;%#EE}}*oZzEVLy3`tSb8a6mDqv? zQXAeGOJ~{++fqs-koJN(jX+8vzzgJ>(!fLtfk;D8Cl<&ird>)XKr)MVLDVqwqwOS& zN>&wY>?!)8D)b|{K$Rk-iTpL?f!Y`;&m7XrCQq2$wno=vuZVG|M=P0`=onp2W~N;d zx!KHg1zyzD60V33Q4oUa^O2{vIeJs7sLV__-n4Y;p`P}z%uF<<8;wD*x>2>633X2v zC3G-ZlrR^`qJ&{d7A34rvM3c}d8SxINlq_mCuo^UF5r#=DpGO*d3y)nE={LO zE-=dsZHpPon!S??+<<+_n)Kyr6g6;{YlPCVC?IEVPA?}vZL$eB(yGAXi2qMW>g)~p*W5?SA=?l2`l}357Qv@7_sN1+{;Q%yl6wf z`9=-rbE93fM~t;Ydp}+QJ$Gh`0}Ljlld5CMuvE<4ga=eW@N3bxb5^!kFh8p-eQjHY zJX!uhM%kaW5JyYzSka+}ZMci8jWD2H4D-0MBef^)q>ih}*U+%dV_{K5Gdxs%SYDS=D&K0jOj!ZWVlFX zu|(62*^|w-qj0y8mo$CLKq}?4joyxtgKY}aD4CMvp7rXes94`I*o|ZeXjhd~epvf+ zCo1t06nY%5#G5BOEJ2uEt;uAUYLI7?RP%;Kx8sJG0`jPW5#{gxGJ4WYm7ats{OJlp zxM(KZPyz@oAhe6W{h=pKS*~`KM-%IHx@c$$pYpU^cY#jhJvuEM2GF4A52y8UT68U~ z2rx*JbWwfZiN|wZT!M^{f+aTO$ap7R1MHkF=m1FlT;;7R+6&=ghbPyA(coHGMBv3R zos9}1w$O05`Cib83w8LV1x;NA49nxKan_?*RS6S(-9D=q%DIPOI#;t!TQT3*Z1q-b z()1A{_U*N*GOKE`s$w%XmCDLt`@7nu_(;YHPHk1iL4+`3@hya$*^K0iwGWvW)aJ&R zG12Z29hDzv=X%a!BJ5hl0)l&zqgeg?r^MbS#Bbs z>tPuAKBfsu!G)u|e2kKks_l}8i_y_W=}?P&ii4eF?xwP;QMdw6*3`}M=j~>SHLDzq z_psRcp#1Rgkfa}tlESthXS)-46{M}xIA$HlPMe|~IuPEN0mB4J#QO+j2R+be{PTvw z-^%RB?ffaJ;B2ZoaSmqpM5nItPmBkbmcY* zo(sD$cwx!4f)a=C3DEKd?8r0aORzS`_pu|LR;2v?l1%ZW#;tC=>Ki-j8}CJ!cgmu^ z@j>4>T;F)wH}0%&JmVYp*BL@PF8*^eXQ1|6)|LK#Mpyc4GY9>}z~TPtbcga3tXfK= zME5DNXy}BGAIceOZA}}#2cl@B9@+^VUZnCjntH?Q#XC4~(r5|vXqZmcV68>D+4J>Ots>q) z_PJU`JmG3WMf{)~<FXP2bX6XL;O>#j=NP65bqrdU(O|}YlNhoJYTE_C zIF+xMxlMsMpJ?PH#&?)yej~Q>);d%(xhjP356z;*`j<#}qmHJpX#orC?MMX!Wc zW=59l7gElUPbeobcqP0Os=mVXa^Kl4b7R$q4P$NfEWE=VsyDo#dgDK;Uy&jZDut>~ zbKTHeCaO33zS1D)AFs$+Y-CT-CPq)H^zE&mD1Xl<8Eu7N<1VClYd+BCR_2a8=q<@x z&te>C<0of)q)l1`mt9$Klpl$`COVo~gD={l0Tj9S{ZDE^t6thUKU^za!Yh#Z|Sw)F?yt&J$-jPT3j_ISS z(E_Fqexz#X+aIUNF{s}nhJqXvg}i;Wt4PP<{{er6;|dNkPb;kvxT)nFfWH>GUc-a3-GvR_E8 z(Bf_i*{7oMhh`(w871V6F5-4bwq>lTbBtw;_ZqZEvo(MUn=cNcdi z9C^1Gr?_WQndxhoPqcOH|L5-gqwG4*`rdu^IWyB-!yVg?&!sps_QRl>{q^ zQ|c{{ofIgN69VM+u0>b-M=Md9xGAf5EiRdWNR-6Dn21Da42WJ+E5*K5f&sBA%7nNe za!sp%dXbCiQdS)zE)Ixdz<^us=leYGyZ1gn=FDhh$F$b+>~r?n`+cAHd7k(A{l4$d zXn1T{WRk?BX)Oq0Z%R6R{ic{;EGsf9S-A4Fbx+-(IQ;B%@721VnZ^O(`uH?H8X~w! zlfG;&AbiQIE=I>OxpNc1V>(AVS?8}0ooAu*rUbCp)@$T}uoSl!yC^Zw;9uM8{%V1- znC2K@%yIw|uL-~yn!rRTul6?(0l3kDbhI>+y)MvhMzj+Fop#vd=8FjJ7E6T{`kDH&6KiNhc#*VQRes1hxt8p@vvbn>zRzt zIIck!W3EmD@nR>2Z93uS-DzcVS{RI*+3Q0mG-{ntXJ?(@bjZ01nZut#xAOUT`jvMGyK3>uoMxL4rM*OP7Q%$V{Kdd^a)Xf0yg zJkA+i)*2m_t-*-SjL(VT5YA5%ET7zBRsq8ChZIeGc6u!V1;#XY}O}Eo1l{tsIpRHxd?zByV zTw0pH4TWC-!8Wp!u50G+TUlB8=Spr1JbSY%!Pb3$Bbn=dfIqaA9o~hs!0VdsS$g78 zP&UWz&VoguVCHcKK&(#?T&zzJpqaA5iD!kAtS9FlhgPMliGo8cb&%ZDjG}Ft0zH{Ca-&ZcQu~@LaM#UfN(i>YB#Lm|U14?v&I-Y-d$H4RQ)#ixGz%bZlZwVB zu$Y$S1YMn@D*^O`uE>!!b?qM158>%r{Lwrp6Kn)-o$UGrCN-YH9ffCdcnc_u3r{dv z6=AfHlNm=Rrj093#AhsG6}o;XbbUe_Ikex#p#u`?)Qz}ESCH~c?_ZOxW5Skh&4H?T z!N#(9!Ko?~KxBRiKHsfqh}Yo27y5XSy9`yBCVWB}Br=R0{bi9+Vv^dM>TM`2YeS+p z6X}(huhm1u-Z(5c_GSSY?~QKM8!KVy%`}K+5-B|(0nIU4z#|CU6Vvfuiez?58!45~+8#?;Nh00W zyspAY_?N{c5)5+VkaqBH$dJ=`G zH^n+7IMUG<&@Q;nW?pewJQ9jATu*r| zQ4EZmTb|)Z-5b^sFjZ!ah0hY0n$8Ir2ZPXgKCx9)%FZ&#*sU?J!=ZMfwK^y^!TQ;_d0L&rSB$_Dvw3JJXbSlDMbArvNJl!OMx&)aijGkm;>cG-s_-+8hd-S4Djb7FS1>{}ojTW>C;f zzv0C3ksT8~=;xD^fZUb*_bGi_0;>MOed&t*#%XQMKEk<@5`&)Q!Vnrpi&<>j>-173 zroi2D(t@`bW(%584=C7|lNrnQQ|MYCq+EzGoj+hqKm^>zGw~V1z=~AZatb>hS-h@D zGp8iepK+rFn;A(AHZyWN6d7>w(QlENMigqe zR2A1VUCbLhNgGnv_avX{!f5q;m6N@{nvj3@nFh;eQJcaq+FNIYPxJdZg6#HGe1;}; zg1C$*JL%UG~9Bn_n5!3wnxDyXSR9jy|U=%J<4#rZeN| zCUhXX*uh#tM$+4Ahsq_C9Bf?A9{`c{rSy15q^Re|^;M^n2N`KiA6t-fX>c+v1EhNL z4dooIXK%3i_`rhR=eMsZ#wY3@Tga{(#JZM4To>`ZhV-lFCl(HqUjT7Je16969a}i8 ztkdD8da|$1?ftEN^;2C9)$W|;V}1o3T_=mwK~%w%khv%M6OHiC=87qLore1ST<=g; zUrwHz>j_ql4e$PaY4Ljg^GCkAYGg0{~MyJc+qkubxx? zI`Mry*Dm@?0h-UNt`Shq3o0p~1=)PP1&i8?nf4@)3GM&J&=vR_lz}Rn5TI^W?>`Ev z)V4SU#uW^!d^F|hj0gJ)WdQzzBE=8$Ysu@31IB|%TMBjhuM0t!`Rfb*dgspcIIn9G ztm=wxgWc+YEx+prsTMN6h>Q!jXo`)nW36DvJq0*Xwu^D84r zyUy^gyz2nov+KgNeT5DLJ>*nl@(XGisds8n+6Z4@b)oUaT9aOx+7joTW4*WA;%iMo$7|4nW)B_ z+S`67P+=KL_;{M1Ub{c--3J_)?dkW{F{cOq4b&m}FN7~)%YMsKa;>1e?9?@e zKEqm@yobXJ8CJ6Hyo=vX+uF^+Nfu++Qkl` zc01syo@;~Y*xE_MO9$b>5<9(%bsRf|{yP=v^+^IHO}@}MRtA$~V59@%))S|?Cax9r z#kG`_FoDP3A>AXg^89O4Up=zwb_;J_nbVsp`v9ir=K4(?8#OiEY|YHhN%-4BR$ZAf zrbh5Fp2MOJ<7~fDjUyico&anK3X;2?zktv+Vi%giki*N!*hjnjXh}g9g(O3J-dKL_ zeQUm1DtkbTYhJP&{_sZdg=NE3I#NNG4|yk0}C)xJAifsj7L5U7*l}3f~?rygNOsY9q7k9 zH)O92CNhUF9yXjf+MNNMM&GG-&U8&0ycX@)dz+-zsc!Ebx~_G5-=+u7vIT)K!bg6> z#xKw!W@JqU!60M-ju#qF^Rd0tS1c6Ii6!z!1@|;?llR^V`YOX6pyGA`1{Lqn6)K`= zjEak*Q#OLW$G;CS6yZlTZUqb!XTA4PV}eBdRB3XQ zkO;;lm{P`;WiD(U4bGq{Nq0L1`>{tOul2rle?sSQj0wh8e#eo=_WxDw`+IM%(^RgV&Ubc?+k+M+Mpa`~9UupEe6@eZ) z{+|BZvu}MTu~-@pvYoNzw$kr8y%MPSP`j=H@)TM9zwb_ty&S>ayIRnOkOFEy(cqeoV)Y_F#~V*QrM54zL7 zK~0f~&tt%l&AzjHySj5RcMpqn1HJ)M2q>9WSUFhb?ro$(c3@2qNVj$SX5~ji7jsgE ze;}xMRz`35DuxvOB4x+m&}XoOTu@a^TAOI5SwL1my}N^jdd^tYpt&0)=+a}^s~+2* zz5l4{T2m~d8#%o{)u)UDUA+$}@@DUK#F3@ZjU|KjkW?{w zJ@}Hb0iM1U+hjW*%Wg7&j3joOpLWT@Uc?IP_Bau?{Fg1dsZo*j5kwQsfLPcs!yuwv zGUD6X>B-jIIjlic$5u?T(h4(Xbf9e9K#{5mTFfYaKM2@$$7&hv$Fe&rV^r$(m5*h& zgg#Tl94hjXu~c~VSE%;NQAnimpEp^TnRg7f^d?KkY2wfgc$?g zW`UW}Acc%C6L@MEHK29C+5wo39Dc=Si|NZ}N!Oh)mvV~k=6@F)YkP%VA2N!*VHbx< zlW64CP}1ycP}u;6z%Cjh++8$6)(${+cqiUTCLpukxs_N{s7D;^ARk ziK?8`^|m|Hhjb+qcS2XPeaCgZgBXLZcuWuI%Kl)-bY+W}qqq+ z?LG8$F~s#y4lLL2V3q|_9u+NPQFE&M_Z6`i3=s`PCw#*=BLpEE4-OHR<85MeMZimN zS*!)P6!8;W7IOiv6~5@B_WoM|!jA64k+c}ocMRaS009A-?F|&rFTl`AQiU`$) z(Jg(IaAIl{$Lb*A)!q9#dtw*@>xkR!98#c-{$!$EkF(b3B^qy>Lg z%4)wOnH#;15>x~%E6tr7MCpQnp!Hv?6ZZg)dEnqqfCIMUV-fx^vjNczJf_4$ODYB&|+Xd z0o}G~dguPW#WeF2Xx-*9N=QH7_efr|kcmY}pZpLOg8WMh5c^05V<9rdMq?p}@DKwr z%^hD{_*dauAm~Y&IyB&4ovI%McLuQn z#4PEp_wR#ng`agOyYHP|c3?|ejq>CY5c(uf60e(&R+yMgfnsDNykQv%R?ggS5o8H& zqQbx{Sa2!tGndj*9C9hrL6^diA5t9db;lG3BrDu*k2D+8-B%iif%L=1p%pR!m+`KM zKMbnFX*my@I2y;e^v84&Z$l5r&lr1Bx*y#rMgOHl^4g zAMg%6Ig$&wI|S%E9{KMKNB&J-Dp2J*&c9|10TrihFNu^}F5vl;4H|=f{Bu^M2xi~? zH<8xM+QdGG*LNd@tJwj1kix8~_jyQgG%_3?&$s#L!^DBu&w(~v^X;QakN0J1w9MI@WiO=(XcS8 z;Kd5gid|))0$3f@f={vg z;f7k!s9b8ngQf+wQEba&j9A2RlUTU>VDD`fCc;!w;}&BK_ks=#-vaZj(a^yG9e6H1 zD0dy@x0d#Cc}nGXFgqmWXOs~UgW}7E6yMuyo}&1IpCi51&awf;rwE%XJ`^w@BhQ*< zMUW@YFGOR-lDy7HV7thj1F0Y-e0!YWii-t+V)yN${eb8w%N!-8vSo0D1nTyLAGZER$L zpCQxhZ2|rP(@T;^rdMUM(5JY-O)r5iH~F;OQyw~@EAFRUV#Fbv#v5@=*-aX8OgN`KHA5c&Y zwQu_kXg7id&_fsxrPRtBaz*&w;$p$K78N7m7HhK0yEh!hN5?v%%!2{o14*~rmIXy< z?d7pDSvx>p0>K&>BAPg-(!$D=TvnV#7m?$W<=)7Oh=3a_WvPj6n39aq>iDb>9Rq6z zVF4^nY}pWgIcZ(FrTK7b;g=KKLh7AN&C*2h^{TorY+fvzH$}sE5Qcq?6%`1jD=JOt z3U>ZUYx4i7^%;IA-XP^fahkS}1!5V3I<$wIz&k@1Bsx8ck{Ay{V(i3P*1@hMof!oD zYG700(U0TwJGXH4^^7<4RFo=M9v{(ZvxeBe||8H z_NQT^s&Gc_Pf`k|Pk_&~zwHa8poGFS^eN@h!QgziA-1qT->tZG67mSViT!D7rq;7R zRor3rXU7(2PfeQv>NvB)k7(7DU})Q<$wnyNtt)6=&OaapJ&S@a>OLwqtwzOgFt%g) z2|H54R4Qs>8lqp^!go~}D+UY~+XN9616Kcm_%J&M@i8m2(rq+#|Dd{85*ZGNhDc#j zZ=!q4J$v_9RuQ3`l^D85hYggSG?neNA{^7KKdSDx(>=VomF~?M9y59i>M{CVq5Di% zM!!u94z2jcx_?-?>ki!)_(;K0a?ew_P`1 z@Lhj#r)T@hNtuc*%t6$nnS)-aJY)`kvCg!UVGegScg5NBy;f)p|ah%<0AjU$3xQE2gp!ObQ+n6Cym=IplKtFlZblH|Tj z3JUlz#WvBtLO}^lbeT5WwH`~yChSCO-CZpZ2yp_&f}0 z$ryErArS}0IEaJo*aFw{zp|#gGzEc|ymZOD1JBB%8pGg2&otfZx@7Z~QrTc-exWAz z4BMtEo`|+Ld&8$#wUG)GWOr#`*3xYQ^U#WOwmZcz9SqNm%knJ)rR+Kz(qN!JfInnT zbr<^gwkt`ZA|Q>Pn#-M*!|hcLsZ>@NQ*~EJ7F+5T-eI$bd$X3ED| zSK{Y-kTE`_f)hBkqvZ4KfeiA5oU(5WP$TgT3^8~*nlW}mw-GYNthuaZHMbFoM%MEu zJ)~Y)$bk4G6`Vc+Q{__8F8pR~TxGO}cJEhD=tWMpv=FX(qNy61Ie z#gt`e2>_qfcO=_DrWOfjnOZWX3fP-P6f?D0K?@dz3oKxnTBNQS5T;6DS}ZOpEYH|3 z3>25|ATT6f*DA~DSf3~b@!YMUM3#yrMaJZAW5}8p2XeSTY&l#Ywj8du>5bmqMJ)0V zqJPRvT^OS9?kYK4vVOzfoo8kNW<&4JpEQ?D`vF&TxW&G|4J#I@Iuf5Rx0v>`R0+%ON01nx?3B(xWB3|T)33yBQpsF?!&7<>v^>48-hK*p`#I=lhtnC5EU-wax_O= zj;5-7+~qK1U+ed9IhqKenyUZW9%9yJuo{krzy`3071Dtkin$zWr0lZ%6gnSqI-2dC zaHJh!W22RwU=boX9a-UYe5%;T)i4$yg3o!mNDzUH9$a0@$B!{SL+LPW2_s=O-= zd+Dae*Y=`!AJV-Y-r1c#)N#Z2M8^%^;~iqMNO~)mHoN;%vb)(j)r;q^zI*eP#&mD? zHr-p1JKdY}L-(1ytJ3WMud#Brs6ZV;rr}9@zKMgNFXT8@N}LbY*aAvf77j$gMygrk zn$DQxI*7D?YY@EKXo+TUR;4a#X50Mj$+ zElG9j)CXawZ(RM0c#U2~)k;|H&JucvkPxh=^<3bfVaovq&ZeTZ~|J>A25XYPHzc7p$rwTQ2Y_U73xuAl9DZ>+y~s3`QIdrcAp3K+mjp zdbjBcBVhR420CtFSA(Wh=8mi>AE3*Hg>Xn?RSdPbpmf+oL7QNLJaB+%ZA&w$yAsm1 zMOZ|_Khi*!lYb~dMaj02NhrfR67ls~v2DTI1P6?WV@Noqqms)#$%C}GoP2~*7plx| z5~H9PEbC)#hB1JRlXr15Z0p?8buP-kk+I_>!bVeA<&B1|p($)=W)5K_80vNf(6@;f z+;`P_o6$+@zU!%q+%0y_cHdR9R~{%A`L6cW<+q|?bJbfZfPdUQ* z>c{o1m`pWRv-GE(j?tlNOp`9_y^6z21{Me+x+@jmLF+`%bwV%lgljaX?bm00XOdZ* z_asaG;1^e-L5*yxJyouJ%*HB_>tTCH@OKR#uzH)o(LyrDIhv#X+npf z4EWbySXt8%o(5htR+JBx>^x}n#O_ZJ{XUwq`a4Kha4xCixR)ptM@l!KldO_x^ts2o z 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

gV;<05yB4)#Lhkow6r}u(1%Ivd*W9 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 {lJ5$Qeq&%$))j*&y*&2Jp0-_ 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 I*Ie`e2ZBqFRsaA1 literal 422710 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Μ8b7 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�CQgU+Um%JNUG~IRL(q8hkg4 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 From b8530be6bf7db1c6398cd8bed60698fd1d637907 Mon Sep 17 00:00:00 2001 From: nhpd Date: Thu, 22 Aug 2024 17:12:57 +0400 Subject: [PATCH 18/60] fix tests after changing reflect.wasm file --- wasmbinding/test/custom_message_test.go | 27 ++++++++++++------------ wasmbinding/testdata/reflect.wasm | Bin 579620 -> 579805 bytes 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index e6726d219..da6a314ad 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -3,6 +3,7 @@ package test import ( "encoding/json" "fmt" + contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" "testing" "cosmossdk.io/math" @@ -543,7 +544,7 @@ func (suite *CustomMessengerTestSuite) TestSubmitTx() { suite.NoError(err) var response ictxtypes.MsgSubmitTxResponse - err = json.Unmarshal(data, &response) + err = response.Unmarshal(data) suite.NoError(err) suite.Equal(uint64(1), response.SequenceId) suite.Equal("channel-2", response.Channel) @@ -594,11 +595,10 @@ func (suite *CustomMessengerTestSuite) TestSoftwareUpgradeProposal() { data, err := suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) - expected, err := json.Marshal(&admintypes.MsgSubmitProposalResponse{ - ProposalId: 1, - }) + var expected admintypes.MsgSubmitProposalResponse + err = expected.Unmarshal(data) suite.NoError(err) - suite.Equal(expected, data) + suite.Equal(expected.ProposalId, uint64(1)) // Test with other proposer that is not admin should return failure _, err = suite.executeNeutronMsg(anotherContract, msg) @@ -623,11 +623,10 @@ func (suite *CustomMessengerTestSuite) TestSoftwareUpgradeProposal() { data, err = suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) - expected, err = json.Marshal(&admintypes.MsgSubmitProposalResponse{ - ProposalId: 2, - }) + var expected2 admintypes.MsgSubmitProposalResponse + err = expected2.Unmarshal(data) suite.NoError(err) - suite.Equal(expected, data) + suite.Equal(expected2.ProposalId, uint64(2)) } func (suite *CustomMessengerTestSuite) TestTooMuchProposals() { @@ -745,9 +744,10 @@ func (suite *CustomMessengerTestSuite) TestResubmitFailureAck() { data, err := suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) - expected, err := json.Marshal(&bindings.ResubmitFailureResponse{}) + var expected contractmanagertypes.Failure + err = expected.Unmarshal(data) suite.NoError(err) - suite.Equal(expected, data) + suite.Equal(expected.Id, failureID) } func (suite *CustomMessengerTestSuite) TestResubmitFailureTimeout() { @@ -769,9 +769,10 @@ func (suite *CustomMessengerTestSuite) TestResubmitFailureTimeout() { data, err := suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) - expected, err := json.Marshal(&bindings.ResubmitFailureResponse{FailureId: failureID}) + var expected contractmanagertypes.Failure + err = expected.Unmarshal(data) suite.NoError(err) - suite.Equal(expected, data) + suite.Equal(expected.Id, failureID) } func (suite *CustomMessengerTestSuite) TestResubmitFailureFromDifferentContract() { diff --git a/wasmbinding/testdata/reflect.wasm b/wasmbinding/testdata/reflect.wasm index df893365f3253e94b0369edb5598cc4fc88bafcc..808c6572bcd92c255baf896be4b598c1b6f12dd7 100644 GIT binary patch delta 28585 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 i7SyFZo_p}HI Date: Thu, 22 Aug 2024 17:36:21 +0400 Subject: [PATCH 19/60] add new tests for unordered --- wasmbinding/test/custom_message_test.go | 3 +- x/feeburner/genesis_test.go | 1 + x/interchaintxs/keeper/msg_server_test.go | 62 +++++++++++++++++++++-- 3 files changed, 62 insertions(+), 4 deletions(-) diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index da6a314ad..446c7159f 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -3,9 +3,10 @@ package test import ( "encoding/json" "fmt" - contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" "testing" + contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" + "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" admintypes "github.com/cosmos/admin-module/v2/x/adminmodule/types" diff --git a/x/feeburner/genesis_test.go b/x/feeburner/genesis_test.go index 39cac8755..4287929a5 100644 --- a/x/feeburner/genesis_test.go +++ b/x/feeburner/genesis_test.go @@ -4,6 +4,7 @@ import ( "testing" "cosmossdk.io/math" + "github.com/neutron-org/neutron/v4/app/config" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/interchaintxs/keeper/msg_server_test.go b/x/interchaintxs/keeper/msg_server_test.go index d06aa20ae..a04afe5bb 100644 --- a/x/interchaintxs/keeper/msg_server_test.go +++ b/x/interchaintxs/keeper/msg_server_test.go @@ -33,6 +33,10 @@ import ( const TestFeeCollectorAddr = "neutron1dua3d89szsmd3vwg0y5a2689ah0g4x68ps8vew" +const channelID = "channel-0" + +var portID = "icacontroller-" + testutil.TestOwnerAddress + ICAId + func TestMsgRegisterInterchainAccountValidate(t *testing.T) { icak, ctx := testkeeper.InterchainTxsKeeper(t, nil, nil, nil, nil, nil, nil, func(_ sdk.Context) string { return TestFeeCollectorAddr @@ -157,8 +161,61 @@ func TestRegisterInterchainAccount(t *testing.T) { require.ErrorContains(t, err, "failed to charge fees to pay for RegisterInterchainAccount msg") require.Nil(t, resp) - channelID := "channel-0" - portID := "icacontroller-" + testutil.TestOwnerAddress + ICAId + wmKeeper.EXPECT().HasContractInfo(ctx, contractAddress).Return(true) + wmKeeper.EXPECT().GetContractInfo(ctx, contractAddress).Return(&wasmtypes.ContractInfo{CodeID: 1}) + bankKeeper.EXPECT().SendCoins(ctx, sdk.MustAccAddressFromBech32(msgRegAcc.FromAddress), sdk.MustAccAddressFromBech32(TestFeeCollectorAddr), msgRegAcc.RegisterFee) + icaMsgServer.EXPECT().RegisterInterchainAccount(ctx, msgRegICA).Return(&icacontrollertypes.MsgRegisterInterchainAccountResponse{ + ChannelId: channelID, + PortId: portID, + }, nil) + icaKeeper.EXPECT().SetMiddlewareEnabled(ctx, portID, msgRegAcc.ConnectionId) + resp, err = icak.RegisterInterchainAccount(ctx, &msgRegAcc) + require.NoError(t, err) + require.Equal(t, types.MsgRegisterInterchainAccountResponse{ + ChannelId: channelID, + PortId: portID, + }, *resp) +} + +func TestRegisterInterchainAccountUnordered(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + icaKeeper := mock_types.NewMockICAControllerKeeper(ctrl) + icaMsgServer := mock_types.NewMockICAControllerMsgServer(ctrl) + wmKeeper := mock_types.NewMockWasmKeeper(ctrl) + bankKeeper := mock_types.NewMockBankKeeper(ctrl) + icak, ctx := testkeeper.InterchainTxsKeeper(t, wmKeeper, nil, icaKeeper, icaMsgServer, nil, bankKeeper, func(_ sdk.Context) string { + return TestFeeCollectorAddr + }) + + msgRegAcc := types.MsgRegisterInterchainAccount{ + FromAddress: testutil.TestOwnerAddress, + ConnectionId: "connection-0", + InterchainAccountId: "ica0", + Ordering: channeltypes.UNORDERED, // return unordered + } + contractAddress := sdk.MustAccAddressFromBech32(msgRegAcc.FromAddress) + icaOwner := types.NewICAOwnerFromAddress(contractAddress, msgRegAcc.InterchainAccountId) + + wmKeeper.EXPECT().HasContractInfo(ctx, contractAddress).Return(false) + resp, err := icak.RegisterInterchainAccount(ctx, &msgRegAcc) + require.ErrorContains(t, err, "is not a contract address") + require.Nil(t, resp) + + wmKeeper.EXPECT().HasContractInfo(ctx, contractAddress).Return(true) + wmKeeper.EXPECT().GetContractInfo(ctx, contractAddress).Return(&wasmtypes.ContractInfo{CodeID: 1}) + resp, err = icak.RegisterInterchainAccount(ctx, &msgRegAcc) + require.ErrorContains(t, err, "failed to charge fees to pay for RegisterInterchainAccount msg") + require.Nil(t, resp) + + msgRegAcc.RegisterFee = sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(1_000_000))) + + msgRegICA := &icacontrollertypes.MsgRegisterInterchainAccount{ + Owner: icaOwner.String(), + ConnectionId: msgRegAcc.ConnectionId, + Version: "", + Ordering: channeltypes.UNORDERED, + } wmKeeper.EXPECT().HasContractInfo(ctx, contractAddress).Return(true) wmKeeper.EXPECT().GetContractInfo(ctx, contractAddress).Return(&wasmtypes.ContractInfo{CodeID: 1}) @@ -441,7 +498,6 @@ func TestSubmitTx(t *testing.T) { require.ErrorContains(t, err, "MsgSubmitTx contains more messages than allowed") submitMsg.Msgs = []*codectypes.Any{&cosmosMsg} - portID := "icacontroller-" + testutil.TestOwnerAddress + ICAId wmKeeper.EXPECT().HasContractInfo(ctx, contractAddress).Return(true) icaKeeper.EXPECT().GetActiveChannelID(ctx, "connection-0", portID).Return("", false) resp, err = icak.SubmitTx(ctx, &submitMsg) From 09031961a8a29c0778f35159302d722aa8a7b33a Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Thu, 22 Aug 2024 17:57:39 -0400 Subject: [PATCH 20/60] Fix limit order cancel accounting --- x/dex/keeper/cancel_limit_order.go | 20 ++++-- .../integration_cancellimitorder_test.go | 64 +++++++++++++++++++ .../keeper/integration_withdrawfilled_test.go | 25 +++++++- 3 files changed, 102 insertions(+), 7 deletions(-) diff --git a/x/dex/keeper/cancel_limit_order.go b/x/dex/keeper/cancel_limit_order.go index 8c3af443e..5680c0699 100644 --- a/x/dex/keeper/cancel_limit_order.go +++ b/x/dex/keeper/cancel_limit_order.go @@ -6,6 +6,7 @@ import ( sdkerrors "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + math_utils "github.com/neutron-org/neutron/v4/utils/math" "github.com/neutron-org/neutron/v4/x/dex/types" ) @@ -78,11 +79,22 @@ func (k Keeper) ExecuteCancelLimitOrder( makerAmountToReturn := tranche.RemoveTokenIn(trancheUser) _, takerAmountOut := tranche.Withdraw(trancheUser) - trancheUser.SharesWithdrawn = trancheUser.SharesOwned - - // Remove the canceled shares from the limitOrder + // Remove the canceled shares from the maker side of the limitOrder tranche.TotalMakerDenom = tranche.TotalMakerDenom.Sub(trancheUser.SharesOwned) - tranche.TotalTakerDenom = tranche.TotalTakerDenom.Sub(takerAmountOut) + + // Calculate total number of shares removed previously withdrawn by the user (denominated in takerDenom) + sharesWithdrawnTakerDenom := math_utils.NewPrecDecFromInt(trancheUser.SharesWithdrawn). + Quo(tranche.PriceTakerToMaker). + TruncateInt() + + // Calculate the total amount removed including prior withdrawals (denominated in takerDenom) + totalAmountOutTakerDenom := sharesWithdrawnTakerDenom.Add(takerAmountOut) + + // Decrease the tranche TotalTakerDenom by the amount being removed + tranche.TotalTakerDenom = tranche.TotalTakerDenom.Sub(totalAmountOutTakerDenom) + + // Set TrancheUser to 100% shares withdrawn + trancheUser.SharesWithdrawn = trancheUser.SharesOwned if !makerAmountToReturn.IsPositive() && !takerAmountOut.IsPositive() { return sdk.Coin{}, sdk.Coin{}, nil, sdkerrors.Wrapf(types.ErrCancelEmptyLimitOrder, "%s", tranche.Key.TrancheKey) diff --git a/x/dex/keeper/integration_cancellimitorder_test.go b/x/dex/keeper/integration_cancellimitorder_test.go index 9c12b8d0f..f72a444d6 100644 --- a/x/dex/keeper/integration_cancellimitorder_test.go +++ b/x/dex/keeper/integration_cancellimitorder_test.go @@ -384,3 +384,67 @@ func (s *DexTestSuite) TestCancelJITNextBlock() { s.aliceCancelsLimitSellFails(trancheKey, types.ErrActiveLimitOrderNotFound) s.assertAliceBalances(0, 0) } + +func (s *DexTestSuite) TestWithdrawThenCancel() { + s.fundAliceBalances(50, 0) + s.fundBobBalances(50, 0) + s.fundCarolBalances(0, 40) + + // // GIVEN alice and bob each limit sells 50 TokenA + trancheKey := s.aliceLimitSells("TokenA", 0, 50) + s.bobLimitSells("TokenA", 0, 50) + + s.carolLimitSells("TokenB", -1, 10, types.LimitOrderType_FILL_OR_KILL) + + // WHEN alice withdraws and cancels her limit order + s.aliceWithdrawsLimitSell(trancheKey) + s.aliceCancelsLimitSell(trancheKey) + s.assertAliceBalances(45, 5) + + s.bobWithdrawsLimitSell(trancheKey) + s.assertBobBalances(0, 5) + s.bobCancelsLimitSell(trancheKey) + s.assertBobBalances(45, 5) +} + +func (s *DexTestSuite) TestWithdrawThenCancel2() { + s.fundAliceBalances(50, 0) + s.fundBobBalances(50, 0) + s.fundCarolBalances(0, 40) + + // // GIVEN alice and bob each limit sells 50 TokenA + trancheKey := s.aliceLimitSells("TokenA", 0, 50) + s.bobLimitSells("TokenA", 0, 50) + + s.carolLimitSells("TokenB", -1, 10, types.LimitOrderType_FILL_OR_KILL) + + // WHEN alice withdraws and cancels her limit order + s.aliceWithdrawsLimitSell(trancheKey) + s.aliceCancelsLimitSell(trancheKey) + s.assertAliceBalances(45, 5) + + s.bobCancelsLimitSell(trancheKey) + s.assertBobBalances(45, 5) +} + +func (s *DexTestSuite) TestWithdrawThenCancelLowTick() { + s.fundAliceBalances(50, 0) + s.fundBobBalances(50, 0) + s.fundCarolBalances(0, 40) + + // // GIVEN alice and bob each limit sells 50 TokenA + trancheKey := s.aliceLimitSells("TokenA", 20000, 50) + s.bobLimitSells("TokenA", 20000, 50) + + s.carolLimitSells("TokenB", -20001, 10, types.LimitOrderType_FILL_OR_KILL) + + // WHEN alice withdraws and cancels her limit order + s.aliceWithdrawsLimitSell(trancheKey) + s.aliceCancelsLimitSell(trancheKey) + s.assertAliceBalancesInt(sdkmath.NewInt(13058413), sdkmath.NewInt(4999999)) + + s.bobWithdrawsLimitSell(trancheKey) + s.assertBobBalancesInt(sdkmath.ZeroInt(), sdkmath.NewInt(4999999)) + s.bobCancelsLimitSell(trancheKey) + s.assertBobBalancesInt(sdkmath.NewInt(13058413), sdkmath.NewInt(4999999)) +} diff --git a/x/dex/keeper/integration_withdrawfilled_test.go b/x/dex/keeper/integration_withdrawfilled_test.go index 8d8ba338b..97df676c0 100644 --- a/x/dex/keeper/integration_withdrawfilled_test.go +++ b/x/dex/keeper/integration_withdrawfilled_test.go @@ -386,8 +386,27 @@ func (s *DexTestSuite) TestWithdrawPartiallyGTTFilledCancelled() { s.False(found, "Alice's LimitOrderTrancheUser not removed") } -// testcancel unfilled +func (s *DexTestSuite) TestWithdrawInactive() { + s.fundAliceBalances(10, 0) + s.fundBobBalances(0, 20) -// test withdraw expired + // GIVEN Alice places an expiring limit order of A + trancheKey := s.aliceLimitSellsGoodTil("TokenA", 0, 10, time.Now()) + + // Bob trades through half of it + s.bobLimitSells("TokenB", -1, 5) + + // Alice withdraws the profits + s.aliceWithdrawsLimitSell(trancheKey) + s.assertAliceBalances(0, 5) + + // bob swap through more + s.bobLimitSells("TokenB", -1, 4) -// how does cancel withdraw work does it call into was filled + // WHEN it is purged + s.App.DexKeeper.PurgeExpiredLimitOrders(s.Ctx, time.Now()) + + // THEN alice can withdraw the expected amount + s.aliceWithdrawsLimitSell(trancheKey) + s.assertAliceBalances(1, 9) +} From 5c3d8f19a0c47dbd8644257536279f55cbe8b40f Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Sun, 25 Aug 2024 15:41:01 +0300 Subject: [PATCH 21/60] make execution_stage field an array of stages --- proto/neutron/cron/query.proto | 6 + proto/neutron/cron/schedule.proto | 16 +- proto/neutron/cron/tx.proto | 9 +- proto/neutron/cron/v1/schedule.proto | 5 +- wasmbinding/bindings/msg.go | 8 +- wasmbinding/message_plugin.go | 11 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 3 +- x/cron/keeper/keeper.go | 36 ++-- x/cron/keeper/keeper_test.go | 73 +++++--- x/cron/keeper/msg_server.go | 2 +- x/cron/keeper/msg_server_test.go | 44 ++++- x/cron/migrations/v2/store.go | 2 +- x/cron/migrations/v2/store_test.go | 2 +- x/cron/module.go | 4 +- x/cron/types/query.pb.go | 6 + x/cron/types/schedule.pb.go | 186 +++++++++++++------- x/cron/types/tx.go | 4 + x/cron/types/tx.pb.go | 198 +++++++++++++++------- x/cron/types/v1/schedule.pb.go | 5 +- 20 files changed, 427 insertions(+), 195 deletions(-) diff --git a/proto/neutron/cron/query.proto b/proto/neutron/cron/query.proto index 401e9ce9d..415d7300f 100644 --- a/proto/neutron/cron/query.proto +++ b/proto/neutron/cron/query.proto @@ -30,25 +30,31 @@ service Query { // this line is used by starport scaffolding # 2 } +// QueryParamsRequest is the request type for the Query/Params RPC method. message QueryParamsRequest {} +// QueryParamsResponse is the response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } +// QueryGetScheduleRequest is the request type for the Query/Schedule RPC method. message QueryGetScheduleRequest { string name = 1; } +// QueryGetScheduleResponse is the response type for the Query/Params RPC method. message QueryGetScheduleResponse { Schedule schedule = 1 [(gogoproto.nullable) = false]; } +// QuerySchedulesRequest is the request type for the Query/Schedules RPC method. message QuerySchedulesRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } +// QuerySchedulesResponse is the response type for the Query/Params RPC method. message QuerySchedulesResponse { repeated Schedule schedules = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index 88baf0b8a..920d0fc38 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -7,24 +7,27 @@ option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; // ExecutionStage defines when messages will be executed in the block enum ExecutionStage { - BEGIN_BLOCKER = 0; - END_BLOCKER = 1; - BOTH_BLOCKERS = 2; + // Execution at the end of the block + EXECUTION_STAGE_END_BLOCKER = 0; + // Execution at the beginning of the block + EXECUTION_STAGE_BEGIN_BLOCKER = 1; } +// Schedule defines the schedule for execution message Schedule { // Name of schedule string name = 1; // Period in blocks uint64 period = 2; - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; - // Execution stage when messages will be executed - ExecutionStage execution_stage = 5; + // Execution stages when messages will be executed + repeated ExecutionStage execution_stages = 5 [(gogoproto.nullable) = false]; } +// MsgExecuteContract defines the contract and the message to pass message MsgExecuteContract { // Contract is the address of the smart contract string contract = 1; @@ -32,6 +35,7 @@ message MsgExecuteContract { string msg = 2; } +// ScheduleCount defines the number of current schedules message ScheduleCount { // Count is the number of current schedules int32 count = 1; diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index fde954369..9db1d58dc 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -32,11 +32,14 @@ message MsgAddSchedule { // Authority is the address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - + // Name of the schedule string name = 2; + // Period in blocks uint64 period = 3; + // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - ExecutionStage execution_stage = 5; + // Execution stages when messages will be executed + repeated ExecutionStage execution_stages = 5 [(gogoproto.nullable) = false]; } // MsgAddScheduleResponse defines the response structure for executing a @@ -50,7 +53,7 @@ message MsgRemoveSchedule { // Authority is the address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - + // Name of the schedule string name = 2; } diff --git a/proto/neutron/cron/v1/schedule.proto b/proto/neutron/cron/v1/schedule.proto index b1f824918..ec7494745 100644 --- a/proto/neutron/cron/v1/schedule.proto +++ b/proto/neutron/cron/v1/schedule.proto @@ -5,17 +5,19 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types/v1"; +// Schedule defines the schedule for execution message Schedule { // Name of schedule string name = 1; // Period in blocks uint64 period = 2; - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; } +// MsgExecuteContract defines the contract and the message to pass message MsgExecuteContract { // Contract is the address of the smart contract string contract = 1; @@ -23,6 +25,7 @@ message MsgExecuteContract { string msg = 2; } +// ScheduleCount defines the number of current schedules message ScheduleCount { // Count is the number of current schedules int32 count = 1; diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index c1697401d..4f245ce0d 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -195,10 +195,10 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` - ExecutionStage string `json:"execution_stage"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` + ExecutionStages []string `json:"execution_stages"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 73c9282c9..799e48612 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -985,15 +985,12 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - var executionStage crontypes.ExecutionStage - - if v, ok := crontypes.ExecutionStage_value[addSchedule.ExecutionStage]; !ok { - executionStage = crontypes.ExecutionStage_END_BLOCKER - } else { - executionStage = crontypes.ExecutionStage(v) + executionStages := make([]crontypes.ExecutionStage, 0, len(addSchedule.ExecutionStages)) + for _, executionStage := range addSchedule.ExecutionStages { + executionStages = append(executionStages, crontypes.ExecutionStage(crontypes.ExecutionStage_value[executionStage])) } - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, executionStage) + err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, executionStages) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), diff --git a/x/cron/genesis.go b/x/cron/genesis.go index 525840e26..404c5dbd3 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStage) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStages) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index 8f971f63d..78afe1517 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -133,8 +133,9 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Period = 1000 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) + item.ExecutionStages = []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER} - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStages) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 0a9e8c0ce..460e5fc00 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -27,6 +27,8 @@ var ( MetricLabelSuccess = "success" MetricLabelScheduleName = "schedule_name" + + schedulesExecutionStages map[string]map[types.ExecutionStage]struct{} ) type ( @@ -47,6 +49,8 @@ func NewKeeper( accountKeeper types.AccountKeeper, authority string, ) *Keeper { + schedulesExecutionStages = make(map[string]map[types.ExecutionStage]struct{}) + return &Keeper{ cdc: cdc, storeKey: storeKey, @@ -66,42 +70,50 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // ExecuteReadySchedules gets all schedules that are due for execution (with limit that is equal to Params.Limit) // and executes messages in each one -// NOTE that errors in contract calls rollback all already executed messages func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.ExecutionStage) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) schedules := k.getSchedulesReadyForExecution(ctx) for _, schedule := range schedules { - if isExecutableAtTheStage(schedule, executionStage) { + if _, ok := schedulesExecutionStages[schedule.Name][executionStage]; ok { err := k.executeSchedule(ctx, schedule) recordExecutedSchedule(err, schedule) } } } -// AddSchedule adds new schedule to execution for every block `period`. +// AddSchedule adds a new schedule to be executed every certain number of blocks, specified in the `period`. // First schedule execution is supposed to be on `now + period` block. func (k *Keeper) AddSchedule( ctx sdk.Context, name string, period uint64, msgs []types.MsgExecuteContract, - executionStage types.ExecutionStage, + executionStages []types.ExecutionStage, ) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) } + schedulesExecutionStages[name] = make(map[types.ExecutionStage]struct{}) + execStages := make([]types.ExecutionStage, 0) + for _, executionStage := range executionStages { + if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { + executionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER + } + + if _, ok := schedulesExecutionStages[name][executionStage]; !ok { + schedulesExecutionStages[name][executionStage] = struct{}{} + execStages = append(execStages, executionStage) + } + } + schedule := types.Schedule{ Name: name, Period: period, Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block - ExecutionStage: executionStage, - } - - if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { - schedule.ExecutionStage = types.ExecutionStage_END_BLOCKER + ExecutionStages: execStages, } k.storeSchedule(ctx, schedule) @@ -116,6 +128,8 @@ func (k *Keeper) RemoveSchedule(ctx sdk.Context, name string) { return } + delete(schedulesExecutionStages, name) + k.changeTotalCount(ctx, -1) k.removeSchedule(ctx, name) } @@ -183,10 +197,6 @@ func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule return res } -func isExecutableAtTheStage(schedule types.Schedule, executionStage types.ExecutionStage) bool { - return schedule.ExecutionStage == executionStage || schedule.ExecutionStage == types.ExecutionStage_BOTH_BLOCKERS -} - // executeSchedule executes all msgs in a given schedule and changes LastExecuteHeight // if at least one msg execution fails, rollback all messages func (k *Keeper) executeSchedule(ctx sdk.Context, schedule types.Schedule) error { diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index 3042e839b..4d3cd2956 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -52,7 +52,9 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, { Name: "2_ready1", @@ -64,7 +66,9 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, { Name: "3_ready2", @@ -76,14 +80,19 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, { Name: "4_unready2", Period: 10, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, - ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }, }, { Name: "5_ready3", @@ -95,7 +104,10 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }, }, { Name: "6_ready4", @@ -107,7 +119,9 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_END_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }, }, { Name: "7_ready5", @@ -119,13 +133,16 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_BOTH_BLOCKERS, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStages) require.NoError(t, err) } @@ -148,7 +165,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) unready1, _ := k.GetSchedule(ctx, "1_unready1") ready1, _ := k.GetSchedule(ctx, "2_ready1") @@ -181,7 +198,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_END_BLOCKER) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") @@ -206,7 +223,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) ready5, _ := k.GetSchedule(ctx, "7_ready5") @@ -221,7 +238,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_END_BLOCKER) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) ready5, _ = k.GetSchedule(ctx, "7_ready5") @@ -250,7 +267,7 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, 0) + }, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER}) require.NoError(t, err) err = k.AddSchedule(ctx, "b", 7, []types.MsgExecuteContract{ @@ -258,7 +275,7 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, 1) + }, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) require.NoError(t, err) err = k.AddSchedule(ctx, "c", 7, []types.MsgExecuteContract{ @@ -266,7 +283,10 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, 2) + }, []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }) require.NoError(t, err) err = k.AddSchedule(ctx, "d", 7, []types.MsgExecuteContract{ @@ -274,11 +294,13 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, 7) + }, []types.ExecutionStage{7}) require.NoError(t, err) // second time with same name returns error - err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, 1) + err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }) require.Error(t, err) scheduleA, found := k.GetSchedule(ctx, "a") @@ -291,10 +313,13 @@ func TestAddSchedule(t *testing.T) { schedules := k.GetAllSchedules(ctx) require.Len(t, schedules, 4) - require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_BEGIN_BLOCKER) - require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_END_BLOCKER) - require.Equal(t, schedules[2].ExecutionStage, types.ExecutionStage_BOTH_BLOCKERS) - require.Equal(t, schedules[3].ExecutionStage, types.ExecutionStage_END_BLOCKER) + require.Equal(t, schedules[0].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER}) + require.Equal(t, schedules[1].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) + require.Equal(t, schedules[2].ExecutionStages, []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }) + require.Equal(t, schedules[3].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) // remove schedule works k.RemoveSchedule(ctx, "a") @@ -321,10 +346,12 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), - ExecutionStage: types.ExecutionStage_END_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, + }, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStage) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStages) require.NoError(t, err) } diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index 03f84220f..8751cd800 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -34,7 +34,7 @@ func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { + if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStages); err != nil { return nil, err } diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index c1d4b6e79..a523def37 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -32,7 +32,9 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, "authority is invalid", }, @@ -48,7 +50,9 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, "authority is invalid", }, @@ -64,7 +68,9 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, "name is invalid", }, @@ -80,21 +86,41 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, "period is invalid", }, { "empty msgs", types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{}, - ExecutionStage: types.ExecutionStage_BEGIN_BLOCKER, + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{}, + ExecutionStages: []types.ExecutionStage{ + types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, }, "msgs should not be empty", }, + { + "empty execution stages", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStages: []types.ExecutionStage{}, + }, + "execution stages should not be empty", + }, } for _, tt := range tests { diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go index 0f519a64d..c22e73fdb 100644 --- a/x/cron/migrations/v2/store.go +++ b/x/cron/migrations/v2/store.go @@ -32,7 +32,7 @@ func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetype var schedule types.Schedule cdc.MustUnmarshal(iterator.Value(), &schedule) // Set execution in EndBlocker - schedule.ExecutionStage = types.ExecutionStage_END_BLOCKER + schedule.ExecutionStages = []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER} schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ key: iterator.Key(), diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go index 9757f508a..f065837af 100644 --- a/x/cron/migrations/v2/store_test.go +++ b/x/cron/migrations/v2/store_test.go @@ -49,5 +49,5 @@ func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { // Check Schedule has correct ExecutionStage newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) - suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_END_BLOCKER) + suite.Equal(newSchedule.ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) } diff --git a/x/cron/module.go b/x/cron/module.go index b865fa43a..3471b0379 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -156,11 +156,11 @@ func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block func (am AppModule) BeginBlock(ctx sdk.Context) { - am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_BEGIN_BLOCKER) + am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) } // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { - am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_END_BLOCKER) + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) return []abci.ValidatorUpdate{}, nil } diff --git a/x/cron/types/query.pb.go b/x/cron/types/query.pb.go index c34c6c3f9..6ba041f07 100644 --- a/x/cron/types/query.pb.go +++ b/x/cron/types/query.pb.go @@ -30,6 +30,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// QueryParamsRequest is the request type for the Query/Params RPC method. type QueryParamsRequest struct { } @@ -66,6 +67,7 @@ func (m *QueryParamsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo +// QueryParamsResponse is the response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` @@ -111,6 +113,7 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +// QueryGetScheduleRequest is the request type for the Query/Schedule RPC method. type QueryGetScheduleRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -155,6 +158,7 @@ func (m *QueryGetScheduleRequest) GetName() string { return "" } +// QueryGetScheduleResponse is the response type for the Query/Params RPC method. type QueryGetScheduleResponse struct { Schedule Schedule `protobuf:"bytes,1,opt,name=schedule,proto3" json:"schedule"` } @@ -199,6 +203,7 @@ func (m *QueryGetScheduleResponse) GetSchedule() Schedule { return Schedule{} } +// QuerySchedulesRequest is the request type for the Query/Schedules RPC method. type QuerySchedulesRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -243,6 +248,7 @@ func (m *QuerySchedulesRequest) GetPagination() *query.PageRequest { return nil } +// QuerySchedulesResponse is the response type for the Query/Params RPC method. type QuerySchedulesResponse struct { Schedules []Schedule `protobuf:"bytes,1,rep,name=schedules,proto3" json:"schedules"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index d948efa4f..5599c1e91 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -27,21 +27,20 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type ExecutionStage int32 const ( - ExecutionStage_BEGIN_BLOCKER ExecutionStage = 0 - ExecutionStage_END_BLOCKER ExecutionStage = 1 - ExecutionStage_BOTH_BLOCKERS ExecutionStage = 2 + // Execution at the end of the block + ExecutionStage_EXECUTION_STAGE_END_BLOCKER ExecutionStage = 0 + // Execution at the beginning of the block + ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER ExecutionStage = 1 ) var ExecutionStage_name = map[int32]string{ - 0: "BEGIN_BLOCKER", - 1: "END_BLOCKER", - 2: "BOTH_BLOCKERS", + 0: "EXECUTION_STAGE_END_BLOCKER", + 1: "EXECUTION_STAGE_BEGIN_BLOCKER", } var ExecutionStage_value = map[string]int32{ - "BEGIN_BLOCKER": 0, - "END_BLOCKER": 1, - "BOTH_BLOCKERS": 2, + "EXECUTION_STAGE_END_BLOCKER": 0, + "EXECUTION_STAGE_BEGIN_BLOCKER": 1, } func (x ExecutionStage) String() string { @@ -52,17 +51,18 @@ func (ExecutionStage) EnumDescriptor() ([]byte, []int) { return fileDescriptor_49ace1b59de613ef, []int{0} } +// Schedule defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Period in blocks Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` - // Execution stage when messages will be executed - ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` + // Execution stages when messages will be executed + ExecutionStages []ExecutionStage `protobuf:"varint,5,rep,packed,name=execution_stages,json=executionStages,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stages,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -126,13 +126,14 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } -func (m *Schedule) GetExecutionStage() ExecutionStage { +func (m *Schedule) GetExecutionStages() []ExecutionStage { if m != nil { - return m.ExecutionStage + return m.ExecutionStages } - return ExecutionStage_BEGIN_BLOCKER + return nil } +// MsgExecuteContract defines the contract and the message to pass type MsgExecuteContract struct { // Contract is the address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` @@ -187,6 +188,7 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } +// ScheduleCount defines the number of current schedules type ScheduleCount struct { // Count is the number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` @@ -242,31 +244,32 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 383 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x4f, 0x6b, 0xe2, 0x40, - 0x1c, 0xcd, 0x68, 0x14, 0x1d, 0xd7, 0x7f, 0xb3, 0xb2, 0x04, 0x77, 0xc9, 0x06, 0x61, 0x21, 0x2c, - 0x6c, 0x02, 0xee, 0x9e, 0xf6, 0x18, 0x37, 0xe8, 0xd2, 0x56, 0x21, 0xf6, 0xd4, 0x4b, 0x88, 0x71, - 0x98, 0x04, 0x4c, 0x46, 0x32, 0x93, 0x62, 0xbf, 0x45, 0x3f, 0x96, 0x47, 0x8f, 0x3d, 0x95, 0xa2, - 0xa7, 0x7e, 0x8b, 0x92, 0x49, 0x22, 0x95, 0x5e, 0xc2, 0x7b, 0xbf, 0xf7, 0x1e, 0xbf, 0x3f, 0x19, - 0xf8, 0x35, 0xc6, 0x29, 0x4f, 0x68, 0x6c, 0xfa, 0xd9, 0x87, 0xf9, 0x01, 0x5e, 0xa7, 0x1b, 0x6c, - 0x6c, 0x13, 0xca, 0x29, 0xfa, 0x54, 0x88, 0x46, 0x26, 0x0e, 0x07, 0x84, 0x12, 0x2a, 0x04, 0x33, - 0x43, 0xb9, 0x67, 0xf4, 0x0a, 0x60, 0x63, 0x59, 0xc4, 0x10, 0x82, 0x72, 0xec, 0x45, 0x58, 0x01, - 0x1a, 0xd0, 0x9b, 0x8e, 0xc0, 0xe8, 0x0b, 0xac, 0x6f, 0x71, 0x12, 0xd2, 0xb5, 0x52, 0xd1, 0x80, - 0x2e, 0x3b, 0x05, 0x43, 0x7f, 0xa1, 0x1c, 0x31, 0xc2, 0x94, 0xaa, 0x56, 0xd5, 0x5b, 0x63, 0xcd, - 0x78, 0xdf, 0xcb, 0xb8, 0x61, 0xc4, 0xde, 0x61, 0x3f, 0xe5, 0x78, 0x42, 0x63, 0x9e, 0x78, 0x3e, - 0xb7, 0xe4, 0xfd, 0xf3, 0x77, 0xc9, 0x11, 0x19, 0x64, 0xc0, 0xcf, 0x1b, 0x8f, 0x71, 0x17, 0xe7, - 0x1e, 0x37, 0xc0, 0x21, 0x09, 0xb8, 0x22, 0x8b, 0x06, 0xfd, 0x4c, 0x2a, 0xd2, 0x33, 0x21, 0x20, - 0x1b, 0x76, 0x73, 0x6b, 0x48, 0x63, 0x97, 0x71, 0x8f, 0x60, 0xa5, 0xa6, 0x01, 0xbd, 0x33, 0xfe, - 0x76, 0xd9, 0xd6, 0x2e, 0x4d, 0xcb, 0xcc, 0xe3, 0x74, 0xf0, 0x05, 0x1f, 0x59, 0x10, 0x7d, 0x1c, - 0x0c, 0x0d, 0x61, 0xc3, 0x2f, 0x70, 0xb1, 0xf8, 0x99, 0xa3, 0x1e, 0xac, 0x46, 0x8c, 0x88, 0xcd, - 0x9b, 0x4e, 0x06, 0x47, 0x3f, 0x60, 0xbb, 0x3c, 0xd7, 0x84, 0xa6, 0x31, 0x47, 0x03, 0x58, 0xf3, - 0x33, 0x20, 0xb2, 0x35, 0x27, 0x27, 0x3f, 0xa7, 0xb0, 0x73, 0x39, 0x0c, 0xea, 0xc3, 0xb6, 0x65, - 0x4f, 0xff, 0xcf, 0x5d, 0xeb, 0x7a, 0x31, 0xb9, 0xb2, 0x9d, 0x9e, 0x84, 0xba, 0xb0, 0x65, 0xcf, - 0xff, 0x9d, 0x0b, 0x40, 0x78, 0x16, 0xb7, 0xb3, 0xb2, 0xb2, 0xec, 0x55, 0xac, 0xd9, 0xfe, 0xa8, - 0x82, 0xc3, 0x51, 0x05, 0x2f, 0x47, 0x15, 0x3c, 0x9e, 0x54, 0xe9, 0x70, 0x52, 0xa5, 0xa7, 0x93, - 0x2a, 0xdd, 0x19, 0x24, 0xe4, 0x41, 0xba, 0x32, 0x7c, 0x1a, 0x99, 0xc5, 0x15, 0x7e, 0xd1, 0x84, - 0x94, 0xd8, 0xbc, 0xff, 0x63, 0xee, 0xf2, 0x67, 0xc1, 0x1f, 0xb6, 0x98, 0xad, 0xea, 0xe2, 0x87, - 0xff, 0x7e, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xed, 0x05, 0x84, 0xca, 0x33, 0x02, 0x00, 0x00, + // 396 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x41, 0x8b, 0xd3, 0x40, + 0x18, 0xcd, 0x98, 0x74, 0xd9, 0x1d, 0x75, 0xad, 0xe3, 0x22, 0x61, 0xab, 0x69, 0x2c, 0x08, 0x41, + 0x30, 0x81, 0xea, 0xc9, 0x9b, 0x89, 0x43, 0x5b, 0xb4, 0x2d, 0xa4, 0x15, 0xc4, 0x4b, 0x48, 0xd3, + 0x61, 0x12, 0x68, 0x32, 0x25, 0x33, 0x91, 0xfa, 0x2f, 0xfc, 0x59, 0x3d, 0xf6, 0xe8, 0x49, 0xa4, + 0xfd, 0x05, 0xfe, 0x03, 0xc9, 0x64, 0x5a, 0xac, 0x7b, 0x19, 0xde, 0x37, 0xef, 0x3d, 0xde, 0xc7, + 0xe3, 0x83, 0x9d, 0x82, 0x54, 0xa2, 0x64, 0x85, 0x97, 0xd4, 0x0f, 0x4f, 0x52, 0xb2, 0xac, 0x56, + 0xc4, 0x5d, 0x97, 0x4c, 0x30, 0xf4, 0x40, 0x91, 0x6e, 0x4d, 0xde, 0xde, 0x50, 0x46, 0x99, 0x24, + 0xbc, 0x1a, 0x35, 0x9a, 0xde, 0x1f, 0x00, 0x2f, 0x67, 0xca, 0x86, 0x10, 0x34, 0x8a, 0x38, 0x27, + 0x26, 0xb0, 0x81, 0x73, 0x15, 0x4a, 0x8c, 0x9e, 0xc2, 0x8b, 0x35, 0x29, 0x33, 0xb6, 0x34, 0xef, + 0xd9, 0xc0, 0x31, 0x42, 0x35, 0xa1, 0x77, 0xd0, 0xc8, 0x39, 0xe5, 0xa6, 0x6e, 0xeb, 0xce, 0xfd, + 0xbe, 0xed, 0xfe, 0x9b, 0xe5, 0x8e, 0x39, 0xc5, 0x1b, 0x92, 0x54, 0x82, 0x04, 0xac, 0x10, 0x65, + 0x9c, 0x08, 0xdf, 0xd8, 0xfe, 0xea, 0x6a, 0xa1, 0xf4, 0x20, 0x17, 0x3e, 0x59, 0xc5, 0x5c, 0x44, + 0xa4, 0xd1, 0x44, 0x29, 0xc9, 0x68, 0x2a, 0x4c, 0x43, 0x06, 0x3c, 0xae, 0x29, 0xe5, 0x1e, 0x4a, + 0x02, 0x8d, 0x61, 0xbb, 0x91, 0x66, 0xac, 0x88, 0xb8, 0x88, 0x29, 0xe1, 0x66, 0xcb, 0xd6, 0x9d, + 0xeb, 0xfe, 0xb3, 0xf3, 0x5c, 0x7c, 0x54, 0xcd, 0x6a, 0x91, 0xca, 0x7c, 0x44, 0xce, 0x7e, 0x79, + 0xcf, 0x87, 0xe8, 0xee, 0x82, 0xe8, 0x16, 0x5e, 0x26, 0x0a, 0xab, 0x02, 0x4e, 0x33, 0x6a, 0x43, + 0x3d, 0xe7, 0x54, 0x36, 0x70, 0x15, 0xd6, 0xb0, 0xf7, 0x12, 0x3e, 0x3c, 0xd6, 0x16, 0xb0, 0xaa, + 0x10, 0xe8, 0x06, 0xb6, 0x92, 0x1a, 0x48, 0x6f, 0x2b, 0x6c, 0x86, 0x57, 0x73, 0x78, 0x7d, 0xbe, + 0x13, 0xea, 0xc2, 0x0e, 0xfe, 0x82, 0x83, 0xcf, 0xf3, 0xd1, 0x74, 0x12, 0xcd, 0xe6, 0xef, 0x07, + 0x38, 0xc2, 0x93, 0x0f, 0x91, 0xff, 0x69, 0x1a, 0x7c, 0xc4, 0x61, 0x5b, 0x43, 0x2f, 0xe0, 0xf3, + 0xff, 0x05, 0x3e, 0x1e, 0x8c, 0x26, 0x27, 0x09, 0xf0, 0x87, 0xdb, 0xbd, 0x05, 0x76, 0x7b, 0x0b, + 0xfc, 0xde, 0x5b, 0xe0, 0xc7, 0xc1, 0xd2, 0x76, 0x07, 0x4b, 0xfb, 0x79, 0xb0, 0xb4, 0xaf, 0x2e, + 0xcd, 0x44, 0x5a, 0x2d, 0xdc, 0x84, 0xe5, 0x9e, 0x6a, 0xe6, 0x35, 0x2b, 0xe9, 0x11, 0x7b, 0xdf, + 0xde, 0x7a, 0x9b, 0xe6, 0x56, 0xc4, 0xf7, 0x35, 0xe1, 0x8b, 0x0b, 0x79, 0x05, 0x6f, 0xfe, 0x06, + 0x00, 0x00, 0xff, 0xff, 0xf1, 0x0a, 0x42, 0x3f, 0x48, 0x02, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -289,10 +292,23 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ExecutionStage != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.ExecutionStage)) + if len(m.ExecutionStages) > 0 { + dAtA2 := make([]byte, len(m.ExecutionStages)*10) + var j1 int + for _, num := range m.ExecutionStages { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintSchedule(dAtA, i, uint64(j1)) i-- - dAtA[i] = 0x28 + dAtA[i] = 0x2a } if m.LastExecuteHeight != 0 { i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) @@ -426,8 +442,12 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } - if m.ExecutionStage != 0 { - n += 1 + sovSchedule(uint64(m.ExecutionStage)) + if len(m.ExecutionStages) > 0 { + l = 0 + for _, e := range m.ExecutionStages { + l += sovSchedule(uint64(e)) + } + n += 1 + sovSchedule(uint64(l)) + l } return n } @@ -601,23 +621,73 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { } } case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) - } - m.ExecutionStage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule + if wireType == 0 { + var v ExecutionStage + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { + m.ExecutionStages = append(m.ExecutionStages, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - m.ExecutionStage |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break + var elementCount int + if elementCount != 0 && len(m.ExecutionStages) == 0 { + m.ExecutionStages = make([]ExecutionStage, 0, elementCount) + } + for iNdEx < postIndex { + var v ExecutionStage + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ExecutionStages = append(m.ExecutionStages, v) } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStages", wireType) } default: iNdEx = preIndex diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index 1bca78a71..c439f37d5 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -45,6 +45,10 @@ func (msg *MsgAddSchedule) Validate() error { return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") } + if len(msg.ExecutionStages) == 0 { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "execution stages should not be empty") + } + return nil } diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 16905d24b..8588b6028 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -34,11 +34,15 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // MsgAddSchedule is the MsgAddSchedule request type. type MsgAddSchedule struct { // Authority is the address of the governance account. - Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` - Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` - ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Name of the schedule + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Period in blocks + Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` + // Msgs that will be executed every certain number of blocks, specified in the `period` field + Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` + // Execution stages when messages will be executed + ExecutionStages []ExecutionStage `protobuf:"varint,5,rep,packed,name=execution_stages,json=executionStages,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stages,omitempty"` } func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } @@ -102,11 +106,11 @@ func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { return nil } -func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { +func (m *MsgAddSchedule) GetExecutionStages() []ExecutionStage { if m != nil { - return m.ExecutionStage + return m.ExecutionStages } - return ExecutionStage_BEGIN_BLOCKER + return nil } // MsgAddScheduleResponse defines the response structure for executing a @@ -151,7 +155,8 @@ var xxx_messageInfo_MsgAddScheduleResponse proto.InternalMessageInfo type MsgRemoveSchedule struct { // Authority is the address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Name of the schedule + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } func (m *MsgRemoveSchedule) Reset() { *m = MsgRemoveSchedule{} } @@ -350,42 +355,42 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 554 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x6b, 0xdb, 0x40, - 0x14, 0xf6, 0xd9, 0x8e, 0xc1, 0xe7, 0xe0, 0x10, 0xd5, 0x75, 0x64, 0x25, 0x55, 0x8c, 0x68, 0x1b, - 0xd7, 0x10, 0x89, 0xba, 0xa5, 0x05, 0x6f, 0x71, 0x31, 0x74, 0x11, 0xb4, 0x72, 0xbb, 0x64, 0x09, - 0x8a, 0x74, 0x9c, 0x05, 0x95, 0x4e, 0xe8, 0x4e, 0xc6, 0xd9, 0x4a, 0xc7, 0x4c, 0xed, 0x5f, 0xd0, - 0xb5, 0xd0, 0xc5, 0x43, 0xff, 0x88, 0x8c, 0xa1, 0x53, 0xa7, 0x52, 0xec, 0xc1, 0xff, 0x46, 0xd1, - 0xaf, 0x44, 0x17, 0x41, 0x0a, 0x85, 0x2c, 0xa7, 0x7b, 0xef, 0xfb, 0xde, 0xd3, 0x77, 0xdf, 0x3d, - 0x0e, 0xde, 0xf7, 0x50, 0xc8, 0x02, 0xe2, 0x69, 0x56, 0xb4, 0xb0, 0xb9, 0xea, 0x07, 0x84, 0x11, - 0x61, 0x33, 0x4d, 0xab, 0x51, 0x5a, 0xda, 0x36, 0x5d, 0xc7, 0x23, 0x5a, 0xbc, 0x26, 0x04, 0x69, - 0xc7, 0x22, 0xd4, 0x25, 0x54, 0x73, 0x29, 0xd6, 0x66, 0x4f, 0xa3, 0x4f, 0x0a, 0x74, 0x12, 0xe0, - 0x24, 0x8e, 0xb4, 0x24, 0x48, 0xa1, 0x16, 0x26, 0x98, 0x24, 0xf9, 0x68, 0x97, 0x15, 0x70, 0x0a, - 0x7c, 0x33, 0x30, 0xdd, 0xac, 0x60, 0x97, 0x83, 0xa8, 0x35, 0x45, 0x76, 0xf8, 0x01, 0x25, 0xa0, - 0xf2, 0xb5, 0x0c, 0x9b, 0x3a, 0xc5, 0x47, 0xb6, 0x3d, 0x49, 0x01, 0xe1, 0x05, 0xac, 0x9b, 0x21, - 0x9b, 0x92, 0xc0, 0x61, 0x67, 0x22, 0xe8, 0x82, 0x5e, 0x7d, 0x24, 0xfe, 0xfc, 0x71, 0xd8, 0x4a, - 0x55, 0x1c, 0xd9, 0x76, 0x80, 0x28, 0x9d, 0xb0, 0xc0, 0xf1, 0xb0, 0x71, 0x4d, 0x15, 0x04, 0x58, - 0xf5, 0x4c, 0x17, 0x89, 0xe5, 0xa8, 0xc4, 0x88, 0xf7, 0x42, 0x1b, 0xd6, 0x7c, 0x14, 0x38, 0xc4, - 0x16, 0x2b, 0x5d, 0xd0, 0xab, 0x1a, 0x69, 0x24, 0x0c, 0x61, 0xd5, 0xa5, 0x98, 0x8a, 0xd5, 0x6e, - 0xa5, 0xd7, 0x18, 0x74, 0xd5, 0xbc, 0x51, 0xaa, 0x4e, 0xf1, 0x78, 0x8e, 0xac, 0x90, 0xa1, 0x57, - 0xc4, 0x63, 0x81, 0x69, 0xb1, 0x51, 0xf5, 0xe2, 0xf7, 0x7e, 0xc9, 0x88, 0x6b, 0x84, 0x31, 0xdc, - 0x42, 0x31, 0xec, 0x10, 0xef, 0x84, 0x32, 0x13, 0x23, 0x71, 0xa3, 0x0b, 0x7a, 0xcd, 0xc1, 0x1e, - 0xdf, 0x66, 0x9c, 0x91, 0x26, 0x11, 0xc7, 0x68, 0x22, 0x2e, 0x1e, 0x3e, 0xfe, 0xb4, 0x5e, 0xf4, - 0xaf, 0xe5, 0x9f, 0xaf, 0x17, 0xfd, 0x7b, 0xb1, 0x43, 0xbc, 0x1d, 0x8a, 0x08, 0xdb, 0x7c, 0xc6, - 0x40, 0xd4, 0x27, 0x1e, 0x45, 0xca, 0x39, 0x80, 0xdb, 0x3a, 0xc5, 0x06, 0x72, 0xc9, 0x0c, 0xdd, - 0x85, 0x7d, 0xc3, 0x27, 0x45, 0x8d, 0xed, 0x4c, 0x23, 0xff, 0x5b, 0x65, 0x17, 0x76, 0x0a, 0xc9, - 0x2b, 0xa5, 0xdf, 0x01, 0xdc, 0xd2, 0x29, 0x7e, 0xef, 0xdb, 0x26, 0x43, 0x6f, 0xe2, 0xe1, 0xf8, - 0x6f, 0x9d, 0x2f, 0x61, 0x2d, 0x19, 0xaf, 0x58, 0x69, 0x63, 0xd0, 0xe2, 0x5d, 0x4f, 0xba, 0x8f, - 0xea, 0xd1, 0x85, 0x7d, 0x5b, 0x2f, 0xfa, 0xc0, 0x48, 0xe9, 0xc3, 0x83, 0xe2, 0x61, 0x5a, 0xd9, - 0x61, 0xf2, 0xca, 0x94, 0x0e, 0xdc, 0xb9, 0x91, 0xca, 0x0e, 0x32, 0xf8, 0x52, 0x86, 0x15, 0x9d, - 0x62, 0xe1, 0x2d, 0x6c, 0xe4, 0x47, 0x76, 0xaf, 0x30, 0x40, 0x39, 0x54, 0x7a, 0x78, 0x1b, 0x9a, - 0xb5, 0x16, 0x8e, 0x61, 0xf3, 0xc6, 0x4d, 0xee, 0x17, 0xea, 0x78, 0x82, 0x74, 0xf0, 0x0f, 0xc2, - 0x55, 0xef, 0x77, 0x70, 0x93, 0xf3, 0xfe, 0x41, 0xa1, 0x30, 0x0f, 0x4b, 0x8f, 0x6e, 0x85, 0xb3, - 0xae, 0xd2, 0xc6, 0xc7, 0xc8, 0xdf, 0xd1, 0xeb, 0x8b, 0xa5, 0x0c, 0x2e, 0x97, 0x32, 0xf8, 0xb3, - 0x94, 0xc1, 0xe7, 0x95, 0x5c, 0xba, 0x5c, 0xc9, 0xa5, 0x5f, 0x2b, 0xb9, 0x74, 0xac, 0x62, 0x87, - 0x4d, 0xc3, 0x53, 0xd5, 0x22, 0xae, 0x96, 0x76, 0x3c, 0x24, 0x01, 0xce, 0xf6, 0xda, 0xec, 0xb9, - 0x36, 0x4f, 0x9f, 0xac, 0x33, 0x1f, 0xd1, 0xd3, 0x5a, 0xfc, 0x26, 0x3c, 0xfb, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0xf7, 0xca, 0x79, 0x29, 0xcf, 0x04, 0x00, 0x00, + // 556 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xc1, 0x6b, 0xd3, 0x50, + 0x1c, 0x6e, 0xd6, 0xae, 0xd0, 0xd7, 0xd1, 0xb9, 0x58, 0xbb, 0x34, 0x9b, 0x59, 0x08, 0xea, 0x6a, + 0x61, 0x09, 0x56, 0x51, 0xe8, 0x6d, 0x95, 0x81, 0x97, 0x80, 0xa6, 0x7a, 0xd9, 0x65, 0x64, 0xc9, + 0xe3, 0x35, 0x60, 0xf2, 0x42, 0xde, 0x4b, 0xe9, 0x6e, 0xe2, 0x71, 0x27, 0xfd, 0x2b, 0x14, 0xbc, + 0xf4, 0xe0, 0x1f, 0xb1, 0xe3, 0xf0, 0xe4, 0x49, 0xa4, 0x3d, 0xf4, 0xdf, 0x90, 0x24, 0x2f, 0x5b, + 0xde, 0x02, 0x13, 0x04, 0x2f, 0xe9, 0x7b, 0xbf, 0xef, 0xfb, 0x7d, 0xfd, 0x7e, 0x5f, 0x7e, 0x04, + 0xdc, 0x0b, 0x60, 0x4c, 0x23, 0x1c, 0x18, 0x4e, 0xf2, 0xa0, 0x33, 0x3d, 0x8c, 0x30, 0xc5, 0xe2, + 0x06, 0x2b, 0xeb, 0x49, 0x59, 0xde, 0xb2, 0x7d, 0x2f, 0xc0, 0x46, 0xfa, 0xcc, 0x08, 0xf2, 0xb6, + 0x83, 0x89, 0x8f, 0x89, 0xe1, 0x13, 0x64, 0x4c, 0x9f, 0x24, 0x3f, 0x0c, 0xe8, 0x66, 0xc0, 0x49, + 0x7a, 0x33, 0xb2, 0x0b, 0x83, 0xda, 0x08, 0x23, 0x9c, 0xd5, 0x93, 0x53, 0xde, 0xc0, 0x39, 0x08, + 0xed, 0xc8, 0xf6, 0xf3, 0x86, 0x1d, 0x0e, 0x22, 0xce, 0x04, 0xba, 0xf1, 0x7b, 0x98, 0x81, 0xda, + 0x97, 0x35, 0xd0, 0x32, 0x09, 0x3a, 0x74, 0xdd, 0x31, 0x03, 0xc4, 0xe7, 0xa0, 0x61, 0xc7, 0x74, + 0x82, 0x23, 0x8f, 0x9e, 0x49, 0x82, 0x2a, 0xf4, 0x1a, 0x23, 0xe9, 0xc7, 0xf7, 0x83, 0x36, 0x73, + 0x71, 0xe8, 0xba, 0x11, 0x24, 0x64, 0x4c, 0x23, 0x2f, 0x40, 0xd6, 0x35, 0x55, 0x14, 0x41, 0x2d, + 0xb0, 0x7d, 0x28, 0xad, 0x25, 0x2d, 0x56, 0x7a, 0x16, 0x3b, 0xa0, 0x1e, 0xc2, 0xc8, 0xc3, 0xae, + 0x54, 0x55, 0x85, 0x5e, 0xcd, 0x62, 0x37, 0x71, 0x08, 0x6a, 0x3e, 0x41, 0x44, 0xaa, 0xa9, 0xd5, + 0x5e, 0x73, 0xa0, 0xea, 0xc5, 0xa0, 0x74, 0x93, 0xa0, 0xa3, 0x19, 0x74, 0x62, 0x0a, 0x5f, 0xe2, + 0x80, 0x46, 0xb6, 0x43, 0x47, 0xb5, 0x8b, 0x5f, 0x7b, 0x15, 0x2b, 0xed, 0x11, 0x4d, 0x70, 0x07, + 0xa6, 0xb0, 0x87, 0x83, 0x13, 0x42, 0x6d, 0x04, 0x89, 0xb4, 0xae, 0x56, 0x7b, 0xad, 0xc1, 0x2e, + 0xaf, 0x73, 0x94, 0xb3, 0xc6, 0x09, 0x89, 0x69, 0x6c, 0x42, 0xae, 0x4a, 0x86, 0x8f, 0x3e, 0xae, + 0xe6, 0xfd, 0xeb, 0x31, 0xce, 0x57, 0xf3, 0xfe, 0xdd, 0x34, 0x29, 0x3e, 0x16, 0x4d, 0x02, 0x1d, + 0xbe, 0x62, 0x41, 0x12, 0xe2, 0x80, 0x40, 0xed, 0x5c, 0x00, 0x5b, 0x26, 0x41, 0x16, 0xf4, 0xf1, + 0x14, 0xfe, 0x8f, 0x18, 0x87, 0x8f, 0xcb, 0x1e, 0x3b, 0xb9, 0x47, 0xfe, 0x6f, 0xb5, 0x1d, 0xd0, + 0x2d, 0x15, 0xaf, 0x9c, 0x7e, 0x13, 0xc0, 0xa6, 0x49, 0xd0, 0xbb, 0xd0, 0xb5, 0x29, 0x7c, 0x9d, + 0x2e, 0xc9, 0x3f, 0xfb, 0x7c, 0x01, 0xea, 0xd9, 0x9a, 0xa5, 0x4e, 0x9b, 0x83, 0x36, 0x1f, 0x7e, + 0xa6, 0x3e, 0x6a, 0x24, 0xa1, 0x7f, 0x5d, 0xcd, 0xfb, 0x82, 0xc5, 0xe8, 0xc3, 0xfd, 0xf2, 0x30, + 0xed, 0x7c, 0x98, 0xa2, 0x33, 0xad, 0x0b, 0xb6, 0x6f, 0x94, 0xf2, 0x41, 0x06, 0x9f, 0xd7, 0x40, + 0xd5, 0x24, 0x48, 0x7c, 0x03, 0x9a, 0xc5, 0xd5, 0xdd, 0x2d, 0x2d, 0x52, 0x01, 0x95, 0x1f, 0xdc, + 0x86, 0xe6, 0xd2, 0xe2, 0x31, 0x68, 0xdd, 0x78, 0x93, 0x7b, 0xa5, 0x3e, 0x9e, 0x20, 0xef, 0xff, + 0x85, 0x70, 0xa5, 0xfd, 0x16, 0x6c, 0x70, 0xd9, 0xdf, 0x2f, 0x35, 0x16, 0x61, 0xf9, 0xe1, 0xad, + 0x70, 0xae, 0x2a, 0xaf, 0x7f, 0x48, 0xf2, 0x1d, 0xbd, 0xba, 0x58, 0x28, 0xc2, 0xe5, 0x42, 0x11, + 0x7e, 0x2f, 0x14, 0xe1, 0xd3, 0x52, 0xa9, 0x5c, 0x2e, 0x95, 0xca, 0xcf, 0xa5, 0x52, 0x39, 0xd6, + 0x91, 0x47, 0x27, 0xf1, 0xa9, 0xee, 0x60, 0xdf, 0x60, 0x8a, 0x07, 0x38, 0x42, 0xf9, 0xd9, 0x98, + 0x3e, 0x33, 0x66, 0xec, 0xd3, 0x75, 0x16, 0x42, 0x72, 0x5a, 0x4f, 0xbf, 0x0d, 0x4f, 0xff, 0x04, + 0x00, 0x00, 0xff, 0xff, 0xb7, 0x18, 0xba, 0xe9, 0xd7, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -566,10 +571,23 @@ func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ExecutionStage != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.ExecutionStage)) + if len(m.ExecutionStages) > 0 { + dAtA2 := make([]byte, len(m.ExecutionStages)*10) + var j1 int + for _, num := range m.ExecutionStages { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintTx(dAtA, i, uint64(j1)) i-- - dAtA[i] = 0x28 + dAtA[i] = 0x2a } if len(m.Msgs) > 0 { for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { @@ -787,8 +805,12 @@ func (m *MsgAddSchedule) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if m.ExecutionStage != 0 { - n += 1 + sovTx(uint64(m.ExecutionStage)) + if len(m.ExecutionStages) > 0 { + l = 0 + for _, e := range m.ExecutionStages { + l += sovTx(uint64(e)) + } + n += 1 + sovTx(uint64(l)) + l } return n } @@ -1005,23 +1027,73 @@ func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) - } - m.ExecutionStage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx + if wireType == 0 { + var v ExecutionStage + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } } - if iNdEx >= l { + m.ExecutionStages = append(m.ExecutionStages, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - m.ExecutionStage |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break + var elementCount int + if elementCount != 0 && len(m.ExecutionStages) == 0 { + m.ExecutionStages = make([]ExecutionStage, 0, elementCount) + } + for iNdEx < postIndex { + var v ExecutionStage + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.ExecutionStages = append(m.ExecutionStages, v) } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStages", wireType) } default: iNdEx = preIndex diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go index b2fe7d90c..814f91cbb 100644 --- a/x/cron/types/v1/schedule.pb.go +++ b/x/cron/types/v1/schedule.pb.go @@ -23,12 +23,13 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// Schedule defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Period in blocks Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` @@ -95,6 +96,7 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } +// MsgExecuteContract defines the contract and the message to pass type MsgExecuteContract struct { // Contract is the address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` @@ -149,6 +151,7 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } +// ScheduleCount defines the number of current schedules type ScheduleCount struct { // Count is the number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` From e01b7526960d56bff0b33f0b9c211678baafff58 Mon Sep 17 00:00:00 2001 From: nhpd Date: Mon, 26 Aug 2024 14:30:00 +0400 Subject: [PATCH 22/60] allow consensus MsgParamsUpdate from governance --- app/proposals_allowlisting.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/proposals_allowlisting.go b/app/proposals_allowlisting.go index 8af48963b..f2cba406d 100644 --- a/app/proposals_allowlisting.go +++ b/app/proposals_allowlisting.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" @@ -63,6 +64,7 @@ func isSdkMessageWhitelisted(msg sdk.Msg) bool { *wasmtypes.MsgUpdateParams, *wasmtypes.MsgPinCodes, *wasmtypes.MsgUnpinCodes, + *consensustypes.MsgUpdateParams, *upgradetypes.MsgSoftwareUpgrade, *upgradetypes.MsgCancelUpgrade, *ibcclienttypes.MsgRecoverClient, From 8b449b2f204ff77fc220a2bbdc026a3384800bc3 Mon Sep 17 00:00:00 2001 From: nhpd Date: Mon, 26 Aug 2024 20:09:35 +0400 Subject: [PATCH 23/60] add consensus module to properly register MsgUpdateParams type --- app/app.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/app.go b/app/app.go index b259d763b..2c0dcd9da 100644 --- a/app/app.go +++ b/app/app.go @@ -183,6 +183,7 @@ import ( ccvconsumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/x/consensus" consensusparamkeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" pfmkeeper "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward/keeper" @@ -279,6 +280,7 @@ var ( oracle.AppModuleBasic{}, marketmap.AppModuleBasic{}, dynamicfees.AppModuleBasic{}, + consensus.AppModuleBasic{}, ) // module account permissions @@ -969,6 +971,7 @@ func New( marketmapModule, oracleModule, auction.NewAppModule(appCodec, app.AuctionKeeper), + consensus.NewAppModule(appCodec, app.ConsensusParamsKeeper), // always be last to make sure that it checks for all invariants and not only part of them crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants, app.GetSubspace(crisistypes.ModuleName)), ) @@ -1015,6 +1018,7 @@ func New( feemarkettypes.ModuleName, ibcswaptypes.ModuleName, dextypes.ModuleName, + consensusparamtypes.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -1051,6 +1055,7 @@ func New( feemarkettypes.ModuleName, ibcswaptypes.ModuleName, dextypes.ModuleName, + consensusparamtypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -1093,6 +1098,7 @@ func New( ibcswaptypes.ModuleName, dextypes.ModuleName, dynamicfeestypes.ModuleName, + consensusparamtypes.ModuleName, ) app.mm.RegisterInvariants(&app.CrisisKeeper) From 8d1c58d0c84d3d25e721428dbcb719bce8700437 Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Tue, 27 Aug 2024 13:58:57 +0300 Subject: [PATCH 24/60] make edits --- proto/neutron/cron/query.proto | 12 +- proto/neutron/cron/schedule.proto | 4 +- proto/neutron/cron/tx.proto | 4 +- wasmbinding/bindings/msg.go | 8 +- wasmbinding/message_plugin.go | 7 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 4 +- x/cron/keeper/keeper.go | 39 ++--- x/cron/keeper/keeper_test.go | 128 ++++----------- x/cron/keeper/msg_server.go | 4 +- x/cron/keeper/msg_server_test.go | 44 ++--- x/cron/migrations/v2/store.go | 2 +- x/cron/migrations/v2/store_test.go | 2 +- x/cron/types/query.pb.go | 12 +- x/cron/types/schedule.pb.go | 165 ++++++------------- x/cron/types/tx.go | 4 - x/cron/types/tx.pb.go | 185 +++++++--------------- 17 files changed, 191 insertions(+), 435 deletions(-) diff --git a/proto/neutron/cron/query.proto b/proto/neutron/cron/query.proto index 415d7300f..906ccfb1d 100644 --- a/proto/neutron/cron/query.proto +++ b/proto/neutron/cron/query.proto @@ -30,31 +30,31 @@ service Query { // this line is used by starport scaffolding # 2 } -// QueryParamsRequest is the request type for the Query/Params RPC method. +// The request type for the Query/Params RPC method. message QueryParamsRequest {} -// QueryParamsResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } -// QueryGetScheduleRequest is the request type for the Query/Schedule RPC method. +// The request type for the Query/Schedule RPC method. message QueryGetScheduleRequest { string name = 1; } -// QueryGetScheduleResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. message QueryGetScheduleResponse { Schedule schedule = 1 [(gogoproto.nullable) = false]; } -// QuerySchedulesRequest is the request type for the Query/Schedules RPC method. +// The request type for the Query/Schedules RPC method. message QuerySchedulesRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } -// QuerySchedulesResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. message QuerySchedulesResponse { repeated Schedule schedules = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index 920d0fc38..a93a5fff6 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -23,8 +23,8 @@ message Schedule { repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; - // Execution stages when messages will be executed - repeated ExecutionStage execution_stages = 5 [(gogoproto.nullable) = false]; + // Execution stage when messages will be executed + ExecutionStage execution_stage = 5; } // MsgExecuteContract defines the contract and the message to pass diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index 9db1d58dc..d01cf89b4 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -38,8 +38,8 @@ message MsgAddSchedule { uint64 period = 3; // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - // Execution stages when messages will be executed - repeated ExecutionStage execution_stages = 5 [(gogoproto.nullable) = false]; + // Execution stage when messages will be executed + ExecutionStage execution_stage = 5; } // MsgAddScheduleResponse defines the response structure for executing a diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 4f245ce0d..c1697401d 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -195,10 +195,10 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` - ExecutionStages []string `json:"execution_stages"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` + ExecutionStage string `json:"execution_stage"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 799e48612..3e835e206 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -985,12 +985,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - executionStages := make([]crontypes.ExecutionStage, 0, len(addSchedule.ExecutionStages)) - for _, executionStage := range addSchedule.ExecutionStages { - executionStages = append(executionStages, crontypes.ExecutionStage(crontypes.ExecutionStage_value[executionStage])) - } - - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, executionStages) + err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, crontypes.ExecutionStage(crontypes.ExecutionStage_value[addSchedule.ExecutionStage])) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), diff --git a/x/cron/genesis.go b/x/cron/genesis.go index 404c5dbd3..525840e26 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStages) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStage) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index 78afe1517..a132fc8d4 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -133,9 +133,9 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Period = 1000 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) - item.ExecutionStages = []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER} + item.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStages) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 460e5fc00..013cf9ede 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -27,8 +27,6 @@ var ( MetricLabelSuccess = "success" MetricLabelScheduleName = "schedule_name" - - schedulesExecutionStages map[string]map[types.ExecutionStage]struct{} ) type ( @@ -49,8 +47,6 @@ func NewKeeper( accountKeeper types.AccountKeeper, authority string, ) *Keeper { - schedulesExecutionStages = make(map[string]map[types.ExecutionStage]struct{}) - return &Keeper{ cdc: cdc, storeKey: storeKey, @@ -72,13 +68,11 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // and executes messages in each one func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.ExecutionStage) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) - schedules := k.getSchedulesReadyForExecution(ctx) + schedules := k.getSchedulesReadyForExecution(ctx, executionStage) for _, schedule := range schedules { - if _, ok := schedulesExecutionStages[schedule.Name][executionStage]; ok { - err := k.executeSchedule(ctx, schedule) - recordExecutedSchedule(err, schedule) - } + err := k.executeSchedule(ctx, schedule) + recordExecutedSchedule(err, schedule) } } @@ -89,31 +83,22 @@ func (k *Keeper) AddSchedule( name string, period uint64, msgs []types.MsgExecuteContract, - executionStages []types.ExecutionStage, + executionStage types.ExecutionStage, ) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) } - schedulesExecutionStages[name] = make(map[types.ExecutionStage]struct{}) - execStages := make([]types.ExecutionStage, 0) - for _, executionStage := range executionStages { - if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { - executionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - } - - if _, ok := schedulesExecutionStages[name][executionStage]; !ok { - schedulesExecutionStages[name][executionStage] = struct{}{} - execStages = append(execStages, executionStage) - } - } - schedule := types.Schedule{ Name: name, Period: period, Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block - ExecutionStages: execStages, + ExecutionStage: executionStage, + } + + if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { + schedule.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER } k.storeSchedule(ctx, schedule) @@ -128,8 +113,6 @@ func (k *Keeper) RemoveSchedule(ctx sdk.Context, name string) { return } - delete(schedulesExecutionStages, name) - k.changeTotalCount(ctx, -1) k.removeSchedule(ctx, name) } @@ -169,7 +152,7 @@ func (k *Keeper) GetScheduleCount(ctx sdk.Context) int32 { return k.getScheduleCount(ctx) } -func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule { +func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context, executionStage types.ExecutionStage) []types.Schedule { params := k.GetParams(ctx) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ScheduleKey) count := uint64(0) @@ -183,7 +166,7 @@ func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule var schedule types.Schedule k.cdc.MustUnmarshal(iterator.Value(), &schedule) - if k.intervalPassed(ctx, schedule) { + if k.intervalPassed(ctx, schedule) && schedule.ExecutionStage == executionStage { res = append(res, schedule) count++ diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index 4d3cd2956..f680bebe3 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -52,9 +52,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "2_ready1", @@ -66,9 +64,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "3_ready2", @@ -80,19 +76,14 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "4_unready2", Period: 10, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "5_ready3", @@ -104,10 +95,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "6_ready4", @@ -119,35 +107,18 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }, - }, - { - Name: "7_ready5", - Period: 1, - Msgs: []types.MsgExecuteContract{ - { - Contract: "7_neutron", - Msg: "7_msg", - }, - }, - LastExecuteHeight: 0, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStages) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) } count := k.GetScheduleCount(ctx) - require.Equal(t, count, int32(7)) + require.Equal(t, count, int32(6)) ctx = ctx.WithBlockHeight(5) @@ -191,14 +162,8 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Msg: []byte("5_msg"), Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ - Sender: testutil.TestOwnerAddress, - Contract: "6_neutron", - Msg: []byte("6_msg"), - Funds: sdk.NewCoins(), - }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") @@ -212,37 +177,32 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(6), ready3.LastExecuteHeight) - require.Equal(t, uint64(6), ready4.LastExecuteHeight) + require.Equal(t, uint64(0), ready4.LastExecuteHeight) ctx = ctx.WithBlockHeight(7) wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, - Contract: "7_neutron", - Msg: []byte("7_msg"), - Funds: sdk.NewCoins(), - }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - - k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) - - ready5, _ := k.GetSchedule(ctx, "7_ready5") - - require.Equal(t, uint64(7), ready5.LastExecuteHeight) - - ctx = ctx.WithBlockHeight(9) - - wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ - Sender: testutil.TestOwnerAddress, - Contract: "7_neutron", - Msg: []byte("7_msg"), + Contract: "6_neutron", + Msg: []byte("6_msg"), Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) - ready5, _ = k.GetSchedule(ctx, "7_ready5") + unready1, _ = k.GetSchedule(ctx, "1_unready1") + ready1, _ = k.GetSchedule(ctx, "2_ready1") + ready2, _ = k.GetSchedule(ctx, "3_ready2") + unready2, _ = k.GetSchedule(ctx, "4_unready2") + ready3, _ = k.GetSchedule(ctx, "5_ready3") + ready4, _ = k.GetSchedule(ctx, "6_ready4") - require.Equal(t, uint64(9), ready5.LastExecuteHeight) + require.Equal(t, uint64(4), unready1.LastExecuteHeight) + require.Equal(t, uint64(5), ready1.LastExecuteHeight) + require.Equal(t, uint64(5), ready2.LastExecuteHeight) + require.Equal(t, uint64(4), unready2.LastExecuteHeight) + require.Equal(t, uint64(6), ready3.LastExecuteHeight) + require.Equal(t, uint64(7), ready4.LastExecuteHeight) } func TestAddSchedule(t *testing.T) { @@ -267,7 +227,7 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER}) + }, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) require.NoError(t, err) err = k.AddSchedule(ctx, "b", 7, []types.MsgExecuteContract{ @@ -275,18 +235,7 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) - require.NoError(t, err) - - err = k.AddSchedule(ctx, "c", 7, []types.MsgExecuteContract{ - { - Contract: "c", - Msg: "m", - }, - }, []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }) + }, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.NoError(t, err) err = k.AddSchedule(ctx, "d", 7, []types.MsgExecuteContract{ @@ -294,13 +243,11 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, []types.ExecutionStage{7}) + }, 7) require.NoError(t, err) // second time with same name returns error - err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }) + err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.Error(t, err) scheduleA, found := k.GetSchedule(ctx, "a") @@ -310,16 +257,13 @@ func TestAddSchedule(t *testing.T) { require.Equal(t, scheduleA.Msgs, []types.MsgExecuteContract{ {Contract: "c", Msg: "m"}, }) + require.Equal(t, scheduleA.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) schedules := k.GetAllSchedules(ctx) - require.Len(t, schedules, 4) - require.Equal(t, schedules[0].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER}) - require.Equal(t, schedules[1].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) - require.Equal(t, schedules[2].ExecutionStages, []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }) - require.Equal(t, schedules[3].ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) + require.Len(t, schedules, 3) + require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + require.Equal(t, schedules[2].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) // remove schedule works k.RemoveSchedule(ctx, "a") @@ -346,12 +290,10 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStages) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStage) require.NoError(t, err) } diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index 8751cd800..ec69a49d2 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -34,8 +34,8 @@ func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStages); err != nil { - return nil, err + if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { + return nil, errors.Wrap(err, "failed to add schedule") } return &types.MsgAddScheduleResponse{}, nil diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index a523def37..5f4d0b308 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -32,9 +32,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, "authority is invalid", }, @@ -50,9 +48,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, "authority is invalid", }, @@ -68,9 +64,7 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, "name is invalid", }, @@ -86,41 +80,21 @@ func TestMsgAddScheduleValidate(t *testing.T) { Msg: "msg", }, }, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, "period is invalid", }, { "empty msgs", types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{}, - ExecutionStages: []types.ExecutionStage{ - types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{}, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, "msgs should not be empty", }, - { - "empty execution stages", - types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStages: []types.ExecutionStage{}, - }, - "execution stages should not be empty", - }, } for _, tt := range tests { diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go index c22e73fdb..f3311aba0 100644 --- a/x/cron/migrations/v2/store.go +++ b/x/cron/migrations/v2/store.go @@ -32,7 +32,7 @@ func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetype var schedule types.Schedule cdc.MustUnmarshal(iterator.Value(), &schedule) // Set execution in EndBlocker - schedule.ExecutionStages = []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER} + schedule.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ key: iterator.Key(), diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go index f065837af..fdc3bf3a8 100644 --- a/x/cron/migrations/v2/store_test.go +++ b/x/cron/migrations/v2/store_test.go @@ -49,5 +49,5 @@ func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { // Check Schedule has correct ExecutionStage newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) - suite.Equal(newSchedule.ExecutionStages, []types.ExecutionStage{types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER}) + suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) } diff --git a/x/cron/types/query.pb.go b/x/cron/types/query.pb.go index 6ba041f07..912a44eaa 100644 --- a/x/cron/types/query.pb.go +++ b/x/cron/types/query.pb.go @@ -30,7 +30,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// QueryParamsRequest is the request type for the Query/Params RPC method. +// The request type for the Query/Params RPC method. type QueryParamsRequest struct { } @@ -67,7 +67,7 @@ func (m *QueryParamsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo -// QueryParamsResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` @@ -113,7 +113,7 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } -// QueryGetScheduleRequest is the request type for the Query/Schedule RPC method. +// The request type for the Query/Schedule RPC method. type QueryGetScheduleRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -158,7 +158,7 @@ func (m *QueryGetScheduleRequest) GetName() string { return "" } -// QueryGetScheduleResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. type QueryGetScheduleResponse struct { Schedule Schedule `protobuf:"bytes,1,opt,name=schedule,proto3" json:"schedule"` } @@ -203,7 +203,7 @@ func (m *QueryGetScheduleResponse) GetSchedule() Schedule { return Schedule{} } -// QuerySchedulesRequest is the request type for the Query/Schedules RPC method. +// The request type for the Query/Schedules RPC method. type QuerySchedulesRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -248,7 +248,7 @@ func (m *QuerySchedulesRequest) GetPagination() *query.PageRequest { return nil } -// QuerySchedulesResponse is the response type for the Query/Params RPC method. +// The response type for the Query/Params RPC method. type QuerySchedulesResponse struct { Schedules []Schedule `protobuf:"bytes,1,rep,name=schedules,proto3" json:"schedules"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index 5599c1e91..d595c3457 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -61,8 +61,8 @@ type Schedule struct { Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` - // Execution stages when messages will be executed - ExecutionStages []ExecutionStage `protobuf:"varint,5,rep,packed,name=execution_stages,json=executionStages,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stages,omitempty"` + // Execution stage when messages will be executed + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -126,11 +126,11 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } -func (m *Schedule) GetExecutionStages() []ExecutionStage { +func (m *Schedule) GetExecutionStage() ExecutionStage { if m != nil { - return m.ExecutionStages + return m.ExecutionStage } - return nil + return ExecutionStage_EXECUTION_STAGE_END_BLOCKER } // MsgExecuteContract defines the contract and the message to pass @@ -244,32 +244,32 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 396 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x52, 0x41, 0x8b, 0xd3, 0x40, - 0x18, 0xcd, 0x98, 0x74, 0xd9, 0x1d, 0x75, 0xad, 0xe3, 0x22, 0x61, 0xab, 0x69, 0x2c, 0x08, 0x41, - 0x30, 0x81, 0xea, 0xc9, 0x9b, 0x89, 0x43, 0x5b, 0xb4, 0x2d, 0xa4, 0x15, 0xc4, 0x4b, 0x48, 0xd3, - 0x61, 0x12, 0x68, 0x32, 0x25, 0x33, 0x91, 0xfa, 0x2f, 0xfc, 0x59, 0x3d, 0xf6, 0xe8, 0x49, 0xa4, - 0xfd, 0x05, 0xfe, 0x03, 0xc9, 0x64, 0x5a, 0xac, 0x7b, 0x19, 0xde, 0x37, 0xef, 0x3d, 0xde, 0xc7, - 0xe3, 0x83, 0x9d, 0x82, 0x54, 0xa2, 0x64, 0x85, 0x97, 0xd4, 0x0f, 0x4f, 0x52, 0xb2, 0xac, 0x56, - 0xc4, 0x5d, 0x97, 0x4c, 0x30, 0xf4, 0x40, 0x91, 0x6e, 0x4d, 0xde, 0xde, 0x50, 0x46, 0x99, 0x24, - 0xbc, 0x1a, 0x35, 0x9a, 0xde, 0x1f, 0x00, 0x2f, 0x67, 0xca, 0x86, 0x10, 0x34, 0x8a, 0x38, 0x27, - 0x26, 0xb0, 0x81, 0x73, 0x15, 0x4a, 0x8c, 0x9e, 0xc2, 0x8b, 0x35, 0x29, 0x33, 0xb6, 0x34, 0xef, - 0xd9, 0xc0, 0x31, 0x42, 0x35, 0xa1, 0x77, 0xd0, 0xc8, 0x39, 0xe5, 0xa6, 0x6e, 0xeb, 0xce, 0xfd, - 0xbe, 0xed, 0xfe, 0x9b, 0xe5, 0x8e, 0x39, 0xc5, 0x1b, 0x92, 0x54, 0x82, 0x04, 0xac, 0x10, 0x65, - 0x9c, 0x08, 0xdf, 0xd8, 0xfe, 0xea, 0x6a, 0xa1, 0xf4, 0x20, 0x17, 0x3e, 0x59, 0xc5, 0x5c, 0x44, - 0xa4, 0xd1, 0x44, 0x29, 0xc9, 0x68, 0x2a, 0x4c, 0x43, 0x06, 0x3c, 0xae, 0x29, 0xe5, 0x1e, 0x4a, - 0x02, 0x8d, 0x61, 0xbb, 0x91, 0x66, 0xac, 0x88, 0xb8, 0x88, 0x29, 0xe1, 0x66, 0xcb, 0xd6, 0x9d, - 0xeb, 0xfe, 0xb3, 0xf3, 0x5c, 0x7c, 0x54, 0xcd, 0x6a, 0x91, 0xca, 0x7c, 0x44, 0xce, 0x7e, 0x79, - 0xcf, 0x87, 0xe8, 0xee, 0x82, 0xe8, 0x16, 0x5e, 0x26, 0x0a, 0xab, 0x02, 0x4e, 0x33, 0x6a, 0x43, - 0x3d, 0xe7, 0x54, 0x36, 0x70, 0x15, 0xd6, 0xb0, 0xf7, 0x12, 0x3e, 0x3c, 0xd6, 0x16, 0xb0, 0xaa, - 0x10, 0xe8, 0x06, 0xb6, 0x92, 0x1a, 0x48, 0x6f, 0x2b, 0x6c, 0x86, 0x57, 0x73, 0x78, 0x7d, 0xbe, - 0x13, 0xea, 0xc2, 0x0e, 0xfe, 0x82, 0x83, 0xcf, 0xf3, 0xd1, 0x74, 0x12, 0xcd, 0xe6, 0xef, 0x07, - 0x38, 0xc2, 0x93, 0x0f, 0x91, 0xff, 0x69, 0x1a, 0x7c, 0xc4, 0x61, 0x5b, 0x43, 0x2f, 0xe0, 0xf3, - 0xff, 0x05, 0x3e, 0x1e, 0x8c, 0x26, 0x27, 0x09, 0xf0, 0x87, 0xdb, 0xbd, 0x05, 0x76, 0x7b, 0x0b, - 0xfc, 0xde, 0x5b, 0xe0, 0xc7, 0xc1, 0xd2, 0x76, 0x07, 0x4b, 0xfb, 0x79, 0xb0, 0xb4, 0xaf, 0x2e, - 0xcd, 0x44, 0x5a, 0x2d, 0xdc, 0x84, 0xe5, 0x9e, 0x6a, 0xe6, 0x35, 0x2b, 0xe9, 0x11, 0x7b, 0xdf, - 0xde, 0x7a, 0x9b, 0xe6, 0x56, 0xc4, 0xf7, 0x35, 0xe1, 0x8b, 0x0b, 0x79, 0x05, 0x6f, 0xfe, 0x06, - 0x00, 0x00, 0xff, 0xff, 0xf1, 0x0a, 0x42, 0x3f, 0x48, 0x02, 0x00, 0x00, + // 393 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xc1, 0xaa, 0xd3, 0x40, + 0x18, 0x85, 0x33, 0x36, 0x2d, 0xed, 0xa8, 0xb5, 0x8e, 0x45, 0x42, 0xab, 0x69, 0x2c, 0x08, 0x41, + 0x30, 0x81, 0xea, 0xca, 0x9d, 0x89, 0x43, 0x5b, 0xd4, 0x16, 0xd2, 0x0a, 0xe2, 0x26, 0xa4, 0xe9, + 0x30, 0x09, 0x34, 0x99, 0x92, 0x99, 0x48, 0x7d, 0x0b, 0x1f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, 0xb4, + 0x2b, 0xdf, 0xe2, 0x92, 0x49, 0x5a, 0x6e, 0xef, 0xdd, 0x84, 0x73, 0x38, 0xdf, 0xe1, 0x9f, 0xf9, + 0x33, 0xb0, 0x9f, 0x92, 0x5c, 0x64, 0x2c, 0xb5, 0xc3, 0xe2, 0xc3, 0xc3, 0x88, 0xac, 0xf3, 0x0d, + 0xb1, 0xb6, 0x19, 0x13, 0x0c, 0x3d, 0xaa, 0x42, 0xab, 0x08, 0x7b, 0x5d, 0xca, 0x28, 0x93, 0x81, + 0x5d, 0xa8, 0x92, 0x19, 0xfe, 0x07, 0xb0, 0xb9, 0xa8, 0x6a, 0x08, 0x41, 0x35, 0x0d, 0x12, 0xa2, + 0x01, 0x03, 0x98, 0x2d, 0x4f, 0x6a, 0xf4, 0x1c, 0x36, 0xb6, 0x24, 0x8b, 0xd9, 0x5a, 0x7b, 0x60, + 0x00, 0x53, 0xf5, 0x2a, 0x87, 0x3e, 0x40, 0x35, 0xe1, 0x94, 0x6b, 0x35, 0xa3, 0x66, 0x3e, 0x1c, + 0x19, 0xd6, 0xed, 0x59, 0xd6, 0x57, 0x4e, 0xf1, 0x8e, 0x84, 0xb9, 0x20, 0x2e, 0x4b, 0x45, 0x16, + 0x84, 0xc2, 0x51, 0xf7, 0x7f, 0x07, 0x8a, 0x27, 0x3b, 0xc8, 0x82, 0xcf, 0x36, 0x01, 0x17, 0x3e, + 0x29, 0x19, 0x3f, 0x22, 0x31, 0x8d, 0x84, 0xa6, 0xca, 0x01, 0x4f, 0x8b, 0xa8, 0x6a, 0x4f, 0x64, + 0x80, 0x30, 0x7c, 0x52, 0xa2, 0x31, 0x4b, 0x7d, 0x2e, 0x02, 0x4a, 0xb4, 0xba, 0x01, 0xcc, 0xf6, + 0xe8, 0xc5, 0xf5, 0x58, 0x7c, 0x86, 0x16, 0x05, 0xe3, 0xb5, 0xc9, 0x95, 0x1f, 0x3a, 0x10, 0xdd, + 0x3f, 0x18, 0xea, 0xc1, 0x66, 0x58, 0xe9, 0xea, 0xe2, 0x17, 0x8f, 0x3a, 0xb0, 0x96, 0x70, 0x2a, + 0x6f, 0xde, 0xf2, 0x0a, 0x39, 0x7c, 0x0d, 0x1f, 0x9f, 0xd7, 0xe5, 0xb2, 0x3c, 0x15, 0xa8, 0x0b, + 0xeb, 0x61, 0x21, 0x64, 0xb7, 0xee, 0x95, 0xe6, 0xcd, 0x12, 0xb6, 0xaf, 0x0f, 0x83, 0x06, 0xb0, + 0x8f, 0xbf, 0x63, 0xf7, 0xdb, 0x72, 0x3a, 0x9f, 0xf9, 0x8b, 0xe5, 0xc7, 0x31, 0xf6, 0xf1, 0xec, + 0x93, 0xef, 0x7c, 0x99, 0xbb, 0x9f, 0xb1, 0xd7, 0x51, 0xd0, 0x2b, 0xf8, 0xf2, 0x2e, 0xe0, 0xe0, + 0xf1, 0x74, 0x76, 0x41, 0x80, 0x33, 0xd9, 0x1f, 0x75, 0x70, 0x38, 0xea, 0xe0, 0xdf, 0x51, 0x07, + 0xbf, 0x4f, 0xba, 0x72, 0x38, 0xe9, 0xca, 0x9f, 0x93, 0xae, 0xfc, 0xb0, 0x68, 0x2c, 0xa2, 0x7c, + 0x65, 0x85, 0x2c, 0xb1, 0xab, 0x95, 0xbc, 0x65, 0x19, 0x3d, 0x6b, 0xfb, 0xe7, 0x7b, 0x7b, 0x57, + 0xbe, 0x11, 0xf1, 0x6b, 0x4b, 0xf8, 0xaa, 0x21, 0xff, 0xfe, 0xbb, 0x9b, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x2e, 0xa9, 0x20, 0xa0, 0x40, 0x02, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -292,23 +292,10 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ExecutionStages) > 0 { - dAtA2 := make([]byte, len(m.ExecutionStages)*10) - var j1 int - for _, num := range m.ExecutionStages { - for num >= 1<<7 { - dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA2[j1] = uint8(num) - j1++ - } - i -= j1 - copy(dAtA[i:], dAtA2[:j1]) - i = encodeVarintSchedule(dAtA, i, uint64(j1)) + if m.ExecutionStage != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.ExecutionStage)) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x28 } if m.LastExecuteHeight != 0 { i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) @@ -442,12 +429,8 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } - if len(m.ExecutionStages) > 0 { - l = 0 - for _, e := range m.ExecutionStages { - l += sovSchedule(uint64(e)) - } - n += 1 + sovSchedule(uint64(l)) + l + if m.ExecutionStage != 0 { + n += 1 + sovSchedule(uint64(m.ExecutionStage)) } return n } @@ -621,73 +604,23 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { } } case 5: - if wireType == 0 { - var v ExecutionStage - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ExecutionStages = append(m.ExecutionStages, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthSchedule - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthSchedule + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) + } + m.ExecutionStage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule } - if postIndex > l { + if iNdEx >= l { return io.ErrUnexpectedEOF } - var elementCount int - if elementCount != 0 && len(m.ExecutionStages) == 0 { - m.ExecutionStages = make([]ExecutionStage, 0, elementCount) - } - for iNdEx < postIndex { - var v ExecutionStage - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ExecutionStages = append(m.ExecutionStages, v) + b := dAtA[iNdEx] + iNdEx++ + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStages", wireType) } default: iNdEx = preIndex diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index c439f37d5..1bca78a71 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -45,10 +45,6 @@ func (msg *MsgAddSchedule) Validate() error { return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") } - if len(msg.ExecutionStages) == 0 { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "execution stages should not be empty") - } - return nil } diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 8588b6028..39b7e92b3 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -41,8 +41,8 @@ type MsgAddSchedule struct { Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` // Msgs that will be executed every certain number of blocks, specified in the `period` field Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` - // Execution stages when messages will be executed - ExecutionStages []ExecutionStage `protobuf:"varint,5,rep,packed,name=execution_stages,json=executionStages,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stages,omitempty"` + // Execution stage when messages will be executed + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } @@ -106,11 +106,11 @@ func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { return nil } -func (m *MsgAddSchedule) GetExecutionStages() []ExecutionStage { +func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { if m != nil { - return m.ExecutionStages + return m.ExecutionStage } - return nil + return ExecutionStage_EXECUTION_STAGE_END_BLOCKER } // MsgAddScheduleResponse defines the response structure for executing a @@ -355,42 +355,42 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 556 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xc1, 0x6b, 0xd3, 0x50, - 0x1c, 0x6e, 0xd6, 0xae, 0xd0, 0xd7, 0xd1, 0xb9, 0x58, 0xbb, 0x34, 0x9b, 0x59, 0x08, 0xea, 0x6a, - 0x61, 0x09, 0x56, 0x51, 0xe8, 0x6d, 0x95, 0x81, 0x97, 0x80, 0xa6, 0x7a, 0xd9, 0x65, 0x64, 0xc9, - 0xe3, 0x35, 0x60, 0xf2, 0x42, 0xde, 0x4b, 0xe9, 0x6e, 0xe2, 0x71, 0x27, 0xfd, 0x2b, 0x14, 0xbc, - 0xf4, 0xe0, 0x1f, 0xb1, 0xe3, 0xf0, 0xe4, 0x49, 0xa4, 0x3d, 0xf4, 0xdf, 0x90, 0x24, 0x2f, 0x5b, - 0xde, 0x02, 0x13, 0x04, 0x2f, 0xe9, 0x7b, 0xbf, 0xef, 0xfb, 0x7d, 0xfd, 0x7e, 0x5f, 0x7e, 0x04, - 0xdc, 0x0b, 0x60, 0x4c, 0x23, 0x1c, 0x18, 0x4e, 0xf2, 0xa0, 0x33, 0x3d, 0x8c, 0x30, 0xc5, 0xe2, - 0x06, 0x2b, 0xeb, 0x49, 0x59, 0xde, 0xb2, 0x7d, 0x2f, 0xc0, 0x46, 0xfa, 0xcc, 0x08, 0xf2, 0xb6, - 0x83, 0x89, 0x8f, 0x89, 0xe1, 0x13, 0x64, 0x4c, 0x9f, 0x24, 0x3f, 0x0c, 0xe8, 0x66, 0xc0, 0x49, - 0x7a, 0x33, 0xb2, 0x0b, 0x83, 0xda, 0x08, 0x23, 0x9c, 0xd5, 0x93, 0x53, 0xde, 0xc0, 0x39, 0x08, - 0xed, 0xc8, 0xf6, 0xf3, 0x86, 0x1d, 0x0e, 0x22, 0xce, 0x04, 0xba, 0xf1, 0x7b, 0x98, 0x81, 0xda, - 0x97, 0x35, 0xd0, 0x32, 0x09, 0x3a, 0x74, 0xdd, 0x31, 0x03, 0xc4, 0xe7, 0xa0, 0x61, 0xc7, 0x74, - 0x82, 0x23, 0x8f, 0x9e, 0x49, 0x82, 0x2a, 0xf4, 0x1a, 0x23, 0xe9, 0xc7, 0xf7, 0x83, 0x36, 0x73, - 0x71, 0xe8, 0xba, 0x11, 0x24, 0x64, 0x4c, 0x23, 0x2f, 0x40, 0xd6, 0x35, 0x55, 0x14, 0x41, 0x2d, - 0xb0, 0x7d, 0x28, 0xad, 0x25, 0x2d, 0x56, 0x7a, 0x16, 0x3b, 0xa0, 0x1e, 0xc2, 0xc8, 0xc3, 0xae, - 0x54, 0x55, 0x85, 0x5e, 0xcd, 0x62, 0x37, 0x71, 0x08, 0x6a, 0x3e, 0x41, 0x44, 0xaa, 0xa9, 0xd5, - 0x5e, 0x73, 0xa0, 0xea, 0xc5, 0xa0, 0x74, 0x93, 0xa0, 0xa3, 0x19, 0x74, 0x62, 0x0a, 0x5f, 0xe2, - 0x80, 0x46, 0xb6, 0x43, 0x47, 0xb5, 0x8b, 0x5f, 0x7b, 0x15, 0x2b, 0xed, 0x11, 0x4d, 0x70, 0x07, - 0xa6, 0xb0, 0x87, 0x83, 0x13, 0x42, 0x6d, 0x04, 0x89, 0xb4, 0xae, 0x56, 0x7b, 0xad, 0xc1, 0x2e, - 0xaf, 0x73, 0x94, 0xb3, 0xc6, 0x09, 0x89, 0x69, 0x6c, 0x42, 0xae, 0x4a, 0x86, 0x8f, 0x3e, 0xae, - 0xe6, 0xfd, 0xeb, 0x31, 0xce, 0x57, 0xf3, 0xfe, 0xdd, 0x34, 0x29, 0x3e, 0x16, 0x4d, 0x02, 0x1d, - 0xbe, 0x62, 0x41, 0x12, 0xe2, 0x80, 0x40, 0xed, 0x5c, 0x00, 0x5b, 0x26, 0x41, 0x16, 0xf4, 0xf1, - 0x14, 0xfe, 0x8f, 0x18, 0x87, 0x8f, 0xcb, 0x1e, 0x3b, 0xb9, 0x47, 0xfe, 0x6f, 0xb5, 0x1d, 0xd0, - 0x2d, 0x15, 0xaf, 0x9c, 0x7e, 0x13, 0xc0, 0xa6, 0x49, 0xd0, 0xbb, 0xd0, 0xb5, 0x29, 0x7c, 0x9d, - 0x2e, 0xc9, 0x3f, 0xfb, 0x7c, 0x01, 0xea, 0xd9, 0x9a, 0xa5, 0x4e, 0x9b, 0x83, 0x36, 0x1f, 0x7e, - 0xa6, 0x3e, 0x6a, 0x24, 0xa1, 0x7f, 0x5d, 0xcd, 0xfb, 0x82, 0xc5, 0xe8, 0xc3, 0xfd, 0xf2, 0x30, - 0xed, 0x7c, 0x98, 0xa2, 0x33, 0xad, 0x0b, 0xb6, 0x6f, 0x94, 0xf2, 0x41, 0x06, 0x9f, 0xd7, 0x40, - 0xd5, 0x24, 0x48, 0x7c, 0x03, 0x9a, 0xc5, 0xd5, 0xdd, 0x2d, 0x2d, 0x52, 0x01, 0x95, 0x1f, 0xdc, - 0x86, 0xe6, 0xd2, 0xe2, 0x31, 0x68, 0xdd, 0x78, 0x93, 0x7b, 0xa5, 0x3e, 0x9e, 0x20, 0xef, 0xff, - 0x85, 0x70, 0xa5, 0xfd, 0x16, 0x6c, 0x70, 0xd9, 0xdf, 0x2f, 0x35, 0x16, 0x61, 0xf9, 0xe1, 0xad, - 0x70, 0xae, 0x2a, 0xaf, 0x7f, 0x48, 0xf2, 0x1d, 0xbd, 0xba, 0x58, 0x28, 0xc2, 0xe5, 0x42, 0x11, - 0x7e, 0x2f, 0x14, 0xe1, 0xd3, 0x52, 0xa9, 0x5c, 0x2e, 0x95, 0xca, 0xcf, 0xa5, 0x52, 0x39, 0xd6, - 0x91, 0x47, 0x27, 0xf1, 0xa9, 0xee, 0x60, 0xdf, 0x60, 0x8a, 0x07, 0x38, 0x42, 0xf9, 0xd9, 0x98, - 0x3e, 0x33, 0x66, 0xec, 0xd3, 0x75, 0x16, 0x42, 0x72, 0x5a, 0x4f, 0xbf, 0x0d, 0x4f, 0xff, 0x04, - 0x00, 0x00, 0xff, 0xff, 0xb7, 0x18, 0xba, 0xe9, 0xd7, 0x04, 0x00, 0x00, + // 554 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x6b, 0xdb, 0x40, + 0x14, 0xf6, 0xd9, 0x8e, 0xc1, 0xe7, 0xe0, 0x10, 0xd5, 0x75, 0x64, 0x25, 0x55, 0x8c, 0x68, 0x1b, + 0xd7, 0x10, 0x89, 0xba, 0xa5, 0x05, 0x6f, 0x71, 0x31, 0x74, 0x11, 0xb4, 0x72, 0xbb, 0x64, 0x09, + 0x8a, 0x74, 0x9c, 0x05, 0x95, 0x4e, 0xe8, 0x4e, 0xc6, 0xd9, 0x4a, 0xc7, 0x4c, 0xed, 0x5f, 0xd0, + 0xb5, 0xd0, 0xc5, 0x43, 0xff, 0x88, 0x8c, 0xa1, 0x53, 0xa7, 0x52, 0xec, 0xc1, 0xff, 0x46, 0xd1, + 0xaf, 0x44, 0x17, 0x41, 0x0a, 0x85, 0x2c, 0xa7, 0x7b, 0xef, 0xfb, 0xde, 0xd3, 0x77, 0xdf, 0x3d, + 0x0e, 0xde, 0xf7, 0x50, 0xc8, 0x02, 0xe2, 0x69, 0x56, 0xb4, 0xb0, 0xb9, 0xea, 0x07, 0x84, 0x11, + 0x61, 0x33, 0x4d, 0xab, 0x51, 0x5a, 0xda, 0x36, 0x5d, 0xc7, 0x23, 0x5a, 0xbc, 0x26, 0x04, 0x69, + 0xc7, 0x22, 0xd4, 0x25, 0x54, 0x73, 0x29, 0xd6, 0x66, 0x4f, 0xa3, 0x4f, 0x0a, 0x74, 0x12, 0xe0, + 0x24, 0x8e, 0xb4, 0x24, 0x48, 0xa1, 0x16, 0x26, 0x98, 0x24, 0xf9, 0x68, 0x97, 0x15, 0x70, 0x0a, + 0x7c, 0x33, 0x30, 0xdd, 0xac, 0x60, 0x97, 0x83, 0xa8, 0x35, 0x45, 0x76, 0xf8, 0x01, 0x25, 0xa0, + 0xf2, 0xb5, 0x0c, 0x9b, 0x3a, 0xc5, 0x47, 0xb6, 0x3d, 0x49, 0x01, 0xe1, 0x05, 0xac, 0x9b, 0x21, + 0x9b, 0x92, 0xc0, 0x61, 0x67, 0x22, 0xe8, 0x82, 0x5e, 0x7d, 0x24, 0xfe, 0xfc, 0x71, 0xd8, 0x4a, + 0x55, 0x1c, 0xd9, 0x76, 0x80, 0x28, 0x9d, 0xb0, 0xc0, 0xf1, 0xb0, 0x71, 0x4d, 0x15, 0x04, 0x58, + 0xf5, 0x4c, 0x17, 0x89, 0xe5, 0xa8, 0xc4, 0x88, 0xf7, 0x42, 0x1b, 0xd6, 0x7c, 0x14, 0x38, 0xc4, + 0x16, 0x2b, 0x5d, 0xd0, 0xab, 0x1a, 0x69, 0x24, 0x0c, 0x61, 0xd5, 0xa5, 0x98, 0x8a, 0xd5, 0x6e, + 0xa5, 0xd7, 0x18, 0x74, 0xd5, 0xbc, 0x51, 0xaa, 0x4e, 0xf1, 0x78, 0x8e, 0xac, 0x90, 0xa1, 0x57, + 0xc4, 0x63, 0x81, 0x69, 0xb1, 0x51, 0xf5, 0xe2, 0xf7, 0x7e, 0xc9, 0x88, 0x6b, 0x84, 0x31, 0xdc, + 0x42, 0x31, 0xec, 0x10, 0xef, 0x84, 0x32, 0x13, 0x23, 0x71, 0xa3, 0x0b, 0x7a, 0xcd, 0xc1, 0x1e, + 0xdf, 0x66, 0x9c, 0x91, 0x26, 0x11, 0xc7, 0x68, 0x22, 0x2e, 0x1e, 0x3e, 0xfe, 0xb4, 0x5e, 0xf4, + 0xaf, 0xe5, 0x9f, 0xaf, 0x17, 0xfd, 0x7b, 0xb1, 0x43, 0xbc, 0x1d, 0x8a, 0x08, 0xdb, 0x7c, 0xc6, + 0x40, 0xd4, 0x27, 0x1e, 0x45, 0xca, 0x39, 0x80, 0xdb, 0x3a, 0xc5, 0x06, 0x72, 0xc9, 0x0c, 0xdd, + 0x85, 0x7d, 0xc3, 0x27, 0x45, 0x8d, 0xed, 0x4c, 0x23, 0xff, 0x5b, 0x65, 0x17, 0x76, 0x0a, 0xc9, + 0x2b, 0xa5, 0xdf, 0x01, 0xdc, 0xd2, 0x29, 0x7e, 0xef, 0xdb, 0x26, 0x43, 0x6f, 0xe2, 0xe1, 0xf8, + 0x6f, 0x9d, 0x2f, 0x61, 0x2d, 0x19, 0xaf, 0x58, 0x69, 0x63, 0xd0, 0xe2, 0x5d, 0x4f, 0xba, 0x8f, + 0xea, 0xd1, 0x85, 0x7d, 0x5b, 0x2f, 0xfa, 0xc0, 0x48, 0xe9, 0xc3, 0x83, 0xe2, 0x61, 0x5a, 0xd9, + 0x61, 0xf2, 0xca, 0x94, 0x0e, 0xdc, 0xb9, 0x91, 0xca, 0x0e, 0x32, 0xf8, 0x52, 0x86, 0x15, 0x9d, + 0x62, 0xe1, 0x2d, 0x6c, 0xe4, 0x47, 0x76, 0xaf, 0x30, 0x40, 0x39, 0x54, 0x7a, 0x78, 0x1b, 0x9a, + 0xb5, 0x16, 0x8e, 0x61, 0xf3, 0xc6, 0x4d, 0xee, 0x17, 0xea, 0x78, 0x82, 0x74, 0xf0, 0x0f, 0xc2, + 0x55, 0xef, 0x77, 0x70, 0x93, 0xf3, 0xfe, 0x41, 0xa1, 0x30, 0x0f, 0x4b, 0x8f, 0x6e, 0x85, 0xb3, + 0xae, 0xd2, 0xc6, 0xc7, 0xc8, 0xdf, 0xd1, 0xeb, 0x8b, 0xa5, 0x0c, 0x2e, 0x97, 0x32, 0xf8, 0xb3, + 0x94, 0xc1, 0xe7, 0x95, 0x5c, 0xba, 0x5c, 0xc9, 0xa5, 0x5f, 0x2b, 0xb9, 0x74, 0xac, 0x62, 0x87, + 0x4d, 0xc3, 0x53, 0xd5, 0x22, 0xae, 0x96, 0x76, 0x3c, 0x24, 0x01, 0xce, 0xf6, 0xda, 0xec, 0xb9, + 0x36, 0x4f, 0x9f, 0xac, 0x33, 0x1f, 0xd1, 0xd3, 0x5a, 0xfc, 0x26, 0x3c, 0xfb, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0xf7, 0xca, 0x79, 0x29, 0xcf, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -571,23 +571,10 @@ func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ExecutionStages) > 0 { - dAtA2 := make([]byte, len(m.ExecutionStages)*10) - var j1 int - for _, num := range m.ExecutionStages { - for num >= 1<<7 { - dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) - num >>= 7 - j1++ - } - dAtA2[j1] = uint8(num) - j1++ - } - i -= j1 - copy(dAtA[i:], dAtA2[:j1]) - i = encodeVarintTx(dAtA, i, uint64(j1)) + if m.ExecutionStage != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ExecutionStage)) i-- - dAtA[i] = 0x2a + dAtA[i] = 0x28 } if len(m.Msgs) > 0 { for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { @@ -805,12 +792,8 @@ func (m *MsgAddSchedule) Size() (n int) { n += 1 + l + sovTx(uint64(l)) } } - if len(m.ExecutionStages) > 0 { - l = 0 - for _, e := range m.ExecutionStages { - l += sovTx(uint64(e)) - } - n += 1 + sovTx(uint64(l)) + l + if m.ExecutionStage != 0 { + n += 1 + sovTx(uint64(m.ExecutionStage)) } return n } @@ -1027,73 +1010,23 @@ func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { } iNdEx = postIndex case 5: - if wireType == 0 { - var v ExecutionStage - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ExecutionStages = append(m.ExecutionStages, v) - } else if wireType == 2 { - var packedLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - packedLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if packedLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + packedLen - if postIndex < 0 { - return ErrInvalidLengthTx + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) + } + m.ExecutionStage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx } - if postIndex > l { + if iNdEx >= l { return io.ErrUnexpectedEOF } - var elementCount int - if elementCount != 0 && len(m.ExecutionStages) == 0 { - m.ExecutionStages = make([]ExecutionStage, 0, elementCount) - } - for iNdEx < postIndex { - var v ExecutionStage - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.ExecutionStages = append(m.ExecutionStages, v) + b := dAtA[iNdEx] + iNdEx++ + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break } - } else { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStages", wireType) } default: iNdEx = preIndex From 2bb9d74be31d612ddb69511ecaf43c28cabd9113 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Tue, 27 Aug 2024 10:58:15 -0300 Subject: [PATCH 25/60] rm pagination in single failure resp --- proto/neutron/contractmanager/query.proto | 8 +- .../keeper/grpc_query_failure.go | 4 +- x/contractmanager/types/query.pb.go | 248 +++++++++++++----- x/contractmanager/types/query.pb.gw.go | 18 -- 4 files changed, 189 insertions(+), 89 deletions(-) diff --git a/proto/neutron/contractmanager/query.proto b/proto/neutron/contractmanager/query.proto index f0e597fa1..32280f2ae 100644 --- a/proto/neutron/contractmanager/query.proto +++ b/proto/neutron/contractmanager/query.proto @@ -18,7 +18,7 @@ service Query { } // Queries a Failure by contract address and failure ID. - rpc AddressFailure(QueryFailureRequest) returns (QueryFailuresResponse) { + rpc AddressFailure(QueryFailureRequest) returns (QueryFailureResponse) { option (google.api.http).get = "/neutron/contractmanager/failures/{address}/{failure_id}"; } @@ -57,7 +57,11 @@ message QueryFailureRequest { string address = 1; // ID of the failure for the given contract. uint64 failure_id = 2; - cosmos.base.query.v1beta1.PageRequest pagination = 3; +} + +// QueryFailureResponse is response type for the Query/Failure RPC method. +message QueryFailureResponse { + Failure failure = 1 [(gogoproto.nullable) = false]; } // QueryFailuresResponse is response type for the Query/Failures RPC method. diff --git a/x/contractmanager/keeper/grpc_query_failure.go b/x/contractmanager/keeper/grpc_query_failure.go index d4c6cb99b..27b547acf 100644 --- a/x/contractmanager/keeper/grpc_query_failure.go +++ b/x/contractmanager/keeper/grpc_query_failure.go @@ -59,7 +59,7 @@ func (k Keeper) AddressFailures(c context.Context, req *types.QueryFailuresReque return &types.QueryFailuresResponse{Failures: failures, Pagination: pageRes}, nil } -func (k Keeper) AddressFailure(c context.Context, req *types.QueryFailureRequest) (*types.QueryFailuresResponse, error) { +func (k Keeper) AddressFailure(c context.Context, req *types.QueryFailureRequest) (*types.QueryFailureResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "request field must not be empty") } @@ -74,5 +74,5 @@ func (k Keeper) AddressFailure(c context.Context, req *types.QueryFailureRequest return nil, status.Error(codes.InvalidArgument, err.Error()) } - return &types.QueryFailuresResponse{Failures: []types.Failure{*resp}}, nil + return &types.QueryFailureResponse{Failure: *resp}, nil } diff --git a/x/contractmanager/types/query.pb.go b/x/contractmanager/types/query.pb.go index 3ea9720d0..031468e29 100644 --- a/x/contractmanager/types/query.pb.go +++ b/x/contractmanager/types/query.pb.go @@ -172,8 +172,7 @@ type QueryFailureRequest struct { // address of the contract which Sudo call failed. Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` // ID of the failure for the given contract. - FailureId uint64 `protobuf:"varint,2,opt,name=failure_id,json=failureId,proto3" json:"failure_id,omitempty"` - Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` + FailureId uint64 `protobuf:"varint,2,opt,name=failure_id,json=failureId,proto3" json:"failure_id,omitempty"` } func (m *QueryFailureRequest) Reset() { *m = QueryFailureRequest{} } @@ -223,11 +222,49 @@ func (m *QueryFailureRequest) GetFailureId() uint64 { return 0 } -func (m *QueryFailureRequest) GetPagination() *query.PageRequest { +// QueryFailureResponse is response type for the Query/Failure RPC method. +type QueryFailureResponse struct { + Failure Failure `protobuf:"bytes,1,opt,name=failure,proto3" json:"failure"` +} + +func (m *QueryFailureResponse) Reset() { *m = QueryFailureResponse{} } +func (m *QueryFailureResponse) String() string { return proto.CompactTextString(m) } +func (*QueryFailureResponse) ProtoMessage() {} +func (*QueryFailureResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f9524a427f219917, []int{4} +} +func (m *QueryFailureResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryFailureResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryFailureResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryFailureResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryFailureResponse.Merge(m, src) +} +func (m *QueryFailureResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryFailureResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryFailureResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryFailureResponse proto.InternalMessageInfo + +func (m *QueryFailureResponse) GetFailure() Failure { if m != nil { - return m.Pagination + return m.Failure } - return nil + return Failure{} } // QueryFailuresResponse is response type for the Query/Failures RPC method. @@ -240,7 +277,7 @@ func (m *QueryFailuresResponse) Reset() { *m = QueryFailuresResponse{} } func (m *QueryFailuresResponse) String() string { return proto.CompactTextString(m) } func (*QueryFailuresResponse) ProtoMessage() {} func (*QueryFailuresResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_f9524a427f219917, []int{4} + return fileDescriptor_f9524a427f219917, []int{5} } func (m *QueryFailuresResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -288,6 +325,7 @@ func init() { proto.RegisterType((*QueryParamsResponse)(nil), "neutron.contractmanager.QueryParamsResponse") proto.RegisterType((*QueryFailuresRequest)(nil), "neutron.contractmanager.QueryFailuresRequest") proto.RegisterType((*QueryFailureRequest)(nil), "neutron.contractmanager.QueryFailureRequest") + proto.RegisterType((*QueryFailureResponse)(nil), "neutron.contractmanager.QueryFailureResponse") proto.RegisterType((*QueryFailuresResponse)(nil), "neutron.contractmanager.QueryFailuresResponse") } @@ -296,41 +334,42 @@ func init() { } var fileDescriptor_f9524a427f219917 = []byte{ - // 542 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x41, 0x6b, 0x13, 0x41, - 0x14, 0xc7, 0x33, 0x69, 0x1b, 0xdb, 0x29, 0x28, 0x8c, 0x11, 0x43, 0xd0, 0x4d, 0xba, 0x55, 0x1b, - 0xad, 0x99, 0xa1, 0xa9, 0x07, 0x15, 0x04, 0xcd, 0xa1, 0xe2, 0xad, 0xae, 0x9e, 0xbc, 0xc8, 0x24, - 0x19, 0xd7, 0x85, 0x66, 0x67, 0xbb, 0x33, 0x5b, 0x5a, 0x4a, 0x2f, 0x9e, 0x3c, 0x78, 0x10, 0x14, - 0x3f, 0x81, 0xde, 0xfd, 0x18, 0x3d, 0x16, 0xbc, 0x78, 0x12, 0x49, 0xfc, 0x20, 0x92, 0x99, 0x97, - 0xa6, 0x69, 0x58, 0x37, 0x8a, 0xf4, 0x36, 0x79, 0x79, 0xff, 0xff, 0xfb, 0xed, 0x7f, 0xde, 0x2e, - 0x5e, 0x0e, 0x45, 0xa2, 0x63, 0x19, 0xb2, 0xb6, 0x0c, 0x75, 0xcc, 0xdb, 0xba, 0xcb, 0x43, 0xee, - 0x8b, 0x98, 0x6d, 0x27, 0x22, 0xde, 0xa3, 0x51, 0x2c, 0xb5, 0x24, 0x97, 0xa1, 0x89, 0x9e, 0x6a, - 0x2a, 0xdf, 0x6a, 0x4b, 0xd5, 0x95, 0x8a, 0xb5, 0xb8, 0x12, 0x56, 0xc1, 0x76, 0xd6, 0x5a, 0x42, - 0xf3, 0x35, 0x16, 0x71, 0x3f, 0x08, 0xb9, 0x0e, 0x64, 0x68, 0x4d, 0xca, 0x45, 0x5f, 0xfa, 0xd2, - 0x1c, 0xd9, 0xe0, 0x04, 0xd5, 0x2b, 0xbe, 0x94, 0xfe, 0x96, 0x60, 0x3c, 0x0a, 0x18, 0x0f, 0x43, - 0xa9, 0x8d, 0x44, 0xc1, 0xbf, 0xd7, 0xd3, 0xe8, 0x5e, 0xf1, 0x60, 0x2b, 0x89, 0x05, 0xb4, 0x5d, - 0x4b, 0x6b, 0x8b, 0x78, 0xcc, 0xbb, 0x60, 0xe6, 0x16, 0x31, 0x79, 0x3a, 0x40, 0xdc, 0x34, 0x45, - 0x4f, 0x6c, 0x27, 0x42, 0x69, 0xf7, 0x39, 0xbe, 0x38, 0x56, 0x55, 0x91, 0x0c, 0x95, 0x20, 0x0f, - 0x70, 0xc1, 0x8a, 0x4b, 0xa8, 0x8a, 0x6a, 0x8b, 0x8d, 0x0a, 0x4d, 0xc9, 0x80, 0x5a, 0x61, 0x73, - 0xf6, 0xf0, 0x47, 0x25, 0xe7, 0x81, 0xc8, 0xdd, 0xc5, 0x45, 0xe3, 0xba, 0x61, 0x39, 0x87, 0xd3, - 0x48, 0x09, 0x9f, 0xe3, 0x9d, 0x4e, 0x2c, 0x94, 0xf5, 0x5d, 0xf0, 0x86, 0x3f, 0xc9, 0x06, 0xc6, - 0xa3, 0xc8, 0x4a, 0x33, 0x66, 0xe8, 0x0d, 0x6a, 0xf3, 0xa5, 0x83, 0x7c, 0xa9, 0xbd, 0x11, 0xc8, - 0x97, 0x6e, 0x72, 0x5f, 0x80, 0xab, 0x77, 0x42, 0xe9, 0x7e, 0x42, 0xf0, 0x40, 0x30, 0x3a, 0x7b, - 0xf2, 0x55, 0x8c, 0x21, 0xce, 0x97, 0x41, 0xa7, 0x94, 0xaf, 0xa2, 0xda, 0xac, 0xb7, 0x00, 0x95, - 0x27, 0x9d, 0xff, 0x06, 0xf6, 0x19, 0xe1, 0x4b, 0xa7, 0x32, 0x81, 0xac, 0x9b, 0x78, 0x1e, 0xc6, - 0x0d, 0xd8, 0x66, 0x6a, 0x8b, 0x8d, 0x6a, 0x6a, 0xda, 0x20, 0x86, 0xb8, 0x8f, 0x75, 0xe4, 0xf1, - 0x18, 0x65, 0xde, 0x50, 0xae, 0x64, 0x52, 0x5a, 0x80, 0x93, 0x98, 0x8d, 0xb7, 0x73, 0x78, 0xce, - 0x60, 0x92, 0x77, 0x08, 0x17, 0xec, 0xe5, 0x92, 0xd5, 0x54, 0x9e, 0xc9, 0x8d, 0x2a, 0xdf, 0x9e, - 0xae, 0xd9, 0xce, 0x76, 0x57, 0xde, 0x7c, 0xfb, 0xf5, 0x21, 0xbf, 0x44, 0x2a, 0xec, 0xcf, 0x4b, - 0x4c, 0xbe, 0x22, 0x7c, 0xfe, 0x91, 0xbd, 0x32, 0x08, 0x81, 0x64, 0x4c, 0x1a, 0xdf, 0x80, 0x32, - 0x9d, 0xaa, 0x7b, 0x44, 0xf6, 0xd0, 0x90, 0xdd, 0x27, 0x77, 0x59, 0xc6, 0x5b, 0xa8, 0xd8, 0x3e, - 0xec, 0xd2, 0x01, 0xdb, 0x1f, 0xad, 0xd2, 0x01, 0xf9, 0x82, 0xf0, 0x85, 0x71, 0x64, 0x45, 0xea, - 0xd3, 0x52, 0xfc, 0x1b, 0xf4, 0xba, 0x81, 0xae, 0x93, 0xd5, 0xbf, 0x80, 0x26, 0x1f, 0x11, 0x9e, - 0x3f, 0x2b, 0xc0, 0x9b, 0x06, 0x70, 0x99, 0x2c, 0x65, 0x02, 0x36, 0x9f, 0x1d, 0xf6, 0x1c, 0x74, - 0xd4, 0x73, 0xd0, 0xcf, 0x9e, 0x83, 0xde, 0xf7, 0x9d, 0xdc, 0x51, 0xdf, 0xc9, 0x7d, 0xef, 0x3b, - 0xb9, 0x17, 0xf7, 0xfc, 0x40, 0xbf, 0x4e, 0x5a, 0xb4, 0x2d, 0xbb, 0x43, 0x9b, 0xba, 0x8c, 0xfd, - 0x63, 0xcb, 0x9d, 0x3b, 0x6c, 0x77, 0xc2, 0x57, 0xef, 0x45, 0x42, 0xb5, 0x0a, 0xe6, 0x63, 0xb8, - 0xfe, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xfa, 0xdd, 0x5e, 0x09, 0xf9, 0x05, 0x00, 0x00, + // 557 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x41, 0x4f, 0x13, 0x41, + 0x1c, 0xc5, 0x3b, 0x05, 0x0a, 0x8c, 0x89, 0x26, 0x63, 0x8d, 0x4d, 0xa3, 0xdb, 0xb2, 0xa8, 0xa0, + 0xd8, 0x99, 0x00, 0x1e, 0xd4, 0xc4, 0x04, 0x7b, 0xc0, 0x78, 0x31, 0xb8, 0x7a, 0x30, 0x5e, 0xcc, + 0xb4, 0x1d, 0xd7, 0x4d, 0xe8, 0xce, 0xb2, 0x33, 0x4b, 0x20, 0x84, 0x8b, 0x17, 0x2f, 0x1e, 0x4c, + 0xf4, 0x23, 0xe8, 0xd9, 0xaf, 0xc1, 0x91, 0xc4, 0x8b, 0x27, 0x63, 0x5a, 0x3f, 0x88, 0xe9, 0xcc, + 0xbf, 0x85, 0x85, 0xac, 0xdb, 0x5e, 0xbc, 0x6d, 0xa7, 0xef, 0xbd, 0xff, 0x6f, 0xdf, 0xfc, 0x5b, + 0xbc, 0x18, 0x8a, 0x44, 0xc7, 0x32, 0x64, 0x6d, 0x19, 0xea, 0x98, 0xb7, 0x75, 0x97, 0x87, 0xdc, + 0x17, 0x31, 0xdb, 0x49, 0x44, 0xbc, 0x4f, 0xa3, 0x58, 0x6a, 0x49, 0xae, 0x82, 0x88, 0x9e, 0x11, + 0x55, 0xef, 0xb4, 0xa5, 0xea, 0x4a, 0xc5, 0x5a, 0x5c, 0x09, 0xeb, 0x60, 0xbb, 0xab, 0x2d, 0xa1, + 0xf9, 0x2a, 0x8b, 0xb8, 0x1f, 0x84, 0x5c, 0x07, 0x32, 0xb4, 0x21, 0xd5, 0xb2, 0x2f, 0x7d, 0x69, + 0x1e, 0xd9, 0xe0, 0x09, 0x4e, 0xaf, 0xf9, 0x52, 0xfa, 0xdb, 0x82, 0xf1, 0x28, 0x60, 0x3c, 0x0c, + 0xa5, 0x36, 0x16, 0x05, 0xdf, 0xde, 0xcc, 0xa2, 0x7b, 0xcb, 0x83, 0xed, 0x24, 0x16, 0x20, 0xbb, + 0x91, 0x25, 0x8b, 0x78, 0xcc, 0xbb, 0x10, 0xe6, 0x96, 0x31, 0x79, 0x3e, 0x40, 0xdc, 0x32, 0x87, + 0x9e, 0xd8, 0x49, 0x84, 0xd2, 0xee, 0x4b, 0x7c, 0x39, 0x75, 0xaa, 0x22, 0x19, 0x2a, 0x41, 0x1e, + 0xe1, 0x92, 0x35, 0x57, 0x50, 0x1d, 0x2d, 0x5f, 0x58, 0xab, 0xd1, 0x8c, 0x0e, 0xa8, 0x35, 0x36, + 0xa7, 0x8f, 0x7e, 0xd5, 0x0a, 0x1e, 0x98, 0xdc, 0x3d, 0x5c, 0x36, 0xa9, 0x9b, 0x96, 0x73, 0x38, + 0x8d, 0x54, 0xf0, 0x2c, 0xef, 0x74, 0x62, 0xa1, 0x6c, 0xee, 0xbc, 0x37, 0xfc, 0x48, 0x36, 0x31, + 0x3e, 0xa9, 0xac, 0x32, 0x65, 0x86, 0xde, 0xa2, 0xb6, 0x5f, 0x3a, 0xe8, 0x97, 0xda, 0x1b, 0x81, + 0x7e, 0xe9, 0x16, 0xf7, 0x05, 0xa4, 0x7a, 0xa7, 0x9c, 0xee, 0x33, 0x78, 0x1f, 0x98, 0x9c, 0x3f, + 0xf8, 0x3a, 0xc6, 0xd0, 0xe6, 0x9b, 0xa0, 0x53, 0x29, 0xd6, 0xd1, 0xf2, 0xb4, 0x37, 0x0f, 0x27, + 0x4f, 0x3b, 0xee, 0xab, 0xf4, 0x9b, 0x8c, 0x0a, 0xda, 0xc0, 0xb3, 0x20, 0x82, 0x86, 0xea, 0x99, + 0x0d, 0x81, 0x15, 0x2a, 0x1a, 0xda, 0xdc, 0xaf, 0x08, 0x5f, 0x39, 0x53, 0x12, 0x64, 0x37, 0xf1, + 0x1c, 0x88, 0x06, 0xb4, 0x53, 0x13, 0x84, 0x8f, 0x7c, 0xe4, 0x49, 0xaa, 0xcf, 0xa2, 0x41, 0x5c, + 0xca, 0xed, 0xd3, 0x02, 0x9c, 0x2e, 0x74, 0xed, 0xc3, 0x0c, 0x9e, 0x31, 0x98, 0xe4, 0x23, 0xc2, + 0x25, 0x7b, 0xdb, 0x64, 0x25, 0x93, 0xe7, 0xfc, 0x8a, 0x55, 0xef, 0x8e, 0x27, 0xb6, 0xb3, 0xdd, + 0xa5, 0xf7, 0x3f, 0xfe, 0x7c, 0x2e, 0x2e, 0x90, 0x1a, 0xfb, 0xf7, 0x56, 0x93, 0xef, 0x08, 0x5f, + 0x7c, 0x6c, 0x2f, 0x11, 0x4a, 0x20, 0x39, 0x93, 0xd2, 0x3b, 0x51, 0x6d, 0x8c, 0xa9, 0x06, 0xb0, + 0x0d, 0x03, 0xf6, 0x90, 0xdc, 0x67, 0x39, 0xbf, 0x4a, 0xc5, 0x0e, 0x60, 0xb9, 0x0e, 0xd9, 0xc1, + 0xc9, 0x6e, 0x1d, 0x92, 0x6f, 0x08, 0x5f, 0x4a, 0x13, 0x2b, 0x32, 0x1e, 0xc4, 0xa8, 0x4b, 0x3a, + 0xae, 0x1c, 0xa0, 0xd7, 0x0d, 0x74, 0x83, 0xac, 0x4c, 0x00, 0x4d, 0xbe, 0x20, 0x3c, 0xf7, 0xbf, + 0x00, 0x6f, 0x1b, 0xc0, 0x45, 0xb2, 0x90, 0x0b, 0xd8, 0x7c, 0x71, 0xd4, 0x73, 0xd0, 0x71, 0xcf, + 0x41, 0xbf, 0x7b, 0x0e, 0xfa, 0xd4, 0x77, 0x0a, 0xc7, 0x7d, 0xa7, 0xf0, 0xb3, 0xef, 0x14, 0x5e, + 0x3f, 0xf0, 0x03, 0xfd, 0x2e, 0x69, 0xd1, 0xb6, 0xec, 0x0e, 0x63, 0x1a, 0x32, 0xf6, 0x47, 0x91, + 0xbb, 0xf7, 0xd8, 0xde, 0xb9, 0x5c, 0xbd, 0x1f, 0x09, 0xd5, 0x2a, 0x99, 0x3f, 0xc7, 0xf5, 0xbf, + 0x01, 0x00, 0x00, 0xff, 0xff, 0x22, 0xf1, 0x02, 0x83, 0x09, 0x06, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -348,7 +387,7 @@ type QueryClient interface { // Parameters queries the parameters of the module. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) // Queries a Failure by contract address and failure ID. - AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) + AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailureResponse, error) // Queries Failures by contract address. AddressFailures(ctx context.Context, in *QueryFailuresRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) // Queries a list of Failures occurred on the network. @@ -372,8 +411,8 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } -func (c *queryClient) AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailuresResponse, error) { - out := new(QueryFailuresResponse) +func (c *queryClient) AddressFailure(ctx context.Context, in *QueryFailureRequest, opts ...grpc.CallOption) (*QueryFailureResponse, error) { + out := new(QueryFailureResponse) err := c.cc.Invoke(ctx, "/neutron.contractmanager.Query/AddressFailure", in, out, opts...) if err != nil { return nil, err @@ -404,7 +443,7 @@ type QueryServer interface { // Parameters queries the parameters of the module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) // Queries a Failure by contract address and failure ID. - AddressFailure(context.Context, *QueryFailureRequest) (*QueryFailuresResponse, error) + AddressFailure(context.Context, *QueryFailureRequest) (*QueryFailureResponse, error) // Queries Failures by contract address. AddressFailures(context.Context, *QueryFailuresRequest) (*QueryFailuresResponse, error) // Queries a list of Failures occurred on the network. @@ -418,7 +457,7 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } -func (*UnimplementedQueryServer) AddressFailure(ctx context.Context, req *QueryFailureRequest) (*QueryFailuresResponse, error) { +func (*UnimplementedQueryServer) AddressFailure(ctx context.Context, req *QueryFailureRequest) (*QueryFailureResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddressFailure not implemented") } func (*UnimplementedQueryServer) AddressFailures(ctx context.Context, req *QueryFailuresRequest) (*QueryFailuresResponse, error) { @@ -647,18 +686,6 @@ func (m *QueryFailureRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.Pagination != nil { - { - size, err := m.Pagination.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintQuery(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } if m.FailureId != 0 { i = encodeVarintQuery(dAtA, i, uint64(m.FailureId)) i-- @@ -674,6 +701,39 @@ func (m *QueryFailureRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryFailureResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryFailureResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryFailureResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Failure.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func (m *QueryFailuresResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -784,10 +844,17 @@ func (m *QueryFailureRequest) Size() (n int) { if m.FailureId != 0 { n += 1 + sovQuery(uint64(m.FailureId)) } - if m.Pagination != nil { - l = m.Pagination.Size() - n += 1 + l + sovQuery(uint64(l)) + return n +} + +func (m *QueryFailureResponse) Size() (n int) { + if m == nil { + return 0 } + var l int + _ = l + l = m.Failure.Size() + n += 1 + l + sovQuery(uint64(l)) return n } @@ -1147,9 +1214,59 @@ func (m *QueryFailureRequest) Unmarshal(dAtA []byte) error { break } } - case 3: + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryFailureResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryFailureResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryFailureResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Failure", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1176,10 +1293,7 @@ func (m *QueryFailureRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if m.Pagination == nil { - m.Pagination = &query.PageRequest{} - } - if err := m.Pagination.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.Failure.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/contractmanager/types/query.pb.gw.go b/x/contractmanager/types/query.pb.gw.go index 9570c42b4..90a96f6be 100644 --- a/x/contractmanager/types/query.pb.gw.go +++ b/x/contractmanager/types/query.pb.gw.go @@ -51,10 +51,6 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal } -var ( - filter_Query_AddressFailure_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0, "failure_id": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} -) - func request_Query_AddressFailure_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryFailureRequest var metadata runtime.ServerMetadata @@ -88,13 +84,6 @@ func request_Query_AddressFailure_0(ctx context.Context, marshaler runtime.Marsh return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "failure_id", err) } - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AddressFailure_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.AddressFailure(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -133,13 +122,6 @@ func local_request_Query_AddressFailure_0(ctx context.Context, marshaler runtime return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "failure_id", err) } - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_AddressFailure_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.AddressFailure(ctx, &protoReq) return msg, metadata, err From 88d9c0b34f4721a00986eba9df06938652de3697 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 08:39:39 +0000 Subject: [PATCH 26/60] Bump google.golang.org/grpc from 1.65.0 to 1.66.0 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.65.0 to 1.66.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.65.0...v1.66.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 36fb23e06..f6e7b7368 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 - google.golang.org/grpc v1.65.0 + google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index da994e033..389be92c2 100644 --- a/go.sum +++ b/go.sum @@ -1672,8 +1672,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 554b780b2373466f88f1544bf2c6feebf6d80caa Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 29 Aug 2024 06:50:19 -0300 Subject: [PATCH 27/60] update wasmd --- go.mod | 9 +++++---- go.sum | 16 ++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 36fb23e06..b68531847 100644 --- a/go.mod +++ b/go.mod @@ -14,13 +14,13 @@ require ( cosmossdk.io/x/tx v0.13.4 cosmossdk.io/x/upgrade v0.1.4 github.com/CosmWasm/wasmd v0.51.0 - github.com/CosmWasm/wasmvm/v2 v2.0.3 + github.com/CosmWasm/wasmvm/v2 v2.1.2 github.com/cometbft/cometbft v0.38.11 github.com/cosmos/admin-module/v2 v2.0.0-20240430142959-8b3328d1b1a2 github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.9 - github.com/cosmos/gogoproto v1.6.0 + github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 github.com/cosmos/ibc-go/modules/capability v1.0.1 github.com/cosmos/ibc-go/v8 v8.4.0 @@ -89,7 +89,7 @@ require ( github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/go-bip39 v1.0.0 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect - github.com/cosmos/iavl v1.1.2 // indirect + github.com/cosmos/iavl v1.2.0 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -178,6 +178,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/shamaton/msgpack/v2 v2.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect @@ -218,7 +219,7 @@ require ( replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 - github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.51.2-neutron + github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7 github.com/cosmos/admin-module/v2 => github.com/neutron-org/admin-module/v2 v2.0.2 github.com/cosmos/cosmos-sdk => github.com/neutron-org/cosmos-sdk v0.50.8-neutron // explicitely replace iavl to v1.2.0 cause sometimes go mod tidy uses not right version diff --git a/go.sum b/go.sum index da994e033..0e17b335b 100644 --- a/go.sum +++ b/go.sum @@ -225,8 +225,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CosmWasm/wasmvm/v2 v2.0.3 h1:G9jpwDk+qFUfDkXCigpWPn9JTGM0H7egKzWQnMEONwE= -github.com/CosmWasm/wasmvm/v2 v2.0.3/go.mod h1:su9lg5qLr7adV95eOfzjZWkGiky8WNaNIHDr7Fpu7Ck= +github.com/CosmWasm/wasmvm/v2 v2.1.2 h1:GkJ5bAsRlLHfIQVg/FY1VHwLyBwlCjAhDea0B8L+e20= +github.com/CosmWasm/wasmvm/v2 v2.1.2/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= @@ -367,12 +367,14 @@ github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4x github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= -github.com/cosmos/gogoproto v1.6.0 h1:Xm0F/96O5Ox4g6xGgjA41rWaaPjYtOdTi59uBcV2qEE= -github.com/cosmos/gogoproto v1.6.0/go.mod h1:Y+g956rcUf2vr4uwtCcK/1Xx9BWVluCtcI9vsh0GHmk= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 h1:dyLNlDElY6+5zW/BT/dO/3Ad9FpQblfh+9dQpYQodbA= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2/go.mod h1:82hPO/tRawbuFad2gPwChvpZ0JEIoNi91LwVneAYCeM= +github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd h1:Lx+/5dZ/nN6qPXP2Ofog6u1fmlkCFA1ElcOconnofEM= +github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd/go.mod h1:JWfpWVKJKiKtd53/KbRoKfxWl8FsT2GPcNezTOk0o5Q= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= github.com/cosmos/ibc-go/v8 v8.4.0 h1:K2PfX0AZ+1XKZytHGEMuSjQXG/MZshPb83RSTQt2+cE= @@ -847,8 +849,8 @@ github.com/neutron-org/admin-module/v2 v2.0.2 h1:XDDFWjvkVBKRf3lBFCazT1zAXZ3dHX8 github.com/neutron-org/admin-module/v2 v2.0.2/go.mod h1:RfOyabXsdJ5btcOKyKPZDYiZhtuKFubbJMOb8EJZtvA= github.com/neutron-org/cosmos-sdk v0.50.8-neutron h1:L+4obYi/KkkmS05gBlXNF+FhipHYTl0iO3EkmpMBXkE= github.com/neutron-org/cosmos-sdk v0.50.8-neutron/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= -github.com/neutron-org/wasmd v0.51.2-neutron h1:+Ih6AzySHeB+ArGmmmpXVQNaiX/fvK5ZSbbaMY7+IEE= -github.com/neutron-org/wasmd v0.51.2-neutron/go.mod h1:7TSaj5HoolghujuVWeExqmcUKgpcYWEySGLSODbnnwY= +github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7 h1:p80auAc2CgdsawR73JMV8SYi9U/5sAir+MAd6IEmgR4= +github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7/go.mod h1:FJl/aWjdpGof3usAMFQpDe07Rkx77PUzp0cygFMOvtw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -970,6 +972,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shamaton/msgpack/v2 v2.2.0 h1:IP1m01pHwCrMa6ZccP9B3bqxEMKMSmMVAVKk54g3L/Y= +github.com/shamaton/msgpack/v2 v2.2.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= From 9c66eb6a7e3d5753dc432abdc3bc83bf9c869eff Mon Sep 17 00:00:00 2001 From: nhpd Date: Fri, 30 Aug 2024 17:11:39 +0400 Subject: [PATCH 28/60] cleanup unused thirdparty/proto files --- .../proto/ibc/applications/fee/v1/ack.proto | 15 - .../proto/ibc/applications/fee/v1/fee.proto | 61 --- .../ibc/applications/fee/v1/genesis.proto | 60 --- .../ibc/applications/fee/v1/metadata.proto | 14 - .../proto/ibc/applications/fee/v1/query.proto | 218 -------- .../proto/ibc/applications/fee/v1/tx.proto | 122 ----- .../controller/v1/controller.proto | 12 - .../controller/v1/query.proto | 42 -- .../controller/v1/tx.proto | 82 --- .../genesis/v1/genesis.proto | 47 -- .../interchain_accounts/host/v1/host.proto | 14 - .../interchain_accounts/host/v1/query.proto | 25 - .../interchain_accounts/host/v1/tx.proto | 35 -- .../interchain_accounts/v1/account.proto | 19 - .../interchain_accounts/v1/metadata.proto | 23 - .../interchain_accounts/v1/packet.proto | 31 -- .../proto/ibc/channel/v1/channel.proto | 187 ------- .../proto/ibc/channel/v1/genesis.proto | 30 -- third_party/proto/ibc/channel/v1/query.proto | 459 ----------------- third_party/proto/ibc/channel/v1/tx.proto | 469 ------------------ .../proto/ibc/channel/v1/upgrade.proto | 43 -- third_party/proto/ibc/client/v1/client.proto | 113 ----- third_party/proto/ibc/client/v1/genesis.proto | 44 -- third_party/proto/ibc/client/v1/query.proto | 207 -------- third_party/proto/ibc/client/v1/tx.proto | 175 ------- .../proto/ibc/commitment/v1/commitment.proto | 39 -- .../proto/ibc/connection/v1/connection.proto | 114 ----- .../proto/ibc/connection/v1/genesis.proto | 17 - .../proto/ibc/connection/v1/query.proto | 152 ------ third_party/proto/ibc/connection/v1/tx.proto | 146 ------ .../proto/ibc/core/client/v1/genesis.proto | 44 -- .../proto/ibc/core/client/v1/query.proto | 207 -------- third_party/proto/ibc/core/client/v1/tx.proto | 175 ------- .../ibc/core/commitment/v1/commitment.proto | 39 -- third_party/proto/ibc/fee/v1/ack.proto | 15 - third_party/proto/ibc/fee/v1/fee.proto | 61 --- third_party/proto/ibc/fee/v1/genesis.proto | 60 --- third_party/proto/ibc/fee/v1/metadata.proto | 14 - third_party/proto/ibc/fee/v1/query.proto | 218 -------- third_party/proto/ibc/fee/v1/tx.proto | 122 ----- .../controller/v1/controller.proto | 12 - .../controller/v1/query.proto | 42 -- .../controller/v1/tx.proto | 82 --- .../genesis/v1/genesis.proto | 47 -- .../interchain_accounts/host/v1/host.proto | 14 - .../interchain_accounts/host/v1/query.proto | 25 - .../ibc/interchain_accounts/host/v1/tx.proto | 35 -- .../ibc/interchain_accounts/v1/account.proto | 19 - .../ibc/interchain_accounts/v1/metadata.proto | 23 - .../ibc/interchain_accounts/v1/packet.proto | 31 -- .../lightclients/localhost/v2/localhost.proto | 16 - .../solomachine/v2/solomachine.proto | 189 ------- .../solomachine/v3/solomachine.proto | 99 ---- .../tendermint/v1/tendermint.proto | 101 ---- .../ibc/lightclients/wasm/v1/genesis.proto | 20 - .../ibc/lightclients/wasm/v1/query.proto | 46 -- .../proto/ibc/lightclients/wasm/v1/tx.proto | 66 --- .../proto/ibc/lightclients/wasm/v1/wasm.proto | 43 -- .../proto/ibc/localhost/v2/localhost.proto | 16 - .../ibc/solomachine/v2/solomachine.proto | 189 ------- .../ibc/solomachine/v3/solomachine.proto | 99 ---- .../proto/ibc/tendermint/v1/tendermint.proto | 101 ---- third_party/proto/ibc/transfer/v1/authz.proto | 34 -- .../proto/ibc/transfer/v1/genesis.proto | 20 - third_party/proto/ibc/transfer/v1/query.proto | 121 ----- .../proto/ibc/transfer/v1/transfer.proto | 28 -- third_party/proto/ibc/transfer/v1/tx.proto | 79 --- .../proto/ibc/transfer/v2/packet.proto | 21 - third_party/proto/ibc/types/v1/genesis.proto | 20 - third_party/proto/ibc/wasm/v1/genesis.proto | 20 - third_party/proto/ibc/wasm/v1/query.proto | 46 -- third_party/proto/ibc/wasm/v1/tx.proto | 66 --- third_party/proto/ibc/wasm/v1/wasm.proto | 43 -- 73 files changed, 5783 deletions(-) delete mode 100644 third_party/proto/ibc/applications/fee/v1/ack.proto delete mode 100644 third_party/proto/ibc/applications/fee/v1/fee.proto delete mode 100644 third_party/proto/ibc/applications/fee/v1/genesis.proto delete mode 100644 third_party/proto/ibc/applications/fee/v1/metadata.proto delete mode 100644 third_party/proto/ibc/applications/fee/v1/query.proto delete mode 100644 third_party/proto/ibc/applications/fee/v1/tx.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/host/v1/query.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/v1/account.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto delete mode 100644 third_party/proto/ibc/applications/interchain_accounts/v1/packet.proto delete mode 100644 third_party/proto/ibc/channel/v1/channel.proto delete mode 100644 third_party/proto/ibc/channel/v1/genesis.proto delete mode 100644 third_party/proto/ibc/channel/v1/query.proto delete mode 100644 third_party/proto/ibc/channel/v1/tx.proto delete mode 100644 third_party/proto/ibc/channel/v1/upgrade.proto delete mode 100644 third_party/proto/ibc/client/v1/client.proto delete mode 100644 third_party/proto/ibc/client/v1/genesis.proto delete mode 100644 third_party/proto/ibc/client/v1/query.proto delete mode 100644 third_party/proto/ibc/client/v1/tx.proto delete mode 100644 third_party/proto/ibc/commitment/v1/commitment.proto delete mode 100644 third_party/proto/ibc/connection/v1/connection.proto delete mode 100644 third_party/proto/ibc/connection/v1/genesis.proto delete mode 100644 third_party/proto/ibc/connection/v1/query.proto delete mode 100644 third_party/proto/ibc/connection/v1/tx.proto delete mode 100644 third_party/proto/ibc/core/client/v1/genesis.proto delete mode 100644 third_party/proto/ibc/core/client/v1/query.proto delete mode 100644 third_party/proto/ibc/core/client/v1/tx.proto delete mode 100644 third_party/proto/ibc/core/commitment/v1/commitment.proto delete mode 100644 third_party/proto/ibc/fee/v1/ack.proto delete mode 100644 third_party/proto/ibc/fee/v1/fee.proto delete mode 100644 third_party/proto/ibc/fee/v1/genesis.proto delete mode 100644 third_party/proto/ibc/fee/v1/metadata.proto delete mode 100644 third_party/proto/ibc/fee/v1/query.proto delete mode 100644 third_party/proto/ibc/fee/v1/tx.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/query.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/host.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/query.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/host/v1/tx.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/v1/account.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/v1/metadata.proto delete mode 100644 third_party/proto/ibc/interchain_accounts/v1/packet.proto delete mode 100644 third_party/proto/ibc/lightclients/localhost/v2/localhost.proto delete mode 100644 third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto delete mode 100644 third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto delete mode 100644 third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto delete mode 100644 third_party/proto/ibc/lightclients/wasm/v1/genesis.proto delete mode 100644 third_party/proto/ibc/lightclients/wasm/v1/query.proto delete mode 100644 third_party/proto/ibc/lightclients/wasm/v1/tx.proto delete mode 100644 third_party/proto/ibc/lightclients/wasm/v1/wasm.proto delete mode 100644 third_party/proto/ibc/localhost/v2/localhost.proto delete mode 100644 third_party/proto/ibc/solomachine/v2/solomachine.proto delete mode 100644 third_party/proto/ibc/solomachine/v3/solomachine.proto delete mode 100644 third_party/proto/ibc/tendermint/v1/tendermint.proto delete mode 100644 third_party/proto/ibc/transfer/v1/authz.proto delete mode 100644 third_party/proto/ibc/transfer/v1/genesis.proto delete mode 100644 third_party/proto/ibc/transfer/v1/query.proto delete mode 100644 third_party/proto/ibc/transfer/v1/transfer.proto delete mode 100644 third_party/proto/ibc/transfer/v1/tx.proto delete mode 100644 third_party/proto/ibc/transfer/v2/packet.proto delete mode 100644 third_party/proto/ibc/types/v1/genesis.proto delete mode 100644 third_party/proto/ibc/wasm/v1/genesis.proto delete mode 100644 third_party/proto/ibc/wasm/v1/query.proto delete mode 100644 third_party/proto/ibc/wasm/v1/tx.proto delete mode 100644 third_party/proto/ibc/wasm/v1/wasm.proto diff --git a/third_party/proto/ibc/applications/fee/v1/ack.proto b/third_party/proto/ibc/applications/fee/v1/ack.proto deleted file mode 100644 index 2f3746d2c..000000000 --- a/third_party/proto/ibc/applications/fee/v1/ack.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware -message IncentivizedAcknowledgement { - // the underlying app acknowledgement bytes - bytes app_acknowledgement = 1; - // the relayer address which submits the recv packet message - string forward_relayer_address = 2; - // success flag of the base application callback - bool underlying_app_success = 3; -} diff --git a/third_party/proto/ibc/applications/fee/v1/fee.proto b/third_party/proto/ibc/applications/fee/v1/fee.proto deleted file mode 100644 index 867e88455..000000000 --- a/third_party/proto/ibc/applications/fee/v1/fee.proto +++ /dev/null @@ -1,61 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "amino/amino.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "cosmos/msg/v1/msg.proto"; - -// Fee defines the ICS29 receive, acknowledgement and timeout fees -message Fee { - // the packet receive fee - repeated cosmos.base.v1beta1.Coin recv_fee = 1 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; - - // the packet acknowledgement fee - repeated cosmos.base.v1beta1.Coin ack_fee = 2 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; - - // the packet timeout fee - repeated cosmos.base.v1beta1.Coin timeout_fee = 3 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; -} - -// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers -message PacketFee { - option (cosmos.msg.v1.signer) = "refund_address"; - - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee fee = 1 [(gogoproto.nullable) = false]; - // the refund address for unspent fees - string refund_address = 2; - // optional list of relayers permitted to receive fees - repeated string relayers = 3; -} - -// PacketFees contains a list of type PacketFee -message PacketFees { - // list of packet fees - repeated PacketFee packet_fees = 1 [(gogoproto.nullable) = false]; -} - -// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId -message IdentifiedPacketFees { - // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; - // list of packet fees - repeated PacketFee packet_fees = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/applications/fee/v1/genesis.proto b/third_party/proto/ibc/applications/fee/v1/genesis.proto deleted file mode 100644 index e48ceb535..000000000 --- a/third_party/proto/ibc/applications/fee/v1/genesis.proto +++ /dev/null @@ -1,60 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// GenesisState defines the ICS29 fee middleware genesis state -message GenesisState { - // list of identified packet fees - repeated IdentifiedPacketFees identified_fees = 1 [(gogoproto.nullable) = false]; - // list of fee enabled channels - repeated FeeEnabledChannel fee_enabled_channels = 2 [(gogoproto.nullable) = false]; - // list of registered payees - repeated RegisteredPayee registered_payees = 3 [(gogoproto.nullable) = false]; - // list of registered counterparty payees - repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 [(gogoproto.nullable) = false]; - // list of forward relayer addresses - repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.nullable) = false]; -} - -// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel -message FeeEnabledChannel { - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; -} - -// RegisteredPayee contains the relayer address and payee address for a specific channel -message RegisteredPayee { - // unique channel identifier - string channel_id = 1; - // the relayer address - string relayer = 2; - // the payee address - string payee = 3; -} - -// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used -// for recv fee distribution) -message RegisteredCounterpartyPayee { - // unique channel identifier - string channel_id = 1; - // the relayer address - string relayer = 2; - // the counterparty payee address - string counterparty_payee = 3; -} - -// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements -message ForwardRelayerAddress { - // the forward relayer address - string address = 1; - // unique packet identifer comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/applications/fee/v1/metadata.proto b/third_party/proto/ibc/applications/fee/v1/metadata.proto deleted file mode 100644 index 1e82e7c25..000000000 --- a/third_party/proto/ibc/applications/fee/v1/metadata.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring -// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning -message Metadata { - // fee_version defines the ICS29 fee version - string fee_version = 1; - // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring - string app_version = 2; -} diff --git a/third_party/proto/ibc/applications/fee/v1/query.proto b/third_party/proto/ibc/applications/fee/v1/query.proto deleted file mode 100644 index 726370ee0..000000000 --- a/third_party/proto/ibc/applications/fee/v1/query.proto +++ /dev/null @@ -1,218 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "gogoproto/gogo.proto"; -import "google/api/annotations.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/applications/fee/v1/genesis.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Query defines the ICS29 gRPC querier service. -service Query { - // IncentivizedPackets returns all incentivized packets and their associated fees - rpc IncentivizedPackets(QueryIncentivizedPacketsRequest) returns (QueryIncentivizedPacketsResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets"; - } - - // IncentivizedPacket returns all packet fees for a packet given its identifier - rpc IncentivizedPacket(QueryIncentivizedPacketRequest) returns (QueryIncentivizedPacketResponse) { - option (google.api.http).get = - "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/" - "{packet_id.sequence}/incentivized_packet"; - } - - // Gets all incentivized packets for a specific channel - rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) - returns (QueryIncentivizedPacketsForChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets"; - } - - // TotalRecvFees returns the total receive fees for a packet given its identifier - rpc TotalRecvFees(QueryTotalRecvFeesRequest) returns (QueryTotalRecvFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_recv_fees"; - } - - // TotalAckFees returns the total acknowledgement fees for a packet given its identifier - rpc TotalAckFees(QueryTotalAckFeesRequest) returns (QueryTotalAckFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_ack_fees"; - } - - // TotalTimeoutFees returns the total timeout fees for a packet given its identifier - rpc TotalTimeoutFees(QueryTotalTimeoutFeesRequest) returns (QueryTotalTimeoutFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_timeout_fees"; - } - - // Payee returns the registered payee address for a specific channel given the relayer address - rpc Payee(QueryPayeeRequest) returns (QueryPayeeResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee"; - } - - // CounterpartyPayee returns the registered counterparty payee for forward relaying - rpc CounterpartyPayee(QueryCounterpartyPayeeRequest) returns (QueryCounterpartyPayeeResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee"; - } - - // FeeEnabledChannels returns a list of all fee enabled channels - rpc FeeEnabledChannels(QueryFeeEnabledChannelsRequest) returns (QueryFeeEnabledChannelsResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled"; - } - - // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel - rpc FeeEnabledChannel(QueryFeeEnabledChannelRequest) returns (QueryFeeEnabledChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled"; - } -} - -// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc -message QueryIncentivizedPacketsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - // block height at which to query - uint64 query_height = 2; -} - -// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc -message QueryIncentivizedPacketsResponse { - // list of identified fees for incentivized packets - repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc -message QueryIncentivizedPacketRequest { - // unique packet identifier comprised of channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; - // block height at which to query - uint64 query_height = 2; -} - -// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc -message QueryIncentivizedPacketResponse { - // the identified fees for the incentivized packet - ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packet = 1 [(gogoproto.nullable) = false]; -} - -// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets -// for a specific channel -message QueryIncentivizedPacketsForChannelRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - string port_id = 2; - string channel_id = 3; - // Height to query at - uint64 query_height = 4; -} - -// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC -message QueryIncentivizedPacketsForChannelResponse { - // Map of all incentivized_packets - repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc -message QueryTotalRecvFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc -message QueryTotalRecvFeesResponse { - // the total packet receive fees - repeated cosmos.base.v1beta1.Coin recv_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc -message QueryTotalAckFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc -message QueryTotalAckFeesResponse { - // the total packet acknowledgement fees - repeated cosmos.base.v1beta1.Coin ack_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc -message QueryTotalTimeoutFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc -message QueryTotalTimeoutFeesResponse { - // the total packet timeout fees - repeated cosmos.base.v1beta1.Coin timeout_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryPayeeRequest defines the request type for the Payee rpc -message QueryPayeeRequest { - // unique channel identifier - string channel_id = 1; - // the relayer address to which the distribution address is registered - string relayer = 2; -} - -// QueryPayeeResponse defines the response type for the Payee rpc -message QueryPayeeResponse { - // the payee address to which packet fees are paid out - string payee_address = 1; -} - -// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc -message QueryCounterpartyPayeeRequest { - // unique channel identifier - string channel_id = 1; - // the relayer address to which the counterparty is registered - string relayer = 2; -} - -// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc -message QueryCounterpartyPayeeResponse { - // the counterparty payee address used to compensate forward relaying - string counterparty_payee = 1; -} - -// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc -message QueryFeeEnabledChannelsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - // block height at which to query - uint64 query_height = 2; -} - -// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc -message QueryFeeEnabledChannelsResponse { - // list of fee enabled channels - repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc -message QueryFeeEnabledChannelRequest { - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; -} - -// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc -message QueryFeeEnabledChannelResponse { - // boolean flag representing the fee enabled channel status - bool fee_enabled = 1; -} diff --git a/third_party/proto/ibc/applications/fee/v1/tx.proto b/third_party/proto/ibc/applications/fee/v1/tx.proto deleted file mode 100644 index e59dddfd1..000000000 --- a/third_party/proto/ibc/applications/fee/v1/tx.proto +++ /dev/null @@ -1,122 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "amino/amino.proto"; -import "gogoproto/gogo.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "cosmos/msg/v1/msg.proto"; - -// Msg defines the ICS29 Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // RegisterPayee defines a rpc handler method for MsgRegisterPayee - // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on - // the source chain from which packets originate as this is where fee distribution takes place. This function may be - // called more than once by a relayer, in which case, the latest payee is always used. - rpc RegisterPayee(MsgRegisterPayee) returns (MsgRegisterPayeeResponse); - - // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee - // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty - // payee address before relaying. This ensures they will be properly compensated for forward relaying since - // the destination chain must include the registered counterparty payee address in the acknowledgement. This function - // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. - rpc RegisterCounterpartyPayee(MsgRegisterCounterpartyPayee) returns (MsgRegisterCounterpartyPayeeResponse); - - // PayPacketFee defines a rpc handler method for MsgPayPacketFee - // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to - // incentivize the relaying of the packet at the next sequence - // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows - // initiates the lifecycle of the incentivized packet - rpc PayPacketFee(MsgPayPacketFee) returns (MsgPayPacketFeeResponse); - - // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync - // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to - // incentivize the relaying of a known packet (i.e. at a particular sequence) - rpc PayPacketFeeAsync(MsgPayPacketFeeAsync) returns (MsgPayPacketFeeAsyncResponse); -} - -// MsgRegisterPayee defines the request type for the RegisterPayee rpc -message MsgRegisterPayee { - option (amino.name) = "cosmos-sdk/MsgRegisterPayee"; - option (cosmos.msg.v1.signer) = "relayer"; - - option (gogoproto.goproto_getters) = false; - - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; - // the relayer address - string relayer = 3; - // the payee address - string payee = 4; -} - -// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc -message MsgRegisterPayeeResponse {} - -// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc -message MsgRegisterCounterpartyPayee { - option (amino.name) = "cosmos-sdk/MsgRegisterCounterpartyPayee"; - option (cosmos.msg.v1.signer) = "relayer"; - - option (gogoproto.goproto_getters) = false; - - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; - // the relayer address - string relayer = 3; - // the counterparty payee address - string counterparty_payee = 4; -} - -// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc -message MsgRegisterCounterpartyPayeeResponse {} - -// MsgPayPacketFee defines the request type for the PayPacketFee rpc -// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be -// paid for -message MsgPayPacketFee { - option (amino.name) = "cosmos-sdk/MsgPayPacketFee"; - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // the source port unique identifier - string source_port_id = 2; - // the source channel unique identifer - string source_channel_id = 3; - // account address to refund fee if necessary - string signer = 4; - // optional list of relayers permitted to the receive packet fees - repeated string relayers = 5; -} - -// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc -message MsgPayPacketFeeResponse {} - -// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc -// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) -message MsgPayPacketFeeAsync { - option (amino.name) = "cosmos-sdk/MsgPayPacketFeeAsync"; - option (cosmos.msg.v1.signer) = "packet_fee"; - option (gogoproto.goproto_getters) = false; - - // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // the packet fee associated with a particular IBC packet - PacketFee packet_fee = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; -} - -// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc -message MsgPayPacketFeeAsyncResponse {} diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto deleted file mode 100644 index 2e6bbe1a1..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/controller.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -// Params defines the set of on-chain interchain accounts parameters. -// The following parameters may be used to disable the controller submodule. -message Params { - // controller_enabled enables or disables the controller submodule. - bool controller_enabled = 1; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto deleted file mode 100644 index 31885fcb2..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/query.proto +++ /dev/null @@ -1,42 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "google/api/annotations.proto"; - -// Query provides defines the gRPC querier service. -service Query { - // InterchainAccount returns the interchain account address for a given owner address on a given connection - rpc InterchainAccount(QueryInterchainAccountRequest) returns (QueryInterchainAccountResponse) { - option (google.api.http).get = - "/ibc/apps/interchain_accounts/controller/v1/owners/{owner}/connections/{connection_id}"; - } - - // Params queries all parameters of the ICA controller submodule. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/ibc/apps/interchain_accounts/controller/v1/params"; - } -} - -// QueryInterchainAccountRequest is the request type for the Query/InterchainAccount RPC method. -message QueryInterchainAccountRequest { - string owner = 1; - string connection_id = 2; -} - -// QueryInterchainAccountResponse the response type for the Query/InterchainAccount RPC method. -message QueryInterchainAccountResponse { - string address = 1; -} - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto b/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto deleted file mode 100644 index ec5c2e62e..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/controller/v1/tx.proto +++ /dev/null @@ -1,82 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/interchain_accounts/v1/packet.proto"; -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "cosmos/msg/v1/msg.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Msg defines the 27-interchain-accounts/controller Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // RegisterInterchainAccount defines a rpc handler for MsgRegisterInterchainAccount. - rpc RegisterInterchainAccount(MsgRegisterInterchainAccount) returns (MsgRegisterInterchainAccountResponse); - // SendTx defines a rpc handler for MsgSendTx. - rpc SendTx(MsgSendTx) returns (MsgSendTxResponse); - // UpdateParams defines a rpc handler for MsgUpdateParams. - rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgRegisterInterchainAccount defines the payload for Msg/RegisterAccount -message MsgRegisterInterchainAccount { - option (cosmos.msg.v1.signer) = "owner"; - - option (gogoproto.goproto_getters) = false; - - string owner = 1; - string connection_id = 2; - string version = 3; - ibc.core.channel.v1.Order ordering = 4; -} - -// MsgRegisterInterchainAccountResponse defines the response for Msg/RegisterAccount -message MsgRegisterInterchainAccountResponse { - option (gogoproto.goproto_getters) = false; - - string channel_id = 1; - string port_id = 2; -} - -// MsgSendTx defines the payload for Msg/SendTx -message MsgSendTx { - option (cosmos.msg.v1.signer) = "owner"; - - option (gogoproto.goproto_getters) = false; - - string owner = 1; - string connection_id = 2; - ibc.applications.interchain_accounts.v1.InterchainAccountPacketData packet_data = 3 [(gogoproto.nullable) = false]; - // Relative timeout timestamp provided will be added to the current block time during transaction execution. - // The timeout timestamp must be non-zero. - uint64 relative_timeout = 4; -} - -// MsgSendTxResponse defines the response for MsgSendTx -message MsgSendTxResponse { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; -} - -// MsgUpdateParams defines the payload for Msg/UpdateParams -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the 27-interchain-accounts/controller parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response for Msg/UpdateParams -message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto b/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto deleted file mode 100644 index 4393e5b0b..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/genesis/v1/genesis.proto +++ /dev/null @@ -1,47 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.genesis.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/genesis/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// GenesisState defines the interchain accounts genesis state -message GenesisState { - ControllerGenesisState controller_genesis_state = 1 [(gogoproto.nullable) = false]; - HostGenesisState host_genesis_state = 2 [(gogoproto.nullable) = false]; -} - -// ControllerGenesisState defines the interchain accounts controller genesis state -message ControllerGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; - repeated string ports = 3; - ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; -} - -// HostGenesisState defines the interchain accounts host genesis state -message HostGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; - string port = 3; - ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; -} - -// ActiveChannel contains a connection ID, port ID and associated active channel ID, as well as a boolean flag to -// indicate if the channel is middleware enabled -message ActiveChannel { - string connection_id = 1; - string port_id = 2; - string channel_id = 3; - bool is_middleware_enabled = 4; -} - -// RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address -message RegisteredInterchainAccount { - string connection_id = 1; - string port_id = 2; - string account_address = 3; -} \ No newline at end of file diff --git a/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto b/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto deleted file mode 100644 index f03685711..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/host/v1/host.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -// Params defines the set of on-chain interchain accounts parameters. -// The following parameters may be used to disable the host submodule. -message Params { - // host_enabled enables or disables the host submodule. - bool host_enabled = 1; - // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. - repeated string allow_messages = 2; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/host/v1/query.proto b/third_party/proto/ibc/applications/interchain_accounts/host/v1/query.proto deleted file mode 100644 index 6f206a14c..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/host/v1/query.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -import "google/api/annotations.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// Query provides defines the gRPC querier service. -service Query { - // Params queries all parameters of the ICA host submodule. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/ibc/apps/interchain_accounts/host/v1/params"; - } -} - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto b/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto deleted file mode 100644 index 5a8073bc9..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/host/v1/tx.proto +++ /dev/null @@ -1,35 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/msg/v1/msg.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// Msg defines the 27-interchain-accounts/host Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // UpdateParams defines a rpc handler for MsgUpdateParams. - rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgUpdateParams defines the payload for Msg/UpdateParams -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the 27-interchain-accounts/host parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response for Msg/UpdateParams -message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto b/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto deleted file mode 100644 index 4a6947c1c..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/v1/account.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; -import "cosmos/auth/v1beta1/auth.proto"; - -// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain -message InterchainAccount { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (cosmos_proto.implements_interface) = "ibc.applications.interchain_accounts.v1.InterchainAccountI"; - - cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; - string account_owner = 2; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto b/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto deleted file mode 100644 index df72b41eb..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/v1/metadata.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring -// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning -message Metadata { - // version defines the ICS27 protocol version - string version = 1; - // controller_connection_id is the connection identifier associated with the controller chain - string controller_connection_id = 2; - // host_connection_id is the connection identifier associated with the host chain - string host_connection_id = 3; - // address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step - // NOTE: the address field is empty on the OnChanOpenInit handshake step - string address = 4; - // encoding defines the supported codec format - string encoding = 5; - // tx_type defines the type of transactions the interchain account can execute - string tx_type = 6; -} diff --git a/third_party/proto/ibc/applications/interchain_accounts/v1/packet.proto b/third_party/proto/ibc/applications/interchain_accounts/v1/packet.proto deleted file mode 100644 index f75a1463e..000000000 --- a/third_party/proto/ibc/applications/interchain_accounts/v1/packet.proto +++ /dev/null @@ -1,31 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -import "google/protobuf/any.proto"; -import "gogoproto/gogo.proto"; - -// Type defines a classification of message issued from a controller chain to its associated interchain accounts -// host -enum Type { - option (gogoproto.goproto_enum_prefix) = false; - - // Default zero value enumeration - TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Execute a transaction on an interchain accounts host chain - TYPE_EXECUTE_TX = 1 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; -} - -// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. -message InterchainAccountPacketData { - Type type = 1; - bytes data = 2; - string memo = 3; -} - -// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. -message CosmosTx { - repeated google.protobuf.Any messages = 1; -} diff --git a/third_party/proto/ibc/channel/v1/channel.proto b/third_party/proto/ibc/channel/v1/channel.proto deleted file mode 100644 index 05a18fefb..000000000 --- a/third_party/proto/ibc/channel/v1/channel.proto +++ /dev/null @@ -1,187 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -// Channel defines pipeline for exactly-once packet delivery between specific -// modules on separate blockchains, which has at least one end capable of -// sending packets and one end capable of receiving packets. -message Channel { - option (gogoproto.goproto_getters) = false; - - // current state of the channel end - State state = 1; - // whether the channel is ordered or unordered - Order ordering = 2; - // counterparty channel end - Counterparty counterparty = 3 [(gogoproto.nullable) = false]; - // list of connection identifiers, in order, along which packets sent on - // this channel will travel - repeated string connection_hops = 4; - // opaque channel version, which is agreed upon during the handshake - string version = 5; - // upgrade sequence indicates the latest upgrade attempt performed by this channel - // the value of 0 indicates the channel has never been upgraded - uint64 upgrade_sequence = 6; -} - -// IdentifiedChannel defines a channel with additional port and channel -// identifier fields. -message IdentifiedChannel { - option (gogoproto.goproto_getters) = false; - - // current state of the channel end - State state = 1; - // whether the channel is ordered or unordered - Order ordering = 2; - // counterparty channel end - Counterparty counterparty = 3 [(gogoproto.nullable) = false]; - // list of connection identifiers, in order, along which packets sent on - // this channel will travel - repeated string connection_hops = 4; - // opaque channel version, which is agreed upon during the handshake - string version = 5; - // port identifier - string port_id = 6; - // channel identifier - string channel_id = 7; - // upgrade sequence indicates the latest upgrade attempt performed by this channel - // the value of 0 indicates the channel has never been upgraded - uint64 upgrade_sequence = 8; -} - -// State defines if a channel is in one of the following states: -// CLOSED, INIT, TRYOPEN, OPEN, FLUSHING, FLUSHCOMPLETE or UNINITIALIZED. -enum State { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; - // A channel has just started the opening handshake. - STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; - // A channel has acknowledged the handshake step on the counterparty chain. - STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; - // A channel has completed the handshake. Open channels are - // ready to send and receive packets. - STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; - // A channel has been closed and can no longer be used to send or receive - // packets. - STATE_CLOSED = 4 [(gogoproto.enumvalue_customname) = "CLOSED"]; - // A channel has just accepted the upgrade handshake attempt and is flushing in-flight packets. - STATE_FLUSHING = 5 [(gogoproto.enumvalue_customname) = "FLUSHING"]; - // A channel has just completed flushing any in-flight packets. - STATE_FLUSHCOMPLETE = 6 [(gogoproto.enumvalue_customname) = "FLUSHCOMPLETE"]; -} - -// Order defines if a channel is ORDERED or UNORDERED -enum Order { - option (gogoproto.goproto_enum_prefix) = false; - - // zero-value for channel ordering - ORDER_NONE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "NONE"]; - // packets can be delivered in any order, which may differ from the order in - // which they were sent. - ORDER_UNORDERED = 1 [(gogoproto.enumvalue_customname) = "UNORDERED"]; - // packets are delivered exactly in the order which they were sent - ORDER_ORDERED = 2 [(gogoproto.enumvalue_customname) = "ORDERED"]; -} - -// Counterparty defines a channel end counterparty -message Counterparty { - option (gogoproto.goproto_getters) = false; - - // port on the counterparty chain which owns the other end of the channel. - string port_id = 1; - // channel end on the counterparty chain - string channel_id = 2; -} - -// Packet defines a type that carries data across different chains through IBC -message Packet { - option (gogoproto.goproto_getters) = false; - - // number corresponds to the order of sends and receives, where a Packet - // with an earlier sequence number must be sent and received before a Packet - // with a later sequence number. - uint64 sequence = 1; - // identifies the port on the sending chain. - string source_port = 2; - // identifies the channel end on the sending chain. - string source_channel = 3; - // identifies the port on the receiving chain. - string destination_port = 4; - // identifies the channel end on the receiving chain. - string destination_channel = 5; - // actual opaque bytes transferred directly to the application module - bytes data = 6; - // block height after which the packet times out - ibc.core.client.v1.Height timeout_height = 7 [(gogoproto.nullable) = false]; - // block timestamp (in nanoseconds) after which the packet times out - uint64 timeout_timestamp = 8; -} - -// PacketState defines the generic type necessary to retrieve and store -// packet commitments, acknowledgements, and receipts. -// Caller is responsible for knowing the context necessary to interpret this -// state as a commitment, acknowledgement, or a receipt. -message PacketState { - option (gogoproto.goproto_getters) = false; - - // channel port identifier. - string port_id = 1; - // channel unique identifier. - string channel_id = 2; - // packet sequence. - uint64 sequence = 3; - // embedded data that represents packet state. - bytes data = 4; -} - -// PacketId is an identifer for a unique Packet -// Source chains refer to packets by source port/channel -// Destination chains refer to packets by destination port/channel -message PacketId { - option (gogoproto.goproto_getters) = false; - - // channel port identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// Acknowledgement is the recommended acknowledgement format to be used by -// app-specific protocols. -// NOTE: The field numbers 21 and 22 were explicitly chosen to avoid accidental -// conflicts with other protobuf message formats used for acknowledgements. -// The first byte of any message with this format will be the non-ASCII values -// `0xaa` (result) or `0xb2` (error). Implemented as defined by ICS: -// https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#acknowledgement-envelope -message Acknowledgement { - // response contains either a result or an error and must be non-empty - oneof response { - bytes result = 21; - string error = 22; - } -} - -// Timeout defines an execution deadline structure for 04-channel handlers. -// This includes packet lifecycle handlers as well as the upgrade handshake handlers. -// A valid Timeout contains either one or both of a timestamp and block height (sequence). -message Timeout { - // block height after which the packet or upgrade times out - ibc.core.client.v1.Height height = 1 [(gogoproto.nullable) = false]; - // block timestamp (in nanoseconds) after which the packet or upgrade times out - uint64 timestamp = 2; -} - -// Params defines the set of IBC channel parameters. -message Params { - // the relative timeout after which channel upgrades will time out. - Timeout upgrade_timeout = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/channel/v1/genesis.proto b/third_party/proto/ibc/channel/v1/genesis.proto deleted file mode 100644 index 665b2b156..000000000 --- a/third_party/proto/ibc/channel/v1/genesis.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// GenesisState defines the ibc channel submodule's genesis state. -message GenesisState { - repeated IdentifiedChannel channels = 1 [(gogoproto.casttype) = "IdentifiedChannel", (gogoproto.nullable) = false]; - repeated PacketState acknowledgements = 2 [(gogoproto.nullable) = false]; - repeated PacketState commitments = 3 [(gogoproto.nullable) = false]; - repeated PacketState receipts = 4 [(gogoproto.nullable) = false]; - repeated PacketSequence send_sequences = 5 [(gogoproto.nullable) = false]; - repeated PacketSequence recv_sequences = 6 [(gogoproto.nullable) = false]; - repeated PacketSequence ack_sequences = 7 [(gogoproto.nullable) = false]; - // the sequence for the next generated channel identifier - uint64 next_channel_sequence = 8; - Params params = 9 [(gogoproto.nullable) = false]; -} - -// PacketSequence defines the genesis type necessary to retrieve and store -// next send and receive sequences. -message PacketSequence { - string port_id = 1; - string channel_id = 2; - uint64 sequence = 3; -} diff --git a/third_party/proto/ibc/channel/v1/query.proto b/third_party/proto/ibc/channel/v1/query.proto deleted file mode 100644 index f89d21273..000000000 --- a/third_party/proto/ibc/channel/v1/query.proto +++ /dev/null @@ -1,459 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; - -import "ibc/core/client/v1/client.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "google/api/annotations.proto"; -import "google/protobuf/any.proto"; -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/upgrade.proto"; - -// Query provides defines the gRPC querier service -service Query { - // Channel queries an IBC Channel. - rpc Channel(QueryChannelRequest) returns (QueryChannelResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}"; - } - - // Channels queries all the IBC channels of a chain. - rpc Channels(QueryChannelsRequest) returns (QueryChannelsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels"; - } - - // ConnectionChannels queries all the channels associated with a connection - // end. - rpc ConnectionChannels(QueryConnectionChannelsRequest) returns (QueryConnectionChannelsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/connections/{connection}/channels"; - } - - // ChannelClientState queries for the client state for the channel associated - // with the provided channel identifiers. - rpc ChannelClientState(QueryChannelClientStateRequest) returns (QueryChannelClientStateResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/client_state"; - } - - // ChannelConsensusState queries for the consensus state for the channel - // associated with the provided channel identifiers. - rpc ChannelConsensusState(QueryChannelConsensusStateRequest) returns (QueryChannelConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/consensus_state/revision/" - "{revision_number}/height/{revision_height}"; - } - - // PacketCommitment queries a stored packet commitment hash. - rpc PacketCommitment(QueryPacketCommitmentRequest) returns (QueryPacketCommitmentResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" - "packet_commitments/{sequence}"; - } - - // PacketCommitments returns all the packet commitments hashes associated - // with a channel. - rpc PacketCommitments(QueryPacketCommitmentsRequest) returns (QueryPacketCommitmentsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_commitments"; - } - - // PacketReceipt queries if a given packet sequence has been received on the - // queried chain - rpc PacketReceipt(QueryPacketReceiptRequest) returns (QueryPacketReceiptResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_receipts/{sequence}"; - } - - // PacketAcknowledgement queries a stored packet acknowledgement hash. - rpc PacketAcknowledgement(QueryPacketAcknowledgementRequest) returns (QueryPacketAcknowledgementResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_acks/{sequence}"; - } - - // PacketAcknowledgements returns all the packet acknowledgements associated - // with a channel. - rpc PacketAcknowledgements(QueryPacketAcknowledgementsRequest) returns (QueryPacketAcknowledgementsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_acknowledgements"; - } - - // UnreceivedPackets returns all the unreceived IBC packets associated with a - // channel and sequences. - rpc UnreceivedPackets(QueryUnreceivedPacketsRequest) returns (QueryUnreceivedPacketsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/ports/{port_id}/" - "packet_commitments/" - "{packet_commitment_sequences}/unreceived_packets"; - } - - // UnreceivedAcks returns all the unreceived IBC acknowledgements associated - // with a channel and sequences. - rpc UnreceivedAcks(QueryUnreceivedAcksRequest) returns (QueryUnreceivedAcksResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/packet_commitments/" - "{packet_ack_sequences}/unreceived_acks"; - } - - // NextSequenceReceive returns the next receive sequence for a given channel. - rpc NextSequenceReceive(QueryNextSequenceReceiveRequest) returns (QueryNextSequenceReceiveResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/next_sequence"; - } - - // NextSequenceSend returns the next send sequence for a given channel. - rpc NextSequenceSend(QueryNextSequenceSendRequest) returns (QueryNextSequenceSendResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/next_sequence_send"; - } - - // UpgradeError returns the error receipt if the upgrade handshake failed. - rpc UpgradeError(QueryUpgradeErrorRequest) returns (QueryUpgradeErrorResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/upgrade_error"; - } - - // Upgrade returns the upgrade for a given port and channel id. - rpc Upgrade(QueryUpgradeRequest) returns (QueryUpgradeResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/channels/{channel_id}/" - "ports/{port_id}/upgrade"; - } - - // ChannelParams queries all parameters of the ibc channel submodule. - rpc ChannelParams(QueryChannelParamsRequest) returns (QueryChannelParamsResponse) { - option (google.api.http).get = "/ibc/core/channel/v1/params"; - } -} - -// QueryChannelRequest is the request type for the Query/Channel RPC method -message QueryChannelRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QueryChannelResponse is the response type for the Query/Channel RPC method. -// Besides the Channel end, it includes a proof and the height from which the -// proof was retrieved. -message QueryChannelResponse { - // channel associated with the request identifiers - ibc.core.channel.v1.Channel channel = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelsRequest is the request type for the Query/Channels RPC method -message QueryChannelsRequest { - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryChannelsResponse is the response type for the Query/Channels RPC method. -message QueryChannelsResponse { - // list of stored channels of the chain. - repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionChannelsRequest is the request type for the -// Query/QueryConnectionChannels RPC method -message QueryConnectionChannelsRequest { - // connection unique identifier - string connection = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConnectionChannelsResponse is the Response type for the -// Query/QueryConnectionChannels RPC method -message QueryConnectionChannelsResponse { - // list of channels associated with a connection. - repeated ibc.core.channel.v1.IdentifiedChannel channels = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelClientStateRequest is the request type for the Query/ClientState -// RPC method -message QueryChannelClientStateRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QueryChannelClientStateResponse is the Response type for the -// Query/QueryChannelClientState RPC method -message QueryChannelClientStateResponse { - // client state associated with the channel - ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelConsensusStateRequest is the request type for the -// Query/ConsensusState RPC method -message QueryChannelConsensusStateRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // revision number of the consensus state - uint64 revision_number = 3; - // revision height of the consensus state - uint64 revision_height = 4; -} - -// QueryChannelClientStateResponse is the Response type for the -// Query/QueryChannelClientState RPC method -message QueryChannelConsensusStateResponse { - // consensus state associated with the channel - google.protobuf.Any consensus_state = 1; - // client ID associated with the consensus state - string client_id = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} - -// QueryPacketCommitmentRequest is the request type for the -// Query/PacketCommitment RPC method -message QueryPacketCommitmentRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketCommitmentResponse defines the client query response for a packet -// which also includes a proof and the height from which the proof was -// retrieved -message QueryPacketCommitmentResponse { - // packet associated with the request fields - bytes commitment = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketCommitmentsRequest is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketCommitmentsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 3; -} - -// QueryPacketCommitmentsResponse is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketCommitmentsResponse { - repeated ibc.core.channel.v1.PacketState commitments = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketReceiptRequest is the request type for the -// Query/PacketReceipt RPC method -message QueryPacketReceiptRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketReceiptResponse defines the client query response for a packet -// receipt which also includes a proof, and the height from which the proof was -// retrieved -message QueryPacketReceiptResponse { - // success flag for if receipt exists - bool received = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} - -// QueryPacketAcknowledgementRequest is the request type for the -// Query/PacketAcknowledgement RPC method -message QueryPacketAcknowledgementRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // packet sequence - uint64 sequence = 3; -} - -// QueryPacketAcknowledgementResponse defines the client query response for a -// packet which also includes a proof and the height from which the -// proof was retrieved -message QueryPacketAcknowledgementResponse { - // packet associated with the request fields - bytes acknowledgement = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryPacketAcknowledgementsRequest is the request type for the -// Query/QueryPacketCommitments RPC method -message QueryPacketAcknowledgementsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 3; - // list of packet sequences - repeated uint64 packet_commitment_sequences = 4; -} - -// QueryPacketAcknowledgemetsResponse is the request type for the -// Query/QueryPacketAcknowledgements RPC method -message QueryPacketAcknowledgementsResponse { - repeated ibc.core.channel.v1.PacketState acknowledgements = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryUnreceivedPacketsRequest is the request type for the -// Query/UnreceivedPackets RPC method -message QueryUnreceivedPacketsRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // list of packet sequences - repeated uint64 packet_commitment_sequences = 3; -} - -// QueryUnreceivedPacketsResponse is the response type for the -// Query/UnreceivedPacketCommitments RPC method -message QueryUnreceivedPacketsResponse { - // list of unreceived packet sequences - repeated uint64 sequences = 1; - // query block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} - -// QueryUnreceivedAcks is the request type for the -// Query/UnreceivedAcks RPC method -message QueryUnreceivedAcksRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; - // list of acknowledgement sequences - repeated uint64 packet_ack_sequences = 3; -} - -// QueryUnreceivedAcksResponse is the response type for the -// Query/UnreceivedAcks RPC method -message QueryUnreceivedAcksResponse { - // list of unreceived acknowledgement sequences - repeated uint64 sequences = 1; - // query block height - ibc.core.client.v1.Height height = 2 [(gogoproto.nullable) = false]; -} - -// QueryNextSequenceReceiveRequest is the request type for the -// Query/QueryNextSequenceReceiveRequest RPC method -message QueryNextSequenceReceiveRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QuerySequenceResponse is the response type for the -// Query/QueryNextSequenceReceiveResponse RPC method -message QueryNextSequenceReceiveResponse { - // next sequence receive number - uint64 next_sequence_receive = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryNextSequenceSendRequest is the request type for the -// Query/QueryNextSequenceSend RPC method -message QueryNextSequenceSendRequest { - // port unique identifier - string port_id = 1; - // channel unique identifier - string channel_id = 2; -} - -// QueryNextSequenceSendResponse is the request type for the -// Query/QueryNextSequenceSend RPC method -message QueryNextSequenceSendResponse { - // next sequence send number - uint64 next_sequence_send = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryUpgradeErrorRequest is the request type for the Query/QueryUpgradeError RPC method -message QueryUpgradeErrorRequest { - string port_id = 1; - string channel_id = 2; -} - -// QueryUpgradeErrorResponse is the response type for the Query/QueryUpgradeError RPC method -message QueryUpgradeErrorResponse { - ErrorReceipt error_receipt = 1 [(gogoproto.nullable) = false]; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryUpgradeRequest is the request type for the QueryUpgradeRequest RPC method -message QueryUpgradeRequest { - string port_id = 1; - string channel_id = 2; -} - -// QueryUpgradeResponse is the response type for the QueryUpgradeResponse RPC method -message QueryUpgradeResponse { - Upgrade upgrade = 1 [(gogoproto.nullable) = false]; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryChannelParamsRequest is the request type for the Query/ChannelParams RPC method. -message QueryChannelParamsRequest {} - -// QueryChannelParamsResponse is the response type for the Query/ChannelParams RPC method. -message QueryChannelParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} \ No newline at end of file diff --git a/third_party/proto/ibc/channel/v1/tx.proto b/third_party/proto/ibc/channel/v1/tx.proto deleted file mode 100644 index 3f30e8b8c..000000000 --- a/third_party/proto/ibc/channel/v1/tx.proto +++ /dev/null @@ -1,469 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/msg/v1/msg.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "ibc/core/channel/v1/upgrade.proto"; - -// Msg defines the ibc/channel Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // ChannelOpenInit defines a rpc handler method for MsgChannelOpenInit. - rpc ChannelOpenInit(MsgChannelOpenInit) returns (MsgChannelOpenInitResponse); - - // ChannelOpenTry defines a rpc handler method for MsgChannelOpenTry. - rpc ChannelOpenTry(MsgChannelOpenTry) returns (MsgChannelOpenTryResponse); - - // ChannelOpenAck defines a rpc handler method for MsgChannelOpenAck. - rpc ChannelOpenAck(MsgChannelOpenAck) returns (MsgChannelOpenAckResponse); - - // ChannelOpenConfirm defines a rpc handler method for MsgChannelOpenConfirm. - rpc ChannelOpenConfirm(MsgChannelOpenConfirm) returns (MsgChannelOpenConfirmResponse); - - // ChannelCloseInit defines a rpc handler method for MsgChannelCloseInit. - rpc ChannelCloseInit(MsgChannelCloseInit) returns (MsgChannelCloseInitResponse); - - // ChannelCloseConfirm defines a rpc handler method for - // MsgChannelCloseConfirm. - rpc ChannelCloseConfirm(MsgChannelCloseConfirm) returns (MsgChannelCloseConfirmResponse); - - // RecvPacket defines a rpc handler method for MsgRecvPacket. - rpc RecvPacket(MsgRecvPacket) returns (MsgRecvPacketResponse); - - // Timeout defines a rpc handler method for MsgTimeout. - rpc Timeout(MsgTimeout) returns (MsgTimeoutResponse); - - // TimeoutOnClose defines a rpc handler method for MsgTimeoutOnClose. - rpc TimeoutOnClose(MsgTimeoutOnClose) returns (MsgTimeoutOnCloseResponse); - - // Acknowledgement defines a rpc handler method for MsgAcknowledgement. - rpc Acknowledgement(MsgAcknowledgement) returns (MsgAcknowledgementResponse); - - // ChannelUpgradeInit defines a rpc handler method for MsgChannelUpgradeInit. - rpc ChannelUpgradeInit(MsgChannelUpgradeInit) returns (MsgChannelUpgradeInitResponse); - - // ChannelUpgradeTry defines a rpc handler method for MsgChannelUpgradeTry. - rpc ChannelUpgradeTry(MsgChannelUpgradeTry) returns (MsgChannelUpgradeTryResponse); - - // ChannelUpgradeAck defines a rpc handler method for MsgChannelUpgradeAck. - rpc ChannelUpgradeAck(MsgChannelUpgradeAck) returns (MsgChannelUpgradeAckResponse); - - // ChannelUpgradeConfirm defines a rpc handler method for MsgChannelUpgradeConfirm. - rpc ChannelUpgradeConfirm(MsgChannelUpgradeConfirm) returns (MsgChannelUpgradeConfirmResponse); - - // ChannelUpgradeOpen defines a rpc handler method for MsgChannelUpgradeOpen. - rpc ChannelUpgradeOpen(MsgChannelUpgradeOpen) returns (MsgChannelUpgradeOpenResponse); - - // ChannelUpgradeTimeout defines a rpc handler method for MsgChannelUpgradeTimeout. - rpc ChannelUpgradeTimeout(MsgChannelUpgradeTimeout) returns (MsgChannelUpgradeTimeoutResponse); - - // ChannelUpgradeCancel defines a rpc handler method for MsgChannelUpgradeCancel. - rpc ChannelUpgradeCancel(MsgChannelUpgradeCancel) returns (MsgChannelUpgradeCancelResponse); - - // UpdateChannelParams defines a rpc handler method for MsgUpdateParams. - rpc UpdateChannelParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); - - // PruneAcknowledgements defines a rpc handler method for MsgPruneAcknowledgements. - rpc PruneAcknowledgements(MsgPruneAcknowledgements) returns (MsgPruneAcknowledgementsResponse); -} - -// ResponseResultType defines the possible outcomes of the execution of a message -enum ResponseResultType { - option (gogoproto.goproto_enum_prefix) = false; - - // Default zero value enumeration - RESPONSE_RESULT_TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // The message did not call the IBC application callbacks (because, for example, the packet had already been relayed) - RESPONSE_RESULT_TYPE_NOOP = 1 [(gogoproto.enumvalue_customname) = "NOOP"]; - // The message was executed successfully - RESPONSE_RESULT_TYPE_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "SUCCESS"]; - // The message was executed unsuccessfully - RESPONSE_RESULT_TYPE_FAILURE = 3 [(gogoproto.enumvalue_customname) = "FAILURE"]; -} - -// MsgChannelOpenInit defines an sdk.Msg to initialize a channel handshake. It -// is called by a relayer on Chain A. -message MsgChannelOpenInit { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - Channel channel = 2 [(gogoproto.nullable) = false]; - string signer = 3; -} - -// MsgChannelOpenInitResponse defines the Msg/ChannelOpenInit response type. -message MsgChannelOpenInitResponse { - option (gogoproto.goproto_getters) = false; - - string channel_id = 1; - string version = 2; -} - -// MsgChannelOpenInit defines a msg sent by a Relayer to try to open a channel -// on Chain B. The version field within the Channel field has been deprecated. Its -// value will be ignored by core IBC. -message MsgChannelOpenTry { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - // Deprecated: this field is unused. Crossing hello's are no longer supported in core IBC. - string previous_channel_id = 2 [deprecated = true]; - // NOTE: the version field within the channel has been deprecated. Its value will be ignored by core IBC. - Channel channel = 3 [(gogoproto.nullable) = false]; - string counterparty_version = 4; - bytes proof_init = 5; - ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelOpenTryResponse defines the Msg/ChannelOpenTry response type. -message MsgChannelOpenTryResponse { - option (gogoproto.goproto_getters) = false; - - string version = 1; - string channel_id = 2; -} - -// MsgChannelOpenAck defines a msg sent by a Relayer to Chain A to acknowledge -// the change of channel state to TRYOPEN on Chain B. -// WARNING: a channel upgrade MUST NOT initialize an upgrade for this channel -// in the same block as executing this message otherwise the counterparty will -// be incapable of opening. -message MsgChannelOpenAck { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - string counterparty_channel_id = 3; - string counterparty_version = 4; - bytes proof_try = 5; - ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelOpenAckResponse defines the Msg/ChannelOpenAck response type. -message MsgChannelOpenAckResponse {} - -// MsgChannelOpenConfirm defines a msg sent by a Relayer to Chain B to -// acknowledge the change of channel state to OPEN on Chain A. -message MsgChannelOpenConfirm { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - bytes proof_ack = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - string signer = 5; -} - -// MsgChannelOpenConfirmResponse defines the Msg/ChannelOpenConfirm response -// type. -message MsgChannelOpenConfirmResponse {} - -// MsgChannelCloseInit defines a msg sent by a Relayer to Chain A -// to close a channel with Chain B. -message MsgChannelCloseInit { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - string signer = 3; -} - -// MsgChannelCloseInitResponse defines the Msg/ChannelCloseInit response type. -message MsgChannelCloseInitResponse {} - -// MsgChannelCloseConfirm defines a msg sent by a Relayer to Chain B -// to acknowledge the change of channel state to CLOSED on Chain A. -message MsgChannelCloseConfirm { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - bytes proof_init = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - string signer = 5; - uint64 counterparty_upgrade_sequence = 6; -} - -// MsgChannelCloseConfirmResponse defines the Msg/ChannelCloseConfirm response -// type. -message MsgChannelCloseConfirmResponse {} - -// MsgRecvPacket receives incoming IBC packet -message MsgRecvPacket { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_commitment = 2; - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; - string signer = 4; -} - -// MsgRecvPacketResponse defines the Msg/RecvPacket response type. -message MsgRecvPacketResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgTimeout receives timed-out packet -message MsgTimeout { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2; - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; - uint64 next_sequence_recv = 4; - string signer = 5; -} - -// MsgTimeoutResponse defines the Msg/Timeout response type. -message MsgTimeoutResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgTimeoutOnClose timed-out packet upon counterparty channel closure. -message MsgTimeoutOnClose { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes proof_unreceived = 2; - bytes proof_close = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - uint64 next_sequence_recv = 5; - string signer = 6; - uint64 counterparty_upgrade_sequence = 7; -} - -// MsgTimeoutOnCloseResponse defines the Msg/TimeoutOnClose response type. -message MsgTimeoutOnCloseResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgAcknowledgement receives incoming IBC acknowledgement -message MsgAcknowledgement { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - Packet packet = 1 [(gogoproto.nullable) = false]; - bytes acknowledgement = 2; - bytes proof_acked = 3; - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; - string signer = 5; -} - -// MsgAcknowledgementResponse defines the Msg/Acknowledgement response type. -message MsgAcknowledgementResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgChannelUpgradeInit defines the request type for the ChannelUpgradeInit rpc -// WARNING: Initializing a channel upgrade in the same block as opening the channel -// may result in the counterparty being incapable of opening. -message MsgChannelUpgradeInit { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - UpgradeFields fields = 3 [(gogoproto.nullable) = false]; - string signer = 4; -} - -// MsgChannelUpgradeInitResponse defines the MsgChannelUpgradeInit response type -message MsgChannelUpgradeInitResponse { - option (gogoproto.goproto_getters) = false; - - Upgrade upgrade = 1 [(gogoproto.nullable) = false]; - uint64 upgrade_sequence = 2; -} - -// MsgChannelUpgradeTry defines the request type for the ChannelUpgradeTry rpc -message MsgChannelUpgradeTry { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - repeated string proposed_upgrade_connection_hops = 3; - UpgradeFields counterparty_upgrade_fields = 4 [(gogoproto.nullable) = false]; - uint64 counterparty_upgrade_sequence = 5; - bytes proof_channel = 6; - bytes proof_upgrade = 7; - ibc.core.client.v1.Height proof_height = 8 [(gogoproto.nullable) = false]; - string signer = 9; -} - -// MsgChannelUpgradeTryResponse defines the MsgChannelUpgradeTry response type -message MsgChannelUpgradeTryResponse { - option (gogoproto.goproto_getters) = false; - - Upgrade upgrade = 1 [(gogoproto.nullable) = false]; - uint64 upgrade_sequence = 2; - ResponseResultType result = 3; -} - -// MsgChannelUpgradeAck defines the request type for the ChannelUpgradeAck rpc -message MsgChannelUpgradeAck { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - string port_id = 1; - string channel_id = 2; - Upgrade counterparty_upgrade = 3 [(gogoproto.nullable) = false]; - bytes proof_channel = 4; - bytes proof_upgrade = 5; - ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelUpgradeAckResponse defines MsgChannelUpgradeAck response type -message MsgChannelUpgradeAckResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgChannelUpgradeConfirm defines the request type for the ChannelUpgradeConfirm rpc -message MsgChannelUpgradeConfirm { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - string port_id = 1; - string channel_id = 2; - State counterparty_channel_state = 3; - Upgrade counterparty_upgrade = 4 [(gogoproto.nullable) = false]; - bytes proof_channel = 5; - bytes proof_upgrade = 6; - ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; - string signer = 8; -} - -// MsgChannelUpgradeConfirmResponse defines MsgChannelUpgradeConfirm response type -message MsgChannelUpgradeConfirmResponse { - option (gogoproto.goproto_getters) = false; - - ResponseResultType result = 1; -} - -// MsgChannelUpgradeOpen defines the request type for the ChannelUpgradeOpen rpc -message MsgChannelUpgradeOpen { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - string port_id = 1; - string channel_id = 2; - State counterparty_channel_state = 3; - uint64 counterparty_upgrade_sequence = 4; - bytes proof_channel = 5; - ibc.core.client.v1.Height proof_height = 6 [(gogoproto.nullable) = false]; - string signer = 7; -} - -// MsgChannelUpgradeOpenResponse defines the MsgChannelUpgradeOpen response type -message MsgChannelUpgradeOpenResponse {} - -// MsgChannelUpgradeTimeout defines the request type for the ChannelUpgradeTimeout rpc -message MsgChannelUpgradeTimeout { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - Channel counterparty_channel = 3 [(gogoproto.nullable) = false]; - bytes proof_channel = 4; - ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; - string signer = 6; -} - -// MsgChannelUpgradeTimeoutRepsonse defines the MsgChannelUpgradeTimeout response type -message MsgChannelUpgradeTimeoutResponse {} - -// MsgChannelUpgradeCancel defines the request type for the ChannelUpgradeCancel rpc -message MsgChannelUpgradeCancel { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - ErrorReceipt error_receipt = 3 [(gogoproto.nullable) = false]; - bytes proof_error_receipt = 4; - ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; - string signer = 6; -} - -// MsgChannelUpgradeCancelResponse defines the MsgChannelUpgradeCancel response type -message MsgChannelUpgradeCancelResponse {} - -// MsgUpdateParams is the MsgUpdateParams request type. -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "authority"; - - option (gogoproto.goproto_getters) = false; - - // authority is the address that controls the module (defaults to x/gov unless overwritten). - string authority = 1; - - // params defines the channel parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the MsgUpdateParams response type. -message MsgUpdateParamsResponse {} - -// MsgPruneAcknowledgements defines the request type for the PruneAcknowledgements rpc. -message MsgPruneAcknowledgements { - option (cosmos.msg.v1.signer) = "signer"; - option (gogoproto.goproto_getters) = false; - - string port_id = 1; - string channel_id = 2; - uint64 limit = 3; - string signer = 4; -} - -// MsgPruneAcknowledgementsResponse defines the response type for the PruneAcknowledgements rpc. -message MsgPruneAcknowledgementsResponse { - // Number of sequences pruned (includes both packet acknowledgements and packet receipts where appropriate). - uint64 total_pruned_sequences = 1; - // Number of sequences left after pruning. - uint64 total_remaining_sequences = 2; -} diff --git a/third_party/proto/ibc/channel/v1/upgrade.proto b/third_party/proto/ibc/channel/v1/upgrade.proto deleted file mode 100644 index 81530ed2a..000000000 --- a/third_party/proto/ibc/channel/v1/upgrade.proto +++ /dev/null @@ -1,43 +0,0 @@ -syntax = "proto3"; - -package ibc.core.channel.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Upgrade is a verifiable type which contains the relevant information -// for an attempted upgrade. It provides the proposed changes to the channel -// end, the timeout for this upgrade attempt and the next packet sequence -// which allows the counterparty to efficiently know the highest sequence it has received. -// The next sequence send is used for pruning and upgrading from unordered to ordered channels. -message Upgrade { - option (gogoproto.goproto_getters) = false; - - UpgradeFields fields = 1 [(gogoproto.nullable) = false]; - Timeout timeout = 2 [(gogoproto.nullable) = false]; - uint64 next_sequence_send = 3; -} - -// UpgradeFields are the fields in a channel end which may be changed -// during a channel upgrade. -message UpgradeFields { - option (gogoproto.goproto_getters) = false; - - Order ordering = 1; - repeated string connection_hops = 2; - string version = 3; -} - -// ErrorReceipt defines a type which encapsulates the upgrade sequence and error associated with the -// upgrade handshake failure. When a channel upgrade handshake is aborted both chains are expected to increment to the -// next sequence. -message ErrorReceipt { - option (gogoproto.goproto_getters) = false; - - // the channel upgrade sequence - uint64 sequence = 1; - // the error message detailing the cause of failure - string message = 2; -} diff --git a/third_party/proto/ibc/client/v1/client.proto b/third_party/proto/ibc/client/v1/client.proto deleted file mode 100644 index 7a09e360a..000000000 --- a/third_party/proto/ibc/client/v1/client.proto +++ /dev/null @@ -1,113 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "cosmos/upgrade/v1beta1/upgrade.proto"; -import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// IdentifiedClientState defines a client state with an additional client -// identifier field. -message IdentifiedClientState { - // client identifier - string client_id = 1; - // client state - google.protobuf.Any client_state = 2; -} - -// ConsensusStateWithHeight defines a consensus state with an additional height -// field. -message ConsensusStateWithHeight { - // consensus state height - Height height = 1 [(gogoproto.nullable) = false]; - // consensus state - google.protobuf.Any consensus_state = 2; -} - -// ClientConsensusStates defines all the stored consensus states for a given -// client. -message ClientConsensusStates { - // client identifier - string client_id = 1; - // consensus states and their heights associated with the client - repeated ConsensusStateWithHeight consensus_states = 2 [(gogoproto.nullable) = false]; -} - -// Height is a monotonically increasing data type -// that can be compared against another Height for the purposes of updating and -// freezing clients -// -// Normally the RevisionHeight is incremented at each height while keeping -// RevisionNumber the same. However some consensus algorithms may choose to -// reset the height in certain conditions e.g. hard forks, state-machine -// breaking changes In these cases, the RevisionNumber is incremented so that -// height continues to be monitonically increasing even as the RevisionHeight -// gets reset -message Height { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - // the revision that the client is currently on - uint64 revision_number = 1; - // the height within the given revision - uint64 revision_height = 2; -} - -// Params defines the set of IBC light client parameters. -message Params { - // allowed_clients defines the list of allowed client state types which can be created - // and interacted with. If a client type is removed from the allowed clients list, usage - // of this client will be disabled until it is added again to the list. - repeated string allowed_clients = 1; -} - -// ClientUpdateProposal is a legacy governance proposal. If it passes, the substitute -// client's latest consensus state is copied over to the subject client. The proposal -// handler may fail if the subject and the substitute do not match in client and -// chain parameters (with exception to latest height, frozen height, and chain-id). -// -// Deprecated: Please use MsgRecoverClient in favour of this message type. -message ClientUpdateProposal { - option deprecated = true; - - option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; - option (gogoproto.goproto_getters) = false; - - // the title of the update proposal - string title = 1; - // the description of the proposal - string description = 2; - // the client identifier for the client to be updated if the proposal passes - string subject_client_id = 3 [(gogoproto.moretags) = "yaml:\"subject_client_id\""]; - // the substitute client identifier for the client standing in for the subject - // client - string substitute_client_id = 4 [(gogoproto.moretags) = "yaml:\"substitute_client_id\""]; -} - -// UpgradeProposal is a gov Content type for initiating an IBC breaking -// upgrade. -// -// Deprecated: Please use MsgIBCSoftwareUpgrade in favour of this message type. -message UpgradeProposal { - option deprecated = true; - - option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (gogoproto.equal) = true; - - string title = 1; - string description = 2; - cosmos.upgrade.v1beta1.Plan plan = 3 [(gogoproto.nullable) = false]; - - // An UpgradedClientState must be provided to perform an IBC breaking upgrade. - // This will make the chain commit to the correct upgraded (self) client state - // before the upgrade occurs, so that connecting chains can verify that the - // new upgraded client is valid by verifying a proof on the previous version - // of the chain. This will allow IBC connections to persist smoothly across - // planned chain upgrades - google.protobuf.Any upgraded_client_state = 4 [(gogoproto.moretags) = "yaml:\"upgraded_client_state\""]; -} diff --git a/third_party/proto/ibc/client/v1/genesis.proto b/third_party/proto/ibc/client/v1/genesis.proto deleted file mode 100644 index 43610b0d4..000000000 --- a/third_party/proto/ibc/client/v1/genesis.proto +++ /dev/null @@ -1,44 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "ibc/core/client/v1/client.proto"; -import "gogoproto/gogo.proto"; - -// GenesisState defines the ibc client submodule's genesis state. -message GenesisState { - // client states with their corresponding identifiers - repeated IdentifiedClientState clients = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // consensus states from each client - repeated ClientConsensusStates clients_consensus = 2 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "ClientsConsensusStates"]; - // metadata from each client - repeated IdentifiedGenesisMetadata clients_metadata = 3 [(gogoproto.nullable) = false]; - Params params = 4 [(gogoproto.nullable) = false]; - // Deprecated: create_localhost has been deprecated. - // The localhost client is automatically created at genesis. - bool create_localhost = 5 [deprecated = true]; - // the sequence for the next generated client identifier - uint64 next_client_sequence = 6; -} - -// GenesisMetadata defines the genesis type for metadata that clients may return -// with ExportMetadata -message GenesisMetadata { - option (gogoproto.goproto_getters) = false; - - // store key of metadata without clientID-prefix - bytes key = 1; - // metadata value - bytes value = 2; -} - -// IdentifiedGenesisMetadata has the client metadata with the corresponding -// client id. -message IdentifiedGenesisMetadata { - string client_id = 1; - repeated GenesisMetadata client_metadata = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/client/v1/query.proto b/third_party/proto/ibc/client/v1/query.proto deleted file mode 100644 index 0032306ec..000000000 --- a/third_party/proto/ibc/client/v1/query.proto +++ /dev/null @@ -1,207 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/client/v1/client.proto"; -import "google/protobuf/any.proto"; -import "google/api/annotations.proto"; -import "gogoproto/gogo.proto"; - -// Query provides defines the gRPC querier service -service Query { - // ClientState queries an IBC light client. - rpc ClientState(QueryClientStateRequest) returns (QueryClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states/{client_id}"; - } - - // ClientStates queries all the IBC light clients of a chain. - rpc ClientStates(QueryClientStatesRequest) returns (QueryClientStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states"; - } - - // ConsensusState queries a consensus state associated with a client state at - // a given height. - rpc ConsensusState(QueryConsensusStateRequest) returns (QueryConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/" - "{client_id}/revision/{revision_number}/" - "height/{revision_height}"; - } - - // ConsensusStates queries all the consensus state associated with a given - // client. - rpc ConsensusStates(QueryConsensusStatesRequest) returns (QueryConsensusStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}"; - } - - // ConsensusStateHeights queries the height of every consensus states associated with a given client. - rpc ConsensusStateHeights(QueryConsensusStateHeightsRequest) returns (QueryConsensusStateHeightsResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}/heights"; - } - - // Status queries the status of an IBC client. - rpc ClientStatus(QueryClientStatusRequest) returns (QueryClientStatusResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_status/{client_id}"; - } - - // ClientParams queries all parameters of the ibc client submodule. - rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) { - option (google.api.http).get = "/ibc/core/client/v1/params"; - } - - // UpgradedClientState queries an Upgraded IBC light client. - rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states"; - } - - // UpgradedConsensusState queries an Upgraded IBC consensus state. - rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_consensus_states"; - } -} - -// QueryClientStateRequest is the request type for the Query/ClientState RPC -// method -message QueryClientStateRequest { - // client state unique identifier - string client_id = 1; -} - -// QueryClientStateResponse is the response type for the Query/ClientState RPC -// method. Besides the client state, it includes a proof and the height from -// which the proof was retrieved. -message QueryClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryClientStatesRequest is the request type for the Query/ClientStates RPC -// method -message QueryClientStatesRequest { - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryClientStatesResponse is the response type for the Query/ClientStates RPC -// method. -message QueryClientStatesResponse { - // list of stored ClientStates of the chain. - repeated IdentifiedClientState client_states = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryConsensusStateRequest is the request type for the Query/ConsensusState -// RPC method. Besides the consensus state, it includes a proof and the height -// from which the proof was retrieved. -message QueryConsensusStateRequest { - // client identifier - string client_id = 1; - // consensus state revision number - uint64 revision_number = 2; - // consensus state revision height - uint64 revision_height = 3; - // latest_height overrrides the height field and queries the latest stored - // ConsensusState - bool latest_height = 4; -} - -// QueryConsensusStateResponse is the response type for the Query/ConsensusState -// RPC method -message QueryConsensusStateResponse { - // consensus state associated with the client identifier at the given height - google.protobuf.Any consensus_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConsensusStatesRequest is the request type for the Query/ConsensusStates -// RPC method. -message QueryConsensusStatesRequest { - // client identifier - string client_id = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConsensusStatesResponse is the response type for the -// Query/ConsensusStates RPC method -message QueryConsensusStatesResponse { - // consensus states associated with the identifier - repeated ConsensusStateWithHeight consensus_states = 1 [(gogoproto.nullable) = false]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights -// RPC method. -message QueryConsensusStateHeightsRequest { - // client identifier - string client_id = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConsensusStateHeightsResponse is the response type for the -// Query/ConsensusStateHeights RPC method -message QueryConsensusStateHeightsResponse { - // consensus state heights - repeated Height consensus_state_heights = 1 [(gogoproto.nullable) = false]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryClientStatusRequest is the request type for the Query/ClientStatus RPC -// method -message QueryClientStatusRequest { - // client unique identifier - string client_id = 1; -} - -// QueryClientStatusResponse is the response type for the Query/ClientStatus RPC -// method. It returns the current status of the IBC client. -message QueryClientStatusResponse { - string status = 1; -} - -// QueryClientParamsRequest is the request type for the Query/ClientParams RPC -// method. -message QueryClientParamsRequest {} - -// QueryClientParamsResponse is the response type for the Query/ClientParams RPC -// method. -message QueryClientParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} - -// QueryUpgradedClientStateRequest is the request type for the -// Query/UpgradedClientState RPC method -message QueryUpgradedClientStateRequest {} - -// QueryUpgradedClientStateResponse is the response type for the -// Query/UpgradedClientState RPC method. -message QueryUpgradedClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any upgraded_client_state = 1; -} - -// QueryUpgradedConsensusStateRequest is the request type for the -// Query/UpgradedConsensusState RPC method -message QueryUpgradedConsensusStateRequest {} - -// QueryUpgradedConsensusStateResponse is the response type for the -// Query/UpgradedConsensusState RPC method. -message QueryUpgradedConsensusStateResponse { - // Consensus state associated with the request identifier - google.protobuf.Any upgraded_consensus_state = 1; -} diff --git a/third_party/proto/ibc/client/v1/tx.proto b/third_party/proto/ibc/client/v1/tx.proto deleted file mode 100644 index b504ab692..000000000 --- a/third_party/proto/ibc/client/v1/tx.proto +++ /dev/null @@ -1,175 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "cosmos/msg/v1/msg.proto"; -import "cosmos/upgrade/v1beta1/upgrade.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "ibc/core/client/v1/client.proto"; - -// Msg defines the ibc/client Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // CreateClient defines a rpc handler method for MsgCreateClient. - rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse); - - // UpdateClient defines a rpc handler method for MsgUpdateClient. - rpc UpdateClient(MsgUpdateClient) returns (MsgUpdateClientResponse); - - // UpgradeClient defines a rpc handler method for MsgUpgradeClient. - rpc UpgradeClient(MsgUpgradeClient) returns (MsgUpgradeClientResponse); - - // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. - rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); - - // RecoverClient defines a rpc handler method for MsgRecoverClient. - rpc RecoverClient(MsgRecoverClient) returns (MsgRecoverClientResponse); - - // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. - rpc IBCSoftwareUpgrade(MsgIBCSoftwareUpgrade) returns (MsgIBCSoftwareUpgradeResponse); - - // UpdateClientParams defines a rpc handler method for MsgUpdateParams. - rpc UpdateClientParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgCreateClient defines a message to create an IBC client -message MsgCreateClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // light client state - google.protobuf.Any client_state = 1; - // consensus state associated with the client that corresponds to a given - // height. - google.protobuf.Any consensus_state = 2; - // signer address - string signer = 3; -} - -// MsgCreateClientResponse defines the Msg/CreateClient response type. -message MsgCreateClientResponse {} - -// MsgUpdateClient defines an sdk.Msg to update a IBC client state using -// the given client message. -message MsgUpdateClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // client message to update the light client - google.protobuf.Any client_message = 2; - // signer address - string signer = 3; -} - -// MsgUpdateClientResponse defines the Msg/UpdateClient response type. -message MsgUpdateClientResponse {} - -// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client -// state -message MsgUpgradeClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // upgraded client state - google.protobuf.Any client_state = 2; - // upgraded consensus state, only contains enough information to serve as a - // basis of trust in update logic - google.protobuf.Any consensus_state = 3; - // proof that old chain committed to new client - bytes proof_upgrade_client = 4; - // proof that old chain committed to new consensus state - bytes proof_upgrade_consensus_state = 5; - // signer address - string signer = 6; -} - -// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type. -message MsgUpgradeClientResponse {} - -// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for -// light client misbehaviour. -// This message has been deprecated. Use MsgUpdateClient instead. -message MsgSubmitMisbehaviour { - option deprecated = true; - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // misbehaviour used for freezing the light client - google.protobuf.Any misbehaviour = 2; - // signer address - string signer = 3; -} - -// MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response -// type. -message MsgSubmitMisbehaviourResponse {} - -// MsgRecoverClient defines the message used to recover a frozen or expired client. -message MsgRecoverClient { - option (gogoproto.goproto_getters) = false; - option (cosmos.msg.v1.signer) = "signer"; - - // the client identifier for the client to be updated if the proposal passes - string subject_client_id = 1; - // the substitute client identifier for the client which will replace the subject - // client - string substitute_client_id = 2; - - // signer address - string signer = 3; -} - -// MsgRecoverClientResponse defines the Msg/RecoverClient response type. -message MsgRecoverClientResponse {} - -// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal -message MsgIBCSoftwareUpgrade { - option (cosmos.msg.v1.signer) = "signer"; - cosmos.upgrade.v1beta1.Plan plan = 1 [(gogoproto.nullable) = false]; - // An UpgradedClientState must be provided to perform an IBC breaking upgrade. - // This will make the chain commit to the correct upgraded (self) client state - // before the upgrade occurs, so that connecting chains can verify that the - // new upgraded client is valid by verifying a proof on the previous version - // of the chain. This will allow IBC connections to persist smoothly across - // planned chain upgrades. Correspondingly, the UpgradedClientState field has been - // deprecated in the Cosmos SDK to allow for this logic to exist solely in - // the 02-client module. - google.protobuf.Any upgraded_client_state = 2; - // signer address - string signer = 3; -} - -// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. -message MsgIBCSoftwareUpgradeResponse {} - -// MsgUpdateParams defines the sdk.Msg type to update the client parameters. -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the client parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the MsgUpdateParams response type. -message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/commitment/v1/commitment.proto b/third_party/proto/ibc/commitment/v1/commitment.proto deleted file mode 100644 index b4753be2d..000000000 --- a/third_party/proto/ibc/commitment/v1/commitment.proto +++ /dev/null @@ -1,39 +0,0 @@ -syntax = "proto3"; - -package ibc.core.commitment.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/ics23/v1/proofs.proto"; - -// MerkleRoot defines a merkle root hash. -// In the Cosmos SDK, the AppHash of a block header becomes the root. -message MerkleRoot { - option (gogoproto.goproto_getters) = false; - - bytes hash = 1; -} - -// MerklePrefix is merkle path prefixed to the key. -// The constructed key from the Path and the key will be append(Path.KeyPath, -// append(Path.KeyPrefix, key...)) -message MerklePrefix { - bytes key_prefix = 1; -} - -// MerklePath is the path used to verify commitment proofs, which can be an -// arbitrary structured object (defined by a commitment type). -// MerklePath is represented from root-to-leaf -message MerklePath { - repeated string key_path = 1; -} - -// MerkleProof is a wrapper type over a chain of CommitmentProofs. -// It demonstrates membership or non-membership for an element or set of -// elements, verifiable in conjunction with a known commitment root. Proofs -// should be succinct. -// MerkleProofs are ordered from leaf-to-root -message MerkleProof { - repeated cosmos.ics23.v1.CommitmentProof proofs = 1; -} diff --git a/third_party/proto/ibc/connection/v1/connection.proto b/third_party/proto/ibc/connection/v1/connection.proto deleted file mode 100644 index 852f3999b..000000000 --- a/third_party/proto/ibc/connection/v1/connection.proto +++ /dev/null @@ -1,114 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/commitment/v1/commitment.proto"; - -// ICS03 - Connection Data Structures as defined in -// https://github.com/cosmos/ibc/blob/master/spec/core/ics-003-connection-semantics#data-structures - -// ConnectionEnd defines a stateful object on a chain connected to another -// separate one. -// NOTE: there must only be 2 defined ConnectionEnds to establish -// a connection between two chains. -message ConnectionEnd { - option (gogoproto.goproto_getters) = false; - // client associated with this connection. - string client_id = 1; - // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection. - repeated Version versions = 2; - // current state of the connection end. - State state = 3; - // counterparty chain associated with this connection. - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - // delay period that must pass before a consensus state can be used for - // packet-verification NOTE: delay period logic is only implemented by some - // clients. - uint64 delay_period = 5; -} - -// IdentifiedConnection defines a connection with additional connection -// identifier field. -message IdentifiedConnection { - option (gogoproto.goproto_getters) = false; - // connection identifier. - string id = 1; - // client associated with this connection. - string client_id = 2; - // IBC version which can be utilised to determine encodings or protocols for - // channels or packets utilising this connection - repeated Version versions = 3; - // current state of the connection end. - State state = 4; - // counterparty chain associated with this connection. - Counterparty counterparty = 5 [(gogoproto.nullable) = false]; - // delay period associated with this connection. - uint64 delay_period = 6; -} - -// State defines if a connection is in one of the following states: -// INIT, TRYOPEN, OPEN or UNINITIALIZED. -enum State { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - STATE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNINITIALIZED"]; - // A connection end has just started the opening handshake. - STATE_INIT = 1 [(gogoproto.enumvalue_customname) = "INIT"]; - // A connection end has acknowledged the handshake step on the counterparty - // chain. - STATE_TRYOPEN = 2 [(gogoproto.enumvalue_customname) = "TRYOPEN"]; - // A connection end has completed the handshake. - STATE_OPEN = 3 [(gogoproto.enumvalue_customname) = "OPEN"]; -} - -// Counterparty defines the counterparty chain associated with a connection end. -message Counterparty { - option (gogoproto.goproto_getters) = false; - - // identifies the client on the counterparty chain associated with a given - // connection. - string client_id = 1; - // identifies the connection end on the counterparty chain associated with a - // given connection. - string connection_id = 2; - // commitment merkle prefix of the counterparty chain. - ibc.core.commitment.v1.MerklePrefix prefix = 3 [(gogoproto.nullable) = false]; -} - -// ClientPaths define all the connection paths for a client state. -message ClientPaths { - // list of connection paths - repeated string paths = 1; -} - -// ConnectionPaths define all the connection paths for a given client state. -message ConnectionPaths { - // client state unique identifier - string client_id = 1; - // list of connection paths - repeated string paths = 2; -} - -// Version defines the versioning scheme used to negotiate the IBC verison in -// the connection handshake. -message Version { - option (gogoproto.goproto_getters) = false; - - // unique version identifier - string identifier = 1; - // list of features compatible with the specified identifier - repeated string features = 2; -} - -// Params defines the set of Connection parameters. -message Params { - // maximum expected time per block (in nanoseconds), used to enforce block delay. This parameter should reflect the - // largest amount of time that the chain might reasonably take to produce the next block under normal operating - // conditions. A safe choice is 3-5x the expected time per block. - uint64 max_expected_time_per_block = 1; -} diff --git a/third_party/proto/ibc/connection/v1/genesis.proto b/third_party/proto/ibc/connection/v1/genesis.proto deleted file mode 100644 index a5eb6b3a1..000000000 --- a/third_party/proto/ibc/connection/v1/genesis.proto +++ /dev/null @@ -1,17 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/connection/v1/connection.proto"; - -// GenesisState defines the ibc connection submodule's genesis state. -message GenesisState { - repeated IdentifiedConnection connections = 1 [(gogoproto.nullable) = false]; - repeated ConnectionPaths client_connection_paths = 2 [(gogoproto.nullable) = false]; - // the sequence for the next generated connection identifier - uint64 next_connection_sequence = 3; - Params params = 4 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/connection/v1/query.proto b/third_party/proto/ibc/connection/v1/query.proto deleted file mode 100644 index c0f1a6f57..000000000 --- a/third_party/proto/ibc/connection/v1/query.proto +++ /dev/null @@ -1,152 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/connection/v1/connection.proto"; -import "google/api/annotations.proto"; -import "google/protobuf/any.proto"; - -// Query provides defines the gRPC querier service -service Query { - // Connection queries an IBC connection end. - rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}"; - } - - // Connections queries all the IBC connections of a chain. - rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections"; - } - - // ClientConnections queries the connection paths associated with a client - // state. - rpc ClientConnections(QueryClientConnectionsRequest) returns (QueryClientConnectionsResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/client_connections/{client_id}"; - } - - // ConnectionClientState queries the client state associated with the - // connection. - rpc ConnectionClientState(QueryConnectionClientStateRequest) returns (QueryConnectionClientStateResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/client_state"; - } - - // ConnectionConsensusState queries the consensus state associated with the - // connection. - rpc ConnectionConsensusState(QueryConnectionConsensusStateRequest) returns (QueryConnectionConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/connections/{connection_id}/consensus_state/" - "revision/{revision_number}/height/{revision_height}"; - } - - // ConnectionParams queries all parameters of the ibc connection submodule. - rpc ConnectionParams(QueryConnectionParamsRequest) returns (QueryConnectionParamsResponse) { - option (google.api.http).get = "/ibc/core/connection/v1/params"; - } -} - -// QueryConnectionRequest is the request type for the Query/Connection RPC -// method -message QueryConnectionRequest { - // connection unique identifier - string connection_id = 1; -} - -// QueryConnectionResponse is the response type for the Query/Connection RPC -// method. Besides the connection end, it includes a proof and the height from -// which the proof was retrieved. -message QueryConnectionResponse { - // connection associated with the request identifier - ibc.core.connection.v1.ConnectionEnd connection = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionsRequest is the request type for the Query/Connections RPC -// method -message QueryConnectionsRequest { - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryConnectionsResponse is the response type for the Query/Connections RPC -// method. -message QueryConnectionsResponse { - // list of stored connections of the chain. - repeated ibc.core.connection.v1.IdentifiedConnection connections = 1; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; - // query block height - ibc.core.client.v1.Height height = 3 [(gogoproto.nullable) = false]; -} - -// QueryClientConnectionsRequest is the request type for the -// Query/ClientConnections RPC method -message QueryClientConnectionsRequest { - // client identifier associated with a connection - string client_id = 1; -} - -// QueryClientConnectionsResponse is the response type for the -// Query/ClientConnections RPC method -message QueryClientConnectionsResponse { - // slice of all the connection paths associated with a client. - repeated string connection_paths = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was generated - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionClientStateRequest is the request type for the -// Query/ConnectionClientState RPC method -message QueryConnectionClientStateRequest { - // connection identifier - string connection_id = 1; -} - -// QueryConnectionClientStateResponse is the response type for the -// Query/ConnectionClientState RPC method -message QueryConnectionClientStateResponse { - // client state associated with the channel - ibc.core.client.v1.IdentifiedClientState identified_client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConnectionConsensusStateRequest is the request type for the -// Query/ConnectionConsensusState RPC method -message QueryConnectionConsensusStateRequest { - // connection identifier - string connection_id = 1; - uint64 revision_number = 2; - uint64 revision_height = 3; -} - -// QueryConnectionConsensusStateResponse is the response type for the -// Query/ConnectionConsensusState RPC method -message QueryConnectionConsensusStateResponse { - // consensus state associated with the channel - google.protobuf.Any consensus_state = 1; - // client ID associated with the consensus state - string client_id = 2; - // merkle proof of existence - bytes proof = 3; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 4 [(gogoproto.nullable) = false]; -} - -// QueryConnectionParamsRequest is the request type for the Query/ConnectionParams RPC method. -message QueryConnectionParamsRequest {} - -// QueryConnectionParamsResponse is the response type for the Query/ConnectionParams RPC method. -message QueryConnectionParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} \ No newline at end of file diff --git a/third_party/proto/ibc/connection/v1/tx.proto b/third_party/proto/ibc/connection/v1/tx.proto deleted file mode 100644 index 3ba8ff456..000000000 --- a/third_party/proto/ibc/connection/v1/tx.proto +++ /dev/null @@ -1,146 +0,0 @@ -syntax = "proto3"; - -package ibc.core.connection.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/msg/v1/msg.proto"; -import "google/protobuf/any.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/connection/v1/connection.proto"; - -// Msg defines the ibc/connection Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // ConnectionOpenInit defines a rpc handler method for MsgConnectionOpenInit. - rpc ConnectionOpenInit(MsgConnectionOpenInit) returns (MsgConnectionOpenInitResponse); - - // ConnectionOpenTry defines a rpc handler method for MsgConnectionOpenTry. - rpc ConnectionOpenTry(MsgConnectionOpenTry) returns (MsgConnectionOpenTryResponse); - - // ConnectionOpenAck defines a rpc handler method for MsgConnectionOpenAck. - rpc ConnectionOpenAck(MsgConnectionOpenAck) returns (MsgConnectionOpenAckResponse); - - // ConnectionOpenConfirm defines a rpc handler method for - // MsgConnectionOpenConfirm. - rpc ConnectionOpenConfirm(MsgConnectionOpenConfirm) returns (MsgConnectionOpenConfirmResponse); - - // UpdateConnectionParams defines a rpc handler method for - // MsgUpdateParams. - rpc UpdateConnectionParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgConnectionOpenInit defines the msg sent by an account on Chain A to -// initialize a connection with Chain B. -message MsgConnectionOpenInit { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string client_id = 1; - Counterparty counterparty = 2 [(gogoproto.nullable) = false]; - Version version = 3; - uint64 delay_period = 4; - string signer = 5; -} - -// MsgConnectionOpenInitResponse defines the Msg/ConnectionOpenInit response -// type. -message MsgConnectionOpenInitResponse {} - -// MsgConnectionOpenTry defines a msg sent by a Relayer to try to open a -// connection on Chain B. -message MsgConnectionOpenTry { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string client_id = 1; - // Deprecated: this field is unused. Crossing hellos are no longer supported in core IBC. - string previous_connection_id = 2 [deprecated = true]; - google.protobuf.Any client_state = 3; - Counterparty counterparty = 4 [(gogoproto.nullable) = false]; - uint64 delay_period = 5; - repeated Version counterparty_versions = 6; - ibc.core.client.v1.Height proof_height = 7 [(gogoproto.nullable) = false]; - // proof of the initialization the connection on Chain A: `UNITIALIZED -> - // INIT` - bytes proof_init = 8; - // proof of client state included in message - bytes proof_client = 9; - // proof of client consensus state - bytes proof_consensus = 10; - ibc.core.client.v1.Height consensus_height = 11 [(gogoproto.nullable) = false]; - string signer = 12; - // optional proof data for host state machines that are unable to introspect their own consensus state - bytes host_consensus_state_proof = 13; -} - -// MsgConnectionOpenTryResponse defines the Msg/ConnectionOpenTry response type. -message MsgConnectionOpenTryResponse {} - -// MsgConnectionOpenAck defines a msg sent by a Relayer to Chain A to -// acknowledge the change of connection state to TRYOPEN on Chain B. -message MsgConnectionOpenAck { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string connection_id = 1; - string counterparty_connection_id = 2; - Version version = 3; - google.protobuf.Any client_state = 4; - ibc.core.client.v1.Height proof_height = 5 [(gogoproto.nullable) = false]; - // proof of the initialization the connection on Chain B: `UNITIALIZED -> - // TRYOPEN` - bytes proof_try = 6; - // proof of client state included in message - bytes proof_client = 7; - // proof of client consensus state - bytes proof_consensus = 8; - ibc.core.client.v1.Height consensus_height = 9 [(gogoproto.nullable) = false]; - string signer = 10; - // optional proof data for host state machines that are unable to introspect their own consensus state - bytes host_consensus_state_proof = 11; -} - -// MsgConnectionOpenAckResponse defines the Msg/ConnectionOpenAck response type. -message MsgConnectionOpenAckResponse {} - -// MsgConnectionOpenConfirm defines a msg sent by a Relayer to Chain B to -// acknowledge the change of connection state to OPEN on Chain A. -message MsgConnectionOpenConfirm { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - string connection_id = 1; - // proof for the change of the connection state on Chain A: `INIT -> OPEN` - bytes proof_ack = 2; - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; - string signer = 4; -} - -// MsgConnectionOpenConfirmResponse defines the Msg/ConnectionOpenConfirm -// response type. -message MsgConnectionOpenConfirmResponse {} - -// MsgUpdateParams defines the sdk.Msg type to update the connection parameters. -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the connection parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the MsgUpdateParams response type. -message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/core/client/v1/genesis.proto b/third_party/proto/ibc/core/client/v1/genesis.proto deleted file mode 100644 index 43610b0d4..000000000 --- a/third_party/proto/ibc/core/client/v1/genesis.proto +++ /dev/null @@ -1,44 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "ibc/core/client/v1/client.proto"; -import "gogoproto/gogo.proto"; - -// GenesisState defines the ibc client submodule's genesis state. -message GenesisState { - // client states with their corresponding identifiers - repeated IdentifiedClientState clients = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // consensus states from each client - repeated ClientConsensusStates clients_consensus = 2 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "ClientsConsensusStates"]; - // metadata from each client - repeated IdentifiedGenesisMetadata clients_metadata = 3 [(gogoproto.nullable) = false]; - Params params = 4 [(gogoproto.nullable) = false]; - // Deprecated: create_localhost has been deprecated. - // The localhost client is automatically created at genesis. - bool create_localhost = 5 [deprecated = true]; - // the sequence for the next generated client identifier - uint64 next_client_sequence = 6; -} - -// GenesisMetadata defines the genesis type for metadata that clients may return -// with ExportMetadata -message GenesisMetadata { - option (gogoproto.goproto_getters) = false; - - // store key of metadata without clientID-prefix - bytes key = 1; - // metadata value - bytes value = 2; -} - -// IdentifiedGenesisMetadata has the client metadata with the corresponding -// client id. -message IdentifiedGenesisMetadata { - string client_id = 1; - repeated GenesisMetadata client_metadata = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/core/client/v1/query.proto b/third_party/proto/ibc/core/client/v1/query.proto deleted file mode 100644 index 0032306ec..000000000 --- a/third_party/proto/ibc/core/client/v1/query.proto +++ /dev/null @@ -1,207 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/core/client/v1/client.proto"; -import "google/protobuf/any.proto"; -import "google/api/annotations.proto"; -import "gogoproto/gogo.proto"; - -// Query provides defines the gRPC querier service -service Query { - // ClientState queries an IBC light client. - rpc ClientState(QueryClientStateRequest) returns (QueryClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states/{client_id}"; - } - - // ClientStates queries all the IBC light clients of a chain. - rpc ClientStates(QueryClientStatesRequest) returns (QueryClientStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_states"; - } - - // ConsensusState queries a consensus state associated with a client state at - // a given height. - rpc ConsensusState(QueryConsensusStateRequest) returns (QueryConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/" - "{client_id}/revision/{revision_number}/" - "height/{revision_height}"; - } - - // ConsensusStates queries all the consensus state associated with a given - // client. - rpc ConsensusStates(QueryConsensusStatesRequest) returns (QueryConsensusStatesResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}"; - } - - // ConsensusStateHeights queries the height of every consensus states associated with a given client. - rpc ConsensusStateHeights(QueryConsensusStateHeightsRequest) returns (QueryConsensusStateHeightsResponse) { - option (google.api.http).get = "/ibc/core/client/v1/consensus_states/{client_id}/heights"; - } - - // Status queries the status of an IBC client. - rpc ClientStatus(QueryClientStatusRequest) returns (QueryClientStatusResponse) { - option (google.api.http).get = "/ibc/core/client/v1/client_status/{client_id}"; - } - - // ClientParams queries all parameters of the ibc client submodule. - rpc ClientParams(QueryClientParamsRequest) returns (QueryClientParamsResponse) { - option (google.api.http).get = "/ibc/core/client/v1/params"; - } - - // UpgradedClientState queries an Upgraded IBC light client. - rpc UpgradedClientState(QueryUpgradedClientStateRequest) returns (QueryUpgradedClientStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_client_states"; - } - - // UpgradedConsensusState queries an Upgraded IBC consensus state. - rpc UpgradedConsensusState(QueryUpgradedConsensusStateRequest) returns (QueryUpgradedConsensusStateResponse) { - option (google.api.http).get = "/ibc/core/client/v1/upgraded_consensus_states"; - } -} - -// QueryClientStateRequest is the request type for the Query/ClientState RPC -// method -message QueryClientStateRequest { - // client state unique identifier - string client_id = 1; -} - -// QueryClientStateResponse is the response type for the Query/ClientState RPC -// method. Besides the client state, it includes a proof and the height from -// which the proof was retrieved. -message QueryClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any client_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryClientStatesRequest is the request type for the Query/ClientStates RPC -// method -message QueryClientStatesRequest { - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryClientStatesResponse is the response type for the Query/ClientStates RPC -// method. -message QueryClientStatesResponse { - // list of stored ClientStates of the chain. - repeated IdentifiedClientState client_states = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryConsensusStateRequest is the request type for the Query/ConsensusState -// RPC method. Besides the consensus state, it includes a proof and the height -// from which the proof was retrieved. -message QueryConsensusStateRequest { - // client identifier - string client_id = 1; - // consensus state revision number - uint64 revision_number = 2; - // consensus state revision height - uint64 revision_height = 3; - // latest_height overrrides the height field and queries the latest stored - // ConsensusState - bool latest_height = 4; -} - -// QueryConsensusStateResponse is the response type for the Query/ConsensusState -// RPC method -message QueryConsensusStateResponse { - // consensus state associated with the client identifier at the given height - google.protobuf.Any consensus_state = 1; - // merkle proof of existence - bytes proof = 2; - // height at which the proof was retrieved - ibc.core.client.v1.Height proof_height = 3 [(gogoproto.nullable) = false]; -} - -// QueryConsensusStatesRequest is the request type for the Query/ConsensusStates -// RPC method. -message QueryConsensusStatesRequest { - // client identifier - string client_id = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConsensusStatesResponse is the response type for the -// Query/ConsensusStates RPC method -message QueryConsensusStatesResponse { - // consensus states associated with the identifier - repeated ConsensusStateWithHeight consensus_states = 1 [(gogoproto.nullable) = false]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryConsensusStateHeightsRequest is the request type for Query/ConsensusStateHeights -// RPC method. -message QueryConsensusStateHeightsRequest { - // client identifier - string client_id = 1; - // pagination request - cosmos.base.query.v1beta1.PageRequest pagination = 2; -} - -// QueryConsensusStateHeightsResponse is the response type for the -// Query/ConsensusStateHeights RPC method -message QueryConsensusStateHeightsResponse { - // consensus state heights - repeated Height consensus_state_heights = 1 [(gogoproto.nullable) = false]; - // pagination response - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryClientStatusRequest is the request type for the Query/ClientStatus RPC -// method -message QueryClientStatusRequest { - // client unique identifier - string client_id = 1; -} - -// QueryClientStatusResponse is the response type for the Query/ClientStatus RPC -// method. It returns the current status of the IBC client. -message QueryClientStatusResponse { - string status = 1; -} - -// QueryClientParamsRequest is the request type for the Query/ClientParams RPC -// method. -message QueryClientParamsRequest {} - -// QueryClientParamsResponse is the response type for the Query/ClientParams RPC -// method. -message QueryClientParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} - -// QueryUpgradedClientStateRequest is the request type for the -// Query/UpgradedClientState RPC method -message QueryUpgradedClientStateRequest {} - -// QueryUpgradedClientStateResponse is the response type for the -// Query/UpgradedClientState RPC method. -message QueryUpgradedClientStateResponse { - // client state associated with the request identifier - google.protobuf.Any upgraded_client_state = 1; -} - -// QueryUpgradedConsensusStateRequest is the request type for the -// Query/UpgradedConsensusState RPC method -message QueryUpgradedConsensusStateRequest {} - -// QueryUpgradedConsensusStateResponse is the response type for the -// Query/UpgradedConsensusState RPC method. -message QueryUpgradedConsensusStateResponse { - // Consensus state associated with the request identifier - google.protobuf.Any upgraded_consensus_state = 1; -} diff --git a/third_party/proto/ibc/core/client/v1/tx.proto b/third_party/proto/ibc/core/client/v1/tx.proto deleted file mode 100644 index b504ab692..000000000 --- a/third_party/proto/ibc/core/client/v1/tx.proto +++ /dev/null @@ -1,175 +0,0 @@ -syntax = "proto3"; - -package ibc.core.client.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; - -import "cosmos/msg/v1/msg.proto"; -import "cosmos/upgrade/v1beta1/upgrade.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; -import "ibc/core/client/v1/client.proto"; - -// Msg defines the ibc/client Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // CreateClient defines a rpc handler method for MsgCreateClient. - rpc CreateClient(MsgCreateClient) returns (MsgCreateClientResponse); - - // UpdateClient defines a rpc handler method for MsgUpdateClient. - rpc UpdateClient(MsgUpdateClient) returns (MsgUpdateClientResponse); - - // UpgradeClient defines a rpc handler method for MsgUpgradeClient. - rpc UpgradeClient(MsgUpgradeClient) returns (MsgUpgradeClientResponse); - - // SubmitMisbehaviour defines a rpc handler method for MsgSubmitMisbehaviour. - rpc SubmitMisbehaviour(MsgSubmitMisbehaviour) returns (MsgSubmitMisbehaviourResponse); - - // RecoverClient defines a rpc handler method for MsgRecoverClient. - rpc RecoverClient(MsgRecoverClient) returns (MsgRecoverClientResponse); - - // IBCSoftwareUpgrade defines a rpc handler method for MsgIBCSoftwareUpgrade. - rpc IBCSoftwareUpgrade(MsgIBCSoftwareUpgrade) returns (MsgIBCSoftwareUpgradeResponse); - - // UpdateClientParams defines a rpc handler method for MsgUpdateParams. - rpc UpdateClientParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgCreateClient defines a message to create an IBC client -message MsgCreateClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // light client state - google.protobuf.Any client_state = 1; - // consensus state associated with the client that corresponds to a given - // height. - google.protobuf.Any consensus_state = 2; - // signer address - string signer = 3; -} - -// MsgCreateClientResponse defines the Msg/CreateClient response type. -message MsgCreateClientResponse {} - -// MsgUpdateClient defines an sdk.Msg to update a IBC client state using -// the given client message. -message MsgUpdateClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // client message to update the light client - google.protobuf.Any client_message = 2; - // signer address - string signer = 3; -} - -// MsgUpdateClientResponse defines the Msg/UpdateClient response type. -message MsgUpdateClientResponse {} - -// MsgUpgradeClient defines an sdk.Msg to upgrade an IBC client to a new client -// state -message MsgUpgradeClient { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // upgraded client state - google.protobuf.Any client_state = 2; - // upgraded consensus state, only contains enough information to serve as a - // basis of trust in update logic - google.protobuf.Any consensus_state = 3; - // proof that old chain committed to new client - bytes proof_upgrade_client = 4; - // proof that old chain committed to new consensus state - bytes proof_upgrade_consensus_state = 5; - // signer address - string signer = 6; -} - -// MsgUpgradeClientResponse defines the Msg/UpgradeClient response type. -message MsgUpgradeClientResponse {} - -// MsgSubmitMisbehaviour defines an sdk.Msg type that submits Evidence for -// light client misbehaviour. -// This message has been deprecated. Use MsgUpdateClient instead. -message MsgSubmitMisbehaviour { - option deprecated = true; - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // client unique identifier - string client_id = 1; - // misbehaviour used for freezing the light client - google.protobuf.Any misbehaviour = 2; - // signer address - string signer = 3; -} - -// MsgSubmitMisbehaviourResponse defines the Msg/SubmitMisbehaviour response -// type. -message MsgSubmitMisbehaviourResponse {} - -// MsgRecoverClient defines the message used to recover a frozen or expired client. -message MsgRecoverClient { - option (gogoproto.goproto_getters) = false; - option (cosmos.msg.v1.signer) = "signer"; - - // the client identifier for the client to be updated if the proposal passes - string subject_client_id = 1; - // the substitute client identifier for the client which will replace the subject - // client - string substitute_client_id = 2; - - // signer address - string signer = 3; -} - -// MsgRecoverClientResponse defines the Msg/RecoverClient response type. -message MsgRecoverClientResponse {} - -// MsgIBCSoftwareUpgrade defines the message used to schedule an upgrade of an IBC client using a v1 governance proposal -message MsgIBCSoftwareUpgrade { - option (cosmos.msg.v1.signer) = "signer"; - cosmos.upgrade.v1beta1.Plan plan = 1 [(gogoproto.nullable) = false]; - // An UpgradedClientState must be provided to perform an IBC breaking upgrade. - // This will make the chain commit to the correct upgraded (self) client state - // before the upgrade occurs, so that connecting chains can verify that the - // new upgraded client is valid by verifying a proof on the previous version - // of the chain. This will allow IBC connections to persist smoothly across - // planned chain upgrades. Correspondingly, the UpgradedClientState field has been - // deprecated in the Cosmos SDK to allow for this logic to exist solely in - // the 02-client module. - google.protobuf.Any upgraded_client_state = 2; - // signer address - string signer = 3; -} - -// MsgIBCSoftwareUpgradeResponse defines the Msg/IBCSoftwareUpgrade response type. -message MsgIBCSoftwareUpgradeResponse {} - -// MsgUpdateParams defines the sdk.Msg type to update the client parameters. -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the client parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the MsgUpdateParams response type. -message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/core/commitment/v1/commitment.proto b/third_party/proto/ibc/core/commitment/v1/commitment.proto deleted file mode 100644 index b4753be2d..000000000 --- a/third_party/proto/ibc/core/commitment/v1/commitment.proto +++ /dev/null @@ -1,39 +0,0 @@ -syntax = "proto3"; - -package ibc.core.commitment.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/ics23/v1/proofs.proto"; - -// MerkleRoot defines a merkle root hash. -// In the Cosmos SDK, the AppHash of a block header becomes the root. -message MerkleRoot { - option (gogoproto.goproto_getters) = false; - - bytes hash = 1; -} - -// MerklePrefix is merkle path prefixed to the key. -// The constructed key from the Path and the key will be append(Path.KeyPath, -// append(Path.KeyPrefix, key...)) -message MerklePrefix { - bytes key_prefix = 1; -} - -// MerklePath is the path used to verify commitment proofs, which can be an -// arbitrary structured object (defined by a commitment type). -// MerklePath is represented from root-to-leaf -message MerklePath { - repeated string key_path = 1; -} - -// MerkleProof is a wrapper type over a chain of CommitmentProofs. -// It demonstrates membership or non-membership for an element or set of -// elements, verifiable in conjunction with a known commitment root. Proofs -// should be succinct. -// MerkleProofs are ordered from leaf-to-root -message MerkleProof { - repeated cosmos.ics23.v1.CommitmentProof proofs = 1; -} diff --git a/third_party/proto/ibc/fee/v1/ack.proto b/third_party/proto/ibc/fee/v1/ack.proto deleted file mode 100644 index 2f3746d2c..000000000 --- a/third_party/proto/ibc/fee/v1/ack.proto +++ /dev/null @@ -1,15 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -// IncentivizedAcknowledgement is the acknowledgement format to be used by applications wrapped in the fee middleware -message IncentivizedAcknowledgement { - // the underlying app acknowledgement bytes - bytes app_acknowledgement = 1; - // the relayer address which submits the recv packet message - string forward_relayer_address = 2; - // success flag of the base application callback - bool underlying_app_success = 3; -} diff --git a/third_party/proto/ibc/fee/v1/fee.proto b/third_party/proto/ibc/fee/v1/fee.proto deleted file mode 100644 index 867e88455..000000000 --- a/third_party/proto/ibc/fee/v1/fee.proto +++ /dev/null @@ -1,61 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "amino/amino.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "gogoproto/gogo.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "cosmos/msg/v1/msg.proto"; - -// Fee defines the ICS29 receive, acknowledgement and timeout fees -message Fee { - // the packet receive fee - repeated cosmos.base.v1beta1.Coin recv_fee = 1 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; - - // the packet acknowledgement fee - repeated cosmos.base.v1beta1.Coin ack_fee = 2 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; - - // the packet timeout fee - repeated cosmos.base.v1beta1.Coin timeout_fee = 3 [ - (gogoproto.nullable) = false, - (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", - (amino.encoding) = "legacy_coins" - ]; -} - -// PacketFee contains ICS29 relayer fees, refund address and optional list of permitted relayers -message PacketFee { - option (cosmos.msg.v1.signer) = "refund_address"; - - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - Fee fee = 1 [(gogoproto.nullable) = false]; - // the refund address for unspent fees - string refund_address = 2; - // optional list of relayers permitted to receive fees - repeated string relayers = 3; -} - -// PacketFees contains a list of type PacketFee -message PacketFees { - // list of packet fees - repeated PacketFee packet_fees = 1 [(gogoproto.nullable) = false]; -} - -// IdentifiedPacketFees contains a list of type PacketFee and associated PacketId -message IdentifiedPacketFees { - // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; - // list of packet fees - repeated PacketFee packet_fees = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/fee/v1/genesis.proto b/third_party/proto/ibc/fee/v1/genesis.proto deleted file mode 100644 index e48ceb535..000000000 --- a/third_party/proto/ibc/fee/v1/genesis.proto +++ /dev/null @@ -1,60 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// GenesisState defines the ICS29 fee middleware genesis state -message GenesisState { - // list of identified packet fees - repeated IdentifiedPacketFees identified_fees = 1 [(gogoproto.nullable) = false]; - // list of fee enabled channels - repeated FeeEnabledChannel fee_enabled_channels = 2 [(gogoproto.nullable) = false]; - // list of registered payees - repeated RegisteredPayee registered_payees = 3 [(gogoproto.nullable) = false]; - // list of registered counterparty payees - repeated RegisteredCounterpartyPayee registered_counterparty_payees = 4 [(gogoproto.nullable) = false]; - // list of forward relayer addresses - repeated ForwardRelayerAddress forward_relayers = 5 [(gogoproto.nullable) = false]; -} - -// FeeEnabledChannel contains the PortID & ChannelID for a fee enabled channel -message FeeEnabledChannel { - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; -} - -// RegisteredPayee contains the relayer address and payee address for a specific channel -message RegisteredPayee { - // unique channel identifier - string channel_id = 1; - // the relayer address - string relayer = 2; - // the payee address - string payee = 3; -} - -// RegisteredCounterpartyPayee contains the relayer address and counterparty payee address for a specific channel (used -// for recv fee distribution) -message RegisteredCounterpartyPayee { - // unique channel identifier - string channel_id = 1; - // the relayer address - string relayer = 2; - // the counterparty payee address - string counterparty_payee = 3; -} - -// ForwardRelayerAddress contains the forward relayer address and PacketId used for async acknowledgements -message ForwardRelayerAddress { - // the forward relayer address - string address = 1; - // unique packet identifer comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 2 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/fee/v1/metadata.proto b/third_party/proto/ibc/fee/v1/metadata.proto deleted file mode 100644 index 1e82e7c25..000000000 --- a/third_party/proto/ibc/fee/v1/metadata.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -// Metadata defines the ICS29 channel specific metadata encoded into the channel version bytestring -// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning -message Metadata { - // fee_version defines the ICS29 fee version - string fee_version = 1; - // app_version defines the underlying application version, which may or may not be a JSON encoded bytestring - string app_version = 2; -} diff --git a/third_party/proto/ibc/fee/v1/query.proto b/third_party/proto/ibc/fee/v1/query.proto deleted file mode 100644 index 726370ee0..000000000 --- a/third_party/proto/ibc/fee/v1/query.proto +++ /dev/null @@ -1,218 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "gogoproto/gogo.proto"; -import "google/api/annotations.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/applications/fee/v1/genesis.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Query defines the ICS29 gRPC querier service. -service Query { - // IncentivizedPackets returns all incentivized packets and their associated fees - rpc IncentivizedPackets(QueryIncentivizedPacketsRequest) returns (QueryIncentivizedPacketsResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/incentivized_packets"; - } - - // IncentivizedPacket returns all packet fees for a packet given its identifier - rpc IncentivizedPacket(QueryIncentivizedPacketRequest) returns (QueryIncentivizedPacketResponse) { - option (google.api.http).get = - "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/sequences/" - "{packet_id.sequence}/incentivized_packet"; - } - - // Gets all incentivized packets for a specific channel - rpc IncentivizedPacketsForChannel(QueryIncentivizedPacketsForChannelRequest) - returns (QueryIncentivizedPacketsForChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/incentivized_packets"; - } - - // TotalRecvFees returns the total receive fees for a packet given its identifier - rpc TotalRecvFees(QueryTotalRecvFeesRequest) returns (QueryTotalRecvFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_recv_fees"; - } - - // TotalAckFees returns the total acknowledgement fees for a packet given its identifier - rpc TotalAckFees(QueryTotalAckFeesRequest) returns (QueryTotalAckFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_ack_fees"; - } - - // TotalTimeoutFees returns the total timeout fees for a packet given its identifier - rpc TotalTimeoutFees(QueryTotalTimeoutFeesRequest) returns (QueryTotalTimeoutFeesResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{packet_id.channel_id}/ports/{packet_id.port_id}/" - "sequences/{packet_id.sequence}/total_timeout_fees"; - } - - // Payee returns the registered payee address for a specific channel given the relayer address - rpc Payee(QueryPayeeRequest) returns (QueryPayeeResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/payee"; - } - - // CounterpartyPayee returns the registered counterparty payee for forward relaying - rpc CounterpartyPayee(QueryCounterpartyPayeeRequest) returns (QueryCounterpartyPayeeResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/relayers/{relayer}/counterparty_payee"; - } - - // FeeEnabledChannels returns a list of all fee enabled channels - rpc FeeEnabledChannels(QueryFeeEnabledChannelsRequest) returns (QueryFeeEnabledChannelsResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/fee_enabled"; - } - - // FeeEnabledChannel returns true if the provided port and channel identifiers belong to a fee enabled channel - rpc FeeEnabledChannel(QueryFeeEnabledChannelRequest) returns (QueryFeeEnabledChannelResponse) { - option (google.api.http).get = "/ibc/apps/fee/v1/channels/{channel_id}/ports/{port_id}/fee_enabled"; - } -} - -// QueryIncentivizedPacketsRequest defines the request type for the IncentivizedPackets rpc -message QueryIncentivizedPacketsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - // block height at which to query - uint64 query_height = 2; -} - -// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPackets rpc -message QueryIncentivizedPacketsResponse { - // list of identified fees for incentivized packets - repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryIncentivizedPacketRequest defines the request type for the IncentivizedPacket rpc -message QueryIncentivizedPacketRequest { - // unique packet identifier comprised of channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; - // block height at which to query - uint64 query_height = 2; -} - -// QueryIncentivizedPacketsResponse defines the response type for the IncentivizedPacket rpc -message QueryIncentivizedPacketResponse { - // the identified fees for the incentivized packet - ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packet = 1 [(gogoproto.nullable) = false]; -} - -// QueryIncentivizedPacketsForChannelRequest defines the request type for querying for all incentivized packets -// for a specific channel -message QueryIncentivizedPacketsForChannelRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - string port_id = 2; - string channel_id = 3; - // Height to query at - uint64 query_height = 4; -} - -// QueryIncentivizedPacketsResponse defines the response type for the incentivized packets RPC -message QueryIncentivizedPacketsForChannelResponse { - // Map of all incentivized_packets - repeated ibc.applications.fee.v1.IdentifiedPacketFees incentivized_packets = 1; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryTotalRecvFeesRequest defines the request type for the TotalRecvFees rpc -message QueryTotalRecvFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalRecvFeesResponse defines the response type for the TotalRecvFees rpc -message QueryTotalRecvFeesResponse { - // the total packet receive fees - repeated cosmos.base.v1beta1.Coin recv_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryTotalAckFeesRequest defines the request type for the TotalAckFees rpc -message QueryTotalAckFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalAckFeesResponse defines the response type for the TotalAckFees rpc -message QueryTotalAckFeesResponse { - // the total packet acknowledgement fees - repeated cosmos.base.v1beta1.Coin ack_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryTotalTimeoutFeesRequest defines the request type for the TotalTimeoutFees rpc -message QueryTotalTimeoutFeesRequest { - // the packet identifier for the associated fees - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false]; -} - -// QueryTotalTimeoutFeesResponse defines the response type for the TotalTimeoutFees rpc -message QueryTotalTimeoutFeesResponse { - // the total packet timeout fees - repeated cosmos.base.v1beta1.Coin timeout_fees = 1 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; -} - -// QueryPayeeRequest defines the request type for the Payee rpc -message QueryPayeeRequest { - // unique channel identifier - string channel_id = 1; - // the relayer address to which the distribution address is registered - string relayer = 2; -} - -// QueryPayeeResponse defines the response type for the Payee rpc -message QueryPayeeResponse { - // the payee address to which packet fees are paid out - string payee_address = 1; -} - -// QueryCounterpartyPayeeRequest defines the request type for the CounterpartyPayee rpc -message QueryCounterpartyPayeeRequest { - // unique channel identifier - string channel_id = 1; - // the relayer address to which the counterparty is registered - string relayer = 2; -} - -// QueryCounterpartyPayeeResponse defines the response type for the CounterpartyPayee rpc -message QueryCounterpartyPayeeResponse { - // the counterparty payee address used to compensate forward relaying - string counterparty_payee = 1; -} - -// QueryFeeEnabledChannelsRequest defines the request type for the FeeEnabledChannels rpc -message QueryFeeEnabledChannelsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; - // block height at which to query - uint64 query_height = 2; -} - -// QueryFeeEnabledChannelsResponse defines the response type for the FeeEnabledChannels rpc -message QueryFeeEnabledChannelsResponse { - // list of fee enabled channels - repeated ibc.applications.fee.v1.FeeEnabledChannel fee_enabled_channels = 1 [(gogoproto.nullable) = false]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryFeeEnabledChannelRequest defines the request type for the FeeEnabledChannel rpc -message QueryFeeEnabledChannelRequest { - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; -} - -// QueryFeeEnabledChannelResponse defines the response type for the FeeEnabledChannel rpc -message QueryFeeEnabledChannelResponse { - // boolean flag representing the fee enabled channel status - bool fee_enabled = 1; -} diff --git a/third_party/proto/ibc/fee/v1/tx.proto b/third_party/proto/ibc/fee/v1/tx.proto deleted file mode 100644 index e59dddfd1..000000000 --- a/third_party/proto/ibc/fee/v1/tx.proto +++ /dev/null @@ -1,122 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.fee.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types"; - -import "amino/amino.proto"; -import "gogoproto/gogo.proto"; -import "ibc/applications/fee/v1/fee.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "cosmos/msg/v1/msg.proto"; - -// Msg defines the ICS29 Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // RegisterPayee defines a rpc handler method for MsgRegisterPayee - // RegisterPayee is called by the relayer on each channelEnd and allows them to set an optional - // payee to which reverse and timeout relayer packet fees will be paid out. The payee should be registered on - // the source chain from which packets originate as this is where fee distribution takes place. This function may be - // called more than once by a relayer, in which case, the latest payee is always used. - rpc RegisterPayee(MsgRegisterPayee) returns (MsgRegisterPayeeResponse); - - // RegisterCounterpartyPayee defines a rpc handler method for MsgRegisterCounterpartyPayee - // RegisterCounterpartyPayee is called by the relayer on each channelEnd and allows them to specify the counterparty - // payee address before relaying. This ensures they will be properly compensated for forward relaying since - // the destination chain must include the registered counterparty payee address in the acknowledgement. This function - // may be called more than once by a relayer, in which case, the latest counterparty payee address is always used. - rpc RegisterCounterpartyPayee(MsgRegisterCounterpartyPayee) returns (MsgRegisterCounterpartyPayeeResponse); - - // PayPacketFee defines a rpc handler method for MsgPayPacketFee - // PayPacketFee is an open callback that may be called by any module/user that wishes to escrow funds in order to - // incentivize the relaying of the packet at the next sequence - // NOTE: This method is intended to be used within a multi msg transaction, where the subsequent msg that follows - // initiates the lifecycle of the incentivized packet - rpc PayPacketFee(MsgPayPacketFee) returns (MsgPayPacketFeeResponse); - - // PayPacketFeeAsync defines a rpc handler method for MsgPayPacketFeeAsync - // PayPacketFeeAsync is an open callback that may be called by any module/user that wishes to escrow funds in order to - // incentivize the relaying of a known packet (i.e. at a particular sequence) - rpc PayPacketFeeAsync(MsgPayPacketFeeAsync) returns (MsgPayPacketFeeAsyncResponse); -} - -// MsgRegisterPayee defines the request type for the RegisterPayee rpc -message MsgRegisterPayee { - option (amino.name) = "cosmos-sdk/MsgRegisterPayee"; - option (cosmos.msg.v1.signer) = "relayer"; - - option (gogoproto.goproto_getters) = false; - - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; - // the relayer address - string relayer = 3; - // the payee address - string payee = 4; -} - -// MsgRegisterPayeeResponse defines the response type for the RegisterPayee rpc -message MsgRegisterPayeeResponse {} - -// MsgRegisterCounterpartyPayee defines the request type for the RegisterCounterpartyPayee rpc -message MsgRegisterCounterpartyPayee { - option (amino.name) = "cosmos-sdk/MsgRegisterCounterpartyPayee"; - option (cosmos.msg.v1.signer) = "relayer"; - - option (gogoproto.goproto_getters) = false; - - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; - // the relayer address - string relayer = 3; - // the counterparty payee address - string counterparty_payee = 4; -} - -// MsgRegisterCounterpartyPayeeResponse defines the response type for the RegisterCounterpartyPayee rpc -message MsgRegisterCounterpartyPayeeResponse {} - -// MsgPayPacketFee defines the request type for the PayPacketFee rpc -// This Msg can be used to pay for a packet at the next sequence send & should be combined with the Msg that will be -// paid for -message MsgPayPacketFee { - option (amino.name) = "cosmos-sdk/MsgPayPacketFee"; - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // fee encapsulates the recv, ack and timeout fees associated with an IBC packet - ibc.applications.fee.v1.Fee fee = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // the source port unique identifier - string source_port_id = 2; - // the source channel unique identifer - string source_channel_id = 3; - // account address to refund fee if necessary - string signer = 4; - // optional list of relayers permitted to the receive packet fees - repeated string relayers = 5; -} - -// MsgPayPacketFeeResponse defines the response type for the PayPacketFee rpc -message MsgPayPacketFeeResponse {} - -// MsgPayPacketFeeAsync defines the request type for the PayPacketFeeAsync rpc -// This Msg can be used to pay for a packet at a specified sequence (instead of the next sequence send) -message MsgPayPacketFeeAsync { - option (amino.name) = "cosmos-sdk/MsgPayPacketFeeAsync"; - option (cosmos.msg.v1.signer) = "packet_fee"; - option (gogoproto.goproto_getters) = false; - - // unique packet identifier comprised of the channel ID, port ID and sequence - ibc.core.channel.v1.PacketId packet_id = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // the packet fee associated with a particular IBC packet - PacketFee packet_fee = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; -} - -// MsgPayPacketFeeAsyncResponse defines the response type for the PayPacketFeeAsync rpc -message MsgPayPacketFeeAsyncResponse {} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto deleted file mode 100644 index 2e6bbe1a1..000000000 --- a/third_party/proto/ibc/interchain_accounts/controller/v1/controller.proto +++ /dev/null @@ -1,12 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -// Params defines the set of on-chain interchain accounts parameters. -// The following parameters may be used to disable the controller submodule. -message Params { - // controller_enabled enables or disables the controller submodule. - bool controller_enabled = 1; -} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto deleted file mode 100644 index 31885fcb2..000000000 --- a/third_party/proto/ibc/interchain_accounts/controller/v1/query.proto +++ /dev/null @@ -1,42 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "google/api/annotations.proto"; - -// Query provides defines the gRPC querier service. -service Query { - // InterchainAccount returns the interchain account address for a given owner address on a given connection - rpc InterchainAccount(QueryInterchainAccountRequest) returns (QueryInterchainAccountResponse) { - option (google.api.http).get = - "/ibc/apps/interchain_accounts/controller/v1/owners/{owner}/connections/{connection_id}"; - } - - // Params queries all parameters of the ICA controller submodule. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/ibc/apps/interchain_accounts/controller/v1/params"; - } -} - -// QueryInterchainAccountRequest is the request type for the Query/InterchainAccount RPC method. -message QueryInterchainAccountRequest { - string owner = 1; - string connection_id = 2; -} - -// QueryInterchainAccountResponse the response type for the Query/InterchainAccount RPC method. -message QueryInterchainAccountResponse { - string address = 1; -} - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} diff --git a/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto b/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto deleted file mode 100644 index ec5c2e62e..000000000 --- a/third_party/proto/ibc/interchain_accounts/controller/v1/tx.proto +++ /dev/null @@ -1,82 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.controller.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/interchain_accounts/v1/packet.proto"; -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "cosmos/msg/v1/msg.proto"; -import "ibc/core/channel/v1/channel.proto"; - -// Msg defines the 27-interchain-accounts/controller Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // RegisterInterchainAccount defines a rpc handler for MsgRegisterInterchainAccount. - rpc RegisterInterchainAccount(MsgRegisterInterchainAccount) returns (MsgRegisterInterchainAccountResponse); - // SendTx defines a rpc handler for MsgSendTx. - rpc SendTx(MsgSendTx) returns (MsgSendTxResponse); - // UpdateParams defines a rpc handler for MsgUpdateParams. - rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgRegisterInterchainAccount defines the payload for Msg/RegisterAccount -message MsgRegisterInterchainAccount { - option (cosmos.msg.v1.signer) = "owner"; - - option (gogoproto.goproto_getters) = false; - - string owner = 1; - string connection_id = 2; - string version = 3; - ibc.core.channel.v1.Order ordering = 4; -} - -// MsgRegisterInterchainAccountResponse defines the response for Msg/RegisterAccount -message MsgRegisterInterchainAccountResponse { - option (gogoproto.goproto_getters) = false; - - string channel_id = 1; - string port_id = 2; -} - -// MsgSendTx defines the payload for Msg/SendTx -message MsgSendTx { - option (cosmos.msg.v1.signer) = "owner"; - - option (gogoproto.goproto_getters) = false; - - string owner = 1; - string connection_id = 2; - ibc.applications.interchain_accounts.v1.InterchainAccountPacketData packet_data = 3 [(gogoproto.nullable) = false]; - // Relative timeout timestamp provided will be added to the current block time during transaction execution. - // The timeout timestamp must be non-zero. - uint64 relative_timeout = 4; -} - -// MsgSendTxResponse defines the response for MsgSendTx -message MsgSendTxResponse { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; -} - -// MsgUpdateParams defines the payload for Msg/UpdateParams -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the 27-interchain-accounts/controller parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response for Msg/UpdateParams -message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto b/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto deleted file mode 100644 index 4393e5b0b..000000000 --- a/third_party/proto/ibc/interchain_accounts/genesis/v1/genesis.proto +++ /dev/null @@ -1,47 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.genesis.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/genesis/types"; - -import "gogoproto/gogo.proto"; -import "ibc/applications/interchain_accounts/controller/v1/controller.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// GenesisState defines the interchain accounts genesis state -message GenesisState { - ControllerGenesisState controller_genesis_state = 1 [(gogoproto.nullable) = false]; - HostGenesisState host_genesis_state = 2 [(gogoproto.nullable) = false]; -} - -// ControllerGenesisState defines the interchain accounts controller genesis state -message ControllerGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; - repeated string ports = 3; - ibc.applications.interchain_accounts.controller.v1.Params params = 4 [(gogoproto.nullable) = false]; -} - -// HostGenesisState defines the interchain accounts host genesis state -message HostGenesisState { - repeated ActiveChannel active_channels = 1 [(gogoproto.nullable) = false]; - repeated RegisteredInterchainAccount interchain_accounts = 2 [(gogoproto.nullable) = false]; - string port = 3; - ibc.applications.interchain_accounts.host.v1.Params params = 4 [(gogoproto.nullable) = false]; -} - -// ActiveChannel contains a connection ID, port ID and associated active channel ID, as well as a boolean flag to -// indicate if the channel is middleware enabled -message ActiveChannel { - string connection_id = 1; - string port_id = 2; - string channel_id = 3; - bool is_middleware_enabled = 4; -} - -// RegisteredInterchainAccount contains a connection ID, port ID and associated interchain account address -message RegisteredInterchainAccount { - string connection_id = 1; - string port_id = 2; - string account_address = 3; -} \ No newline at end of file diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/host.proto b/third_party/proto/ibc/interchain_accounts/host/v1/host.proto deleted file mode 100644 index f03685711..000000000 --- a/third_party/proto/ibc/interchain_accounts/host/v1/host.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -// Params defines the set of on-chain interchain accounts parameters. -// The following parameters may be used to disable the host submodule. -message Params { - // host_enabled enables or disables the host submodule. - bool host_enabled = 1; - // allow_messages defines a list of sdk message typeURLs allowed to be executed on a host chain. - repeated string allow_messages = 2; -} diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/query.proto b/third_party/proto/ibc/interchain_accounts/host/v1/query.proto deleted file mode 100644 index 6f206a14c..000000000 --- a/third_party/proto/ibc/interchain_accounts/host/v1/query.proto +++ /dev/null @@ -1,25 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -import "google/api/annotations.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// Query provides defines the gRPC querier service. -service Query { - // Params queries all parameters of the ICA host submodule. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/ibc/apps/interchain_accounts/host/v1/params"; - } -} - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} diff --git a/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto b/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto deleted file mode 100644 index 5a8073bc9..000000000 --- a/third_party/proto/ibc/interchain_accounts/host/v1/tx.proto +++ /dev/null @@ -1,35 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.host.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"; - -import "gogoproto/gogo.proto"; -import "cosmos/msg/v1/msg.proto"; -import "ibc/applications/interchain_accounts/host/v1/host.proto"; - -// Msg defines the 27-interchain-accounts/host Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // UpdateParams defines a rpc handler for MsgUpdateParams. - rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgUpdateParams defines the payload for Msg/UpdateParams -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the 27-interchain-accounts/host parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response for Msg/UpdateParams -message MsgUpdateParamsResponse {} diff --git a/third_party/proto/ibc/interchain_accounts/v1/account.proto b/third_party/proto/ibc/interchain_accounts/v1/account.proto deleted file mode 100644 index 4a6947c1c..000000000 --- a/third_party/proto/ibc/interchain_accounts/v1/account.proto +++ /dev/null @@ -1,19 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; -import "cosmos/auth/v1beta1/auth.proto"; - -// An InterchainAccount is defined as a BaseAccount & the address of the account owner on the controller chain -message InterchainAccount { - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - option (cosmos_proto.implements_interface) = "ibc.applications.interchain_accounts.v1.InterchainAccountI"; - - cosmos.auth.v1beta1.BaseAccount base_account = 1 [(gogoproto.embed) = true]; - string account_owner = 2; -} diff --git a/third_party/proto/ibc/interchain_accounts/v1/metadata.proto b/third_party/proto/ibc/interchain_accounts/v1/metadata.proto deleted file mode 100644 index df72b41eb..000000000 --- a/third_party/proto/ibc/interchain_accounts/v1/metadata.proto +++ /dev/null @@ -1,23 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -// Metadata defines a set of protocol specific data encoded into the ICS27 channel version bytestring -// See ICS004: https://github.com/cosmos/ibc/tree/master/spec/core/ics-004-channel-and-packet-semantics#Versioning -message Metadata { - // version defines the ICS27 protocol version - string version = 1; - // controller_connection_id is the connection identifier associated with the controller chain - string controller_connection_id = 2; - // host_connection_id is the connection identifier associated with the host chain - string host_connection_id = 3; - // address defines the interchain account address to be fulfilled upon the OnChanOpenTry handshake step - // NOTE: the address field is empty on the OnChanOpenInit handshake step - string address = 4; - // encoding defines the supported codec format - string encoding = 5; - // tx_type defines the type of transactions the interchain account can execute - string tx_type = 6; -} diff --git a/third_party/proto/ibc/interchain_accounts/v1/packet.proto b/third_party/proto/ibc/interchain_accounts/v1/packet.proto deleted file mode 100644 index f75a1463e..000000000 --- a/third_party/proto/ibc/interchain_accounts/v1/packet.proto +++ /dev/null @@ -1,31 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.interchain_accounts.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"; - -import "google/protobuf/any.proto"; -import "gogoproto/gogo.proto"; - -// Type defines a classification of message issued from a controller chain to its associated interchain accounts -// host -enum Type { - option (gogoproto.goproto_enum_prefix) = false; - - // Default zero value enumeration - TYPE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Execute a transaction on an interchain accounts host chain - TYPE_EXECUTE_TX = 1 [(gogoproto.enumvalue_customname) = "EXECUTE_TX"]; -} - -// InterchainAccountPacketData is comprised of a raw transaction, type of transaction and optional memo field. -message InterchainAccountPacketData { - Type type = 1; - bytes data = 2; - string memo = 3; -} - -// CosmosTx contains a list of sdk.Msg's. It should be used when sending transactions to an SDK host chain. -message CosmosTx { - repeated google.protobuf.Any messages = 1; -} diff --git a/third_party/proto/ibc/lightclients/localhost/v2/localhost.proto b/third_party/proto/ibc/lightclients/localhost/v2/localhost.proto deleted file mode 100644 index 635db8521..000000000 --- a/third_party/proto/ibc/lightclients/localhost/v2/localhost.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.localhost.v2; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost;localhost"; - -import "ibc/core/client/v1/client.proto"; -import "gogoproto/gogo.proto"; - -// ClientState defines the 09-localhost client state -message ClientState { - option (gogoproto.goproto_getters) = false; - - // the latest block height - ibc.core.client.v1.Height latest_height = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto deleted file mode 100644 index 9dc2690c5..000000000 --- a/third_party/proto/ibc/lightclients/solomachine/v2/solomachine.proto +++ /dev/null @@ -1,189 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v2; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7"; - -import "ibc/core/connection/v1/connection.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - bool is_frozen = 2; - ConsensusState consensus_state = 3; - // when set to true, will allow governance to update a solo machine client. - // The client will be unfrozen if it is frozen. - bool allow_update_after_proposal = 4; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - // sequence to update solo machine public key at - uint64 sequence = 1; - uint64 timestamp = 2; - bytes signature = 3; - google.protobuf.Any new_public_key = 4; - string new_diversifier = 5; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - string client_id = 1; - uint64 sequence = 2; - SignatureAndData signature_one = 3; - SignatureAndData signature_two = 4; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - bytes signature = 1; - DataType data_type = 2; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - bytes signature_data = 1; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; - // type of the data used - DataType data_type = 4; - // marshaled data - bytes data = 5; -} - -// DataType defines the type of solo machine proof being created. This is done -// to preserve uniqueness of different data sign byte encodings. -enum DataType { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Data type for client state verification - DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"]; - // Data type for consensus state verification - DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"]; - // Data type for connection state verification - DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"]; - // Data type for channel state verification - DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"]; - // Data type for packet commitment verification - DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"]; - // Data type for packet acknowledgement verification - DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"]; - // Data type for packet receipt absence verification - DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"]; - // Data type for next sequence recv verification - DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"]; - // Data type for header verification - DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"]; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1; - // header diversifier - string new_diversifier = 2; -} - -// ClientStateData returns the SignBytes data for client state verification. -message ClientStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any client_state = 2; -} - -// ConsensusStateData returns the SignBytes data for consensus state -// verification. -message ConsensusStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any consensus_state = 2; -} - -// ConnectionStateData returns the SignBytes data for connection state -// verification. -message ConnectionStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.connection.v1.ConnectionEnd connection = 2; -} - -// ChannelStateData returns the SignBytes data for channel state -// verification. -message ChannelStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.channel.v1.Channel channel = 2; -} - -// PacketCommitmentData returns the SignBytes data for packet commitment -// verification. -message PacketCommitmentData { - bytes path = 1; - bytes commitment = 2; -} - -// PacketAcknowledgementData returns the SignBytes data for acknowledgement -// verification. -message PacketAcknowledgementData { - bytes path = 1; - bytes acknowledgement = 2; -} - -// PacketReceiptAbsenceData returns the SignBytes data for -// packet receipt absence verification. -message PacketReceiptAbsenceData { - bytes path = 1; -} - -// NextSequenceRecvData returns the SignBytes data for verification of the next -// sequence to be received. -message NextSequenceRecvData { - bytes path = 1; - uint64 next_seq_recv = 2; -} diff --git a/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto b/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto deleted file mode 100644 index 194905b38..000000000 --- a/third_party/proto/ibc/lightclients/solomachine/v3/solomachine.proto +++ /dev/null @@ -1,99 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v3; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine;solomachine"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - bool is_frozen = 2; - ConsensusState consensus_state = 3; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - - uint64 timestamp = 1; - bytes signature = 2; - google.protobuf.Any new_public_key = 3; - string new_diversifier = 4; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - SignatureAndData signature_one = 2; - SignatureAndData signature_two = 3; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - - bytes signature = 1; - bytes path = 2; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - - bytes signature_data = 1; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - // the sequence number - uint64 sequence = 1; - // the proof timestamp - uint64 timestamp = 2; - // the public key diversifier - string diversifier = 3; - // the standardised path bytes - bytes path = 4; - // the marshaled data bytes - bytes data = 5; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1; - // header diversifier - string new_diversifier = 2; -} diff --git a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto b/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto deleted file mode 100644 index 505361222..000000000 --- a/third_party/proto/ibc/lightclients/tendermint/v1/tendermint.proto +++ /dev/null @@ -1,101 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.tendermint.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint;tendermint"; - -import "tendermint/types/validator.proto"; -import "tendermint/types/types.proto"; -import "cosmos/ics23/v1/proofs.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/commitment/v1/commitment.proto"; -import "gogoproto/gogo.proto"; - -// ClientState from Tendermint tracks the current validator set, latest height, -// and a possible frozen height. -message ClientState { - option (gogoproto.goproto_getters) = false; - - string chain_id = 1; - Fraction trust_level = 2 [(gogoproto.nullable) = false]; - // duration of the period since the LastestTimestamp during which the - // submitted headers are valid for upgrade - google.protobuf.Duration trusting_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // duration of the staking unbonding period - google.protobuf.Duration unbonding_period = 4 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // defines how much new (untrusted) header's Time can drift into the future. - google.protobuf.Duration max_clock_drift = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // Block height when the client was frozen due to a misbehaviour - ibc.core.client.v1.Height frozen_height = 6 [(gogoproto.nullable) = false]; - // Latest height the client was updated to - ibc.core.client.v1.Height latest_height = 7 [(gogoproto.nullable) = false]; - - // Proof specifications used in verifying counterparty state - repeated cosmos.ics23.v1.ProofSpec proof_specs = 8; - - // Path at which next upgraded client will be committed. - // Each element corresponds to the key for a single CommitmentProof in the - // chained proof. NOTE: ClientState must stored under - // `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored - // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using - // the default upgrade module, upgrade_path should be []string{"upgrade", - // "upgradedIBCState"}` - repeated string upgrade_path = 9; - - // allow_update_after_expiry is deprecated - bool allow_update_after_expiry = 10 [deprecated = true]; - // allow_update_after_misbehaviour is deprecated - bool allow_update_after_misbehaviour = 11 [deprecated = true]; -} - -// ConsensusState defines the consensus state from Tendermint. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - - // timestamp that corresponds to the block height in which the ConsensusState - // was stored. - google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - // commitment root (i.e app hash) - ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; - bytes next_validators_hash = 3 [(gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes"]; -} - -// Misbehaviour is a wrapper over two conflicting Headers -// that implements Misbehaviour interface expected by ICS-02 -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - - // ClientID is deprecated - string client_id = 1 [deprecated = true]; - Header header_1 = 2 [(gogoproto.customname) = "Header1"]; - Header header_2 = 3 [(gogoproto.customname) = "Header2"]; -} - -// Header defines the Tendermint client consensus Header. -// It encapsulates all the information necessary to update from a trusted -// Tendermint ConsensusState. The inclusion of TrustedHeight and -// TrustedValidators allows this update to process correctly, so long as the -// ConsensusState for the TrustedHeight exists, this removes race conditions -// among relayers The SignedHeader and ValidatorSet are the new untrusted update -// fields for the client. The TrustedHeight is the height of a stored -// ConsensusState on the client that will be used to verify the new untrusted -// header. The Trusted ConsensusState must be within the unbonding period of -// current time in order to correctly verify, and the TrustedValidators must -// hash to TrustedConsensusState.NextValidatorsHash since that is the last -// trusted validator set at the TrustedHeight. -message Header { - .tendermint.types.SignedHeader signed_header = 1 [(gogoproto.embed) = true]; - - .tendermint.types.ValidatorSet validator_set = 2; - ibc.core.client.v1.Height trusted_height = 3 [(gogoproto.nullable) = false]; - .tendermint.types.ValidatorSet trusted_validators = 4; -} - -// Fraction defines the protobuf message type for tmmath.Fraction that only -// supports positive values. -message Fraction { - uint64 numerator = 1; - uint64 denominator = 2; -} diff --git a/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto b/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto deleted file mode 100644 index 637ba1677..000000000 --- a/third_party/proto/ibc/lightclients/wasm/v1/genesis.proto +++ /dev/null @@ -1,20 +0,0 @@ - -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// GenesisState defines 08-wasm's keeper genesis state -message GenesisState { - // uploaded light client wasm contracts - repeated Contract contracts = 1 [(gogoproto.nullable) = false]; -} - -// Contract stores contract code -message Contract { - option (gogoproto.goproto_getters) = false; - // contract byte code - bytes code_bytes = 1; -} \ No newline at end of file diff --git a/third_party/proto/ibc/lightclients/wasm/v1/query.proto b/third_party/proto/ibc/lightclients/wasm/v1/query.proto deleted file mode 100644 index bbbed29dd..000000000 --- a/third_party/proto/ibc/lightclients/wasm/v1/query.proto +++ /dev/null @@ -1,46 +0,0 @@ -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// Query service for wasm module -service Query { - // Get all Wasm checksums - rpc Checksums(QueryChecksumsRequest) returns (QueryChecksumsResponse) { - option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums"; - } - - // Get Wasm code for given checksum - rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { - option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums/{checksum}/code"; - } -} - -// QueryChecksumsRequest is the request type for the Query/Checksums RPC method. -message QueryChecksumsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryChecksumsResponse is the response type for the Query/Checksums RPC method. -message QueryChecksumsResponse { - // checksums is a list of the hex encoded checksums of all wasm codes stored. - repeated string checksums = 1; - - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryCodeRequest is the request type for the Query/Code RPC method. -message QueryCodeRequest { - // checksum is a hex encoded string of the code stored. - string checksum = 1; -} - -// QueryCodeResponse is the response type for the Query/Code RPC method. -message QueryCodeResponse { - bytes data = 1; -} diff --git a/third_party/proto/ibc/lightclients/wasm/v1/tx.proto b/third_party/proto/ibc/lightclients/wasm/v1/tx.proto deleted file mode 100644 index d2fc46591..000000000 --- a/third_party/proto/ibc/lightclients/wasm/v1/tx.proto +++ /dev/null @@ -1,66 +0,0 @@ -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -import "cosmos/msg/v1/msg.proto"; - -// Msg defines the ibc/08-wasm Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // StoreCode defines a rpc handler method for MsgStoreCode. - rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); - - // RemoveChecksum defines a rpc handler method for MsgRemoveChecksum. - rpc RemoveChecksum(MsgRemoveChecksum) returns (MsgRemoveChecksumResponse); - - // MigrateContract defines a rpc handler method for MsgMigrateContract. - rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse); -} - -// MsgStoreCode defines the request type for the StoreCode rpc. -message MsgStoreCode { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // wasm byte code of light client contract. It can be raw or gzip compressed - bytes wasm_byte_code = 2; -} - -// MsgStoreCodeResponse defines the response type for the StoreCode rpc -message MsgStoreCodeResponse { - // checksum is the sha256 hash of the stored code - bytes checksum = 1; -} - -// MsgRemoveChecksum defines the request type for the MsgRemoveChecksum rpc. -message MsgRemoveChecksum { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // checksum is the sha256 hash to be removed from the store - bytes checksum = 2; -} - -// MsgStoreChecksumResponse defines the response type for the StoreCode rpc -message MsgRemoveChecksumResponse {} - -// MsgMigrateContract defines the request type for the MigrateContract rpc. -message MsgMigrateContract { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // the client id of the contract - string client_id = 2; - // checksum is the sha256 hash of the new wasm byte code for the contract - bytes checksum = 3; - // the json encoded message to be passed to the contract on migration - bytes msg = 4; -} - -// MsgMigrateContractResponse defines the response type for the MigrateContract rpc -message MsgMigrateContractResponse {} diff --git a/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto b/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto deleted file mode 100644 index b6a45e3d8..000000000 --- a/third_party/proto/ibc/lightclients/wasm/v1/wasm.proto +++ /dev/null @@ -1,43 +0,0 @@ - -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// Wasm light client's Client state -message ClientState { - option (gogoproto.goproto_getters) = false; - // bytes encoding the client state of the underlying light client - // implemented as a Wasm contract. - bytes data = 1; - bytes checksum = 2; - ibc.core.client.v1.Height latest_height = 3 [(gogoproto.nullable) = false]; -} - -// Wasm light client's ConsensusState -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // bytes encoding the consensus state of the underlying light client - // implemented as a Wasm contract. - bytes data = 1; -} - -// Wasm light client message (either header(s) or misbehaviour) -message ClientMessage { - option (gogoproto.goproto_getters) = false; - - bytes data = 1; -} - -// Checksums defines a list of all checksums that are stored -// -// Deprecated: This message is deprecated in favor of storing the checksums -// using a Collections.KeySet. -message Checksums { - option deprecated = true; - - repeated bytes checksums = 1; -} \ No newline at end of file diff --git a/third_party/proto/ibc/localhost/v2/localhost.proto b/third_party/proto/ibc/localhost/v2/localhost.proto deleted file mode 100644 index 635db8521..000000000 --- a/third_party/proto/ibc/localhost/v2/localhost.proto +++ /dev/null @@ -1,16 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.localhost.v2; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost;localhost"; - -import "ibc/core/client/v1/client.proto"; -import "gogoproto/gogo.proto"; - -// ClientState defines the 09-localhost client state -message ClientState { - option (gogoproto.goproto_getters) = false; - - // the latest block height - ibc.core.client.v1.Height latest_height = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/solomachine/v2/solomachine.proto b/third_party/proto/ibc/solomachine/v2/solomachine.proto deleted file mode 100644 index 9dc2690c5..000000000 --- a/third_party/proto/ibc/solomachine/v2/solomachine.proto +++ /dev/null @@ -1,189 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v2; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/migrations/v7"; - -import "ibc/core/connection/v1/connection.proto"; -import "ibc/core/channel/v1/channel.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - bool is_frozen = 2; - ConsensusState consensus_state = 3; - // when set to true, will allow governance to update a solo machine client. - // The client will be unfrozen if it is frozen. - bool allow_update_after_proposal = 4; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - // sequence to update solo machine public key at - uint64 sequence = 1; - uint64 timestamp = 2; - bytes signature = 3; - google.protobuf.Any new_public_key = 4; - string new_diversifier = 5; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - string client_id = 1; - uint64 sequence = 2; - SignatureAndData signature_one = 3; - SignatureAndData signature_two = 4; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - bytes signature = 1; - DataType data_type = 2; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - bytes signature_data = 1; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - uint64 timestamp = 2; - string diversifier = 3; - // type of the data used - DataType data_type = 4; - // marshaled data - bytes data = 5; -} - -// DataType defines the type of solo machine proof being created. This is done -// to preserve uniqueness of different data sign byte encodings. -enum DataType { - option (gogoproto.goproto_enum_prefix) = false; - - // Default State - DATA_TYPE_UNINITIALIZED_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "UNSPECIFIED"]; - // Data type for client state verification - DATA_TYPE_CLIENT_STATE = 1 [(gogoproto.enumvalue_customname) = "CLIENT"]; - // Data type for consensus state verification - DATA_TYPE_CONSENSUS_STATE = 2 [(gogoproto.enumvalue_customname) = "CONSENSUS"]; - // Data type for connection state verification - DATA_TYPE_CONNECTION_STATE = 3 [(gogoproto.enumvalue_customname) = "CONNECTION"]; - // Data type for channel state verification - DATA_TYPE_CHANNEL_STATE = 4 [(gogoproto.enumvalue_customname) = "CHANNEL"]; - // Data type for packet commitment verification - DATA_TYPE_PACKET_COMMITMENT = 5 [(gogoproto.enumvalue_customname) = "PACKETCOMMITMENT"]; - // Data type for packet acknowledgement verification - DATA_TYPE_PACKET_ACKNOWLEDGEMENT = 6 [(gogoproto.enumvalue_customname) = "PACKETACKNOWLEDGEMENT"]; - // Data type for packet receipt absence verification - DATA_TYPE_PACKET_RECEIPT_ABSENCE = 7 [(gogoproto.enumvalue_customname) = "PACKETRECEIPTABSENCE"]; - // Data type for next sequence recv verification - DATA_TYPE_NEXT_SEQUENCE_RECV = 8 [(gogoproto.enumvalue_customname) = "NEXTSEQUENCERECV"]; - // Data type for header verification - DATA_TYPE_HEADER = 9 [(gogoproto.enumvalue_customname) = "HEADER"]; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1; - // header diversifier - string new_diversifier = 2; -} - -// ClientStateData returns the SignBytes data for client state verification. -message ClientStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any client_state = 2; -} - -// ConsensusStateData returns the SignBytes data for consensus state -// verification. -message ConsensusStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - google.protobuf.Any consensus_state = 2; -} - -// ConnectionStateData returns the SignBytes data for connection state -// verification. -message ConnectionStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.connection.v1.ConnectionEnd connection = 2; -} - -// ChannelStateData returns the SignBytes data for channel state -// verification. -message ChannelStateData { - option (gogoproto.goproto_getters) = false; - - bytes path = 1; - ibc.core.channel.v1.Channel channel = 2; -} - -// PacketCommitmentData returns the SignBytes data for packet commitment -// verification. -message PacketCommitmentData { - bytes path = 1; - bytes commitment = 2; -} - -// PacketAcknowledgementData returns the SignBytes data for acknowledgement -// verification. -message PacketAcknowledgementData { - bytes path = 1; - bytes acknowledgement = 2; -} - -// PacketReceiptAbsenceData returns the SignBytes data for -// packet receipt absence verification. -message PacketReceiptAbsenceData { - bytes path = 1; -} - -// NextSequenceRecvData returns the SignBytes data for verification of the next -// sequence to be received. -message NextSequenceRecvData { - bytes path = 1; - uint64 next_seq_recv = 2; -} diff --git a/third_party/proto/ibc/solomachine/v3/solomachine.proto b/third_party/proto/ibc/solomachine/v3/solomachine.proto deleted file mode 100644 index 194905b38..000000000 --- a/third_party/proto/ibc/solomachine/v3/solomachine.proto +++ /dev/null @@ -1,99 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.solomachine.v3; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine;solomachine"; - -import "gogoproto/gogo.proto"; -import "google/protobuf/any.proto"; - -// ClientState defines a solo machine client that tracks the current consensus -// state and if the client is frozen. -message ClientState { - option (gogoproto.goproto_getters) = false; - // latest sequence of the client state - uint64 sequence = 1; - // frozen sequence of the solo machine - bool is_frozen = 2; - ConsensusState consensus_state = 3; -} - -// ConsensusState defines a solo machine consensus state. The sequence of a -// consensus state is contained in the "height" key used in storing the -// consensus state. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // public key of the solo machine - google.protobuf.Any public_key = 1; - // diversifier allows the same public key to be re-used across different solo - // machine clients (potentially on different chains) without being considered - // misbehaviour. - string diversifier = 2; - uint64 timestamp = 3; -} - -// Header defines a solo machine consensus header -message Header { - option (gogoproto.goproto_getters) = false; - - uint64 timestamp = 1; - bytes signature = 2; - google.protobuf.Any new_public_key = 3; - string new_diversifier = 4; -} - -// Misbehaviour defines misbehaviour for a solo machine which consists -// of a sequence and two signatures over different messages at that sequence. -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - - uint64 sequence = 1; - SignatureAndData signature_one = 2; - SignatureAndData signature_two = 3; -} - -// SignatureAndData contains a signature and the data signed over to create that -// signature. -message SignatureAndData { - option (gogoproto.goproto_getters) = false; - - bytes signature = 1; - bytes path = 2; - bytes data = 3; - uint64 timestamp = 4; -} - -// TimestampedSignatureData contains the signature data and the timestamp of the -// signature. -message TimestampedSignatureData { - option (gogoproto.goproto_getters) = false; - - bytes signature_data = 1; - uint64 timestamp = 2; -} - -// SignBytes defines the signed bytes used for signature verification. -message SignBytes { - option (gogoproto.goproto_getters) = false; - - // the sequence number - uint64 sequence = 1; - // the proof timestamp - uint64 timestamp = 2; - // the public key diversifier - string diversifier = 3; - // the standardised path bytes - bytes path = 4; - // the marshaled data bytes - bytes data = 5; -} - -// HeaderData returns the SignBytes data for update verification. -message HeaderData { - option (gogoproto.goproto_getters) = false; - - // header public key - google.protobuf.Any new_pub_key = 1; - // header diversifier - string new_diversifier = 2; -} diff --git a/third_party/proto/ibc/tendermint/v1/tendermint.proto b/third_party/proto/ibc/tendermint/v1/tendermint.proto deleted file mode 100644 index 505361222..000000000 --- a/third_party/proto/ibc/tendermint/v1/tendermint.proto +++ /dev/null @@ -1,101 +0,0 @@ -syntax = "proto3"; - -package ibc.lightclients.tendermint.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint;tendermint"; - -import "tendermint/types/validator.proto"; -import "tendermint/types/types.proto"; -import "cosmos/ics23/v1/proofs.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/core/commitment/v1/commitment.proto"; -import "gogoproto/gogo.proto"; - -// ClientState from Tendermint tracks the current validator set, latest height, -// and a possible frozen height. -message ClientState { - option (gogoproto.goproto_getters) = false; - - string chain_id = 1; - Fraction trust_level = 2 [(gogoproto.nullable) = false]; - // duration of the period since the LastestTimestamp during which the - // submitted headers are valid for upgrade - google.protobuf.Duration trusting_period = 3 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // duration of the staking unbonding period - google.protobuf.Duration unbonding_period = 4 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // defines how much new (untrusted) header's Time can drift into the future. - google.protobuf.Duration max_clock_drift = 5 [(gogoproto.nullable) = false, (gogoproto.stdduration) = true]; - // Block height when the client was frozen due to a misbehaviour - ibc.core.client.v1.Height frozen_height = 6 [(gogoproto.nullable) = false]; - // Latest height the client was updated to - ibc.core.client.v1.Height latest_height = 7 [(gogoproto.nullable) = false]; - - // Proof specifications used in verifying counterparty state - repeated cosmos.ics23.v1.ProofSpec proof_specs = 8; - - // Path at which next upgraded client will be committed. - // Each element corresponds to the key for a single CommitmentProof in the - // chained proof. NOTE: ClientState must stored under - // `{upgradePath}/{upgradeHeight}/clientState` ConsensusState must be stored - // under `{upgradepath}/{upgradeHeight}/consensusState` For SDK chains using - // the default upgrade module, upgrade_path should be []string{"upgrade", - // "upgradedIBCState"}` - repeated string upgrade_path = 9; - - // allow_update_after_expiry is deprecated - bool allow_update_after_expiry = 10 [deprecated = true]; - // allow_update_after_misbehaviour is deprecated - bool allow_update_after_misbehaviour = 11 [deprecated = true]; -} - -// ConsensusState defines the consensus state from Tendermint. -message ConsensusState { - option (gogoproto.goproto_getters) = false; - - // timestamp that corresponds to the block height in which the ConsensusState - // was stored. - google.protobuf.Timestamp timestamp = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - // commitment root (i.e app hash) - ibc.core.commitment.v1.MerkleRoot root = 2 [(gogoproto.nullable) = false]; - bytes next_validators_hash = 3 [(gogoproto.casttype) = "github.com/cometbft/cometbft/libs/bytes.HexBytes"]; -} - -// Misbehaviour is a wrapper over two conflicting Headers -// that implements Misbehaviour interface expected by ICS-02 -message Misbehaviour { - option (gogoproto.goproto_getters) = false; - - // ClientID is deprecated - string client_id = 1 [deprecated = true]; - Header header_1 = 2 [(gogoproto.customname) = "Header1"]; - Header header_2 = 3 [(gogoproto.customname) = "Header2"]; -} - -// Header defines the Tendermint client consensus Header. -// It encapsulates all the information necessary to update from a trusted -// Tendermint ConsensusState. The inclusion of TrustedHeight and -// TrustedValidators allows this update to process correctly, so long as the -// ConsensusState for the TrustedHeight exists, this removes race conditions -// among relayers The SignedHeader and ValidatorSet are the new untrusted update -// fields for the client. The TrustedHeight is the height of a stored -// ConsensusState on the client that will be used to verify the new untrusted -// header. The Trusted ConsensusState must be within the unbonding period of -// current time in order to correctly verify, and the TrustedValidators must -// hash to TrustedConsensusState.NextValidatorsHash since that is the last -// trusted validator set at the TrustedHeight. -message Header { - .tendermint.types.SignedHeader signed_header = 1 [(gogoproto.embed) = true]; - - .tendermint.types.ValidatorSet validator_set = 2; - ibc.core.client.v1.Height trusted_height = 3 [(gogoproto.nullable) = false]; - .tendermint.types.ValidatorSet trusted_validators = 4; -} - -// Fraction defines the protobuf message type for tmmath.Fraction that only -// supports positive values. -message Fraction { - uint64 numerator = 1; - uint64 denominator = 2; -} diff --git a/third_party/proto/ibc/transfer/v1/authz.proto b/third_party/proto/ibc/transfer/v1/authz.proto deleted file mode 100644 index e7561b070..000000000 --- a/third_party/proto/ibc/transfer/v1/authz.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -import "cosmos_proto/cosmos.proto"; -import "gogoproto/gogo.proto"; -import "cosmos/base/v1beta1/coin.proto"; - -// Allocation defines the spend limit for a particular port and channel -message Allocation { - // the port on which the packet will be sent - string source_port = 1; - // the channel by which the packet will be sent - string source_channel = 2; - // spend limitation on the channel - repeated cosmos.base.v1beta1.Coin spend_limit = 3 - [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; - // allow list of receivers, an empty allow list permits any receiver address - repeated string allow_list = 4; - // allow list of packet data keys, an empty list prohibits all packet data keys; - // a list only with "*" permits any packet data key - repeated string allowed_packet_data = 5; -} - -// TransferAuthorization allows the grantee to spend up to spend_limit coins from -// the granter's account for ibc transfer on a specific channel -message TransferAuthorization { - option (cosmos_proto.implements_interface) = "cosmos.authz.v1beta1.Authorization"; - - // port and channel amounts - repeated Allocation allocations = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/transfer/v1/genesis.proto b/third_party/proto/ibc/transfer/v1/genesis.proto deleted file mode 100644 index f7d707f6c..000000000 --- a/third_party/proto/ibc/transfer/v1/genesis.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -import "ibc/applications/transfer/v1/transfer.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "gogoproto/gogo.proto"; - -// GenesisState defines the ibc-transfer genesis state -message GenesisState { - string port_id = 1; - repeated DenomTrace denom_traces = 2 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false]; - Params params = 3 [(gogoproto.nullable) = false]; - // total_escrowed contains the total amount of tokens escrowed - // by the transfer module - repeated cosmos.base.v1beta1.Coin total_escrowed = 4 - [(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins", (gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/transfer/v1/query.proto b/third_party/proto/ibc/transfer/v1/query.proto deleted file mode 100644 index 788296718..000000000 --- a/third_party/proto/ibc/transfer/v1/query.proto +++ /dev/null @@ -1,121 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v1; - -import "gogoproto/gogo.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; -import "ibc/applications/transfer/v1/transfer.proto"; -import "google/api/annotations.proto"; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -// Query provides defines the gRPC querier service. -service Query { - // DenomTraces queries all denomination traces. - rpc DenomTraces(QueryDenomTracesRequest) returns (QueryDenomTracesResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/denom_traces"; - } - - // DenomTrace queries a denomination trace information. - rpc DenomTrace(QueryDenomTraceRequest) returns (QueryDenomTraceResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/denom_traces/{hash=**}"; - } - - // Params queries all parameters of the ibc-transfer module. - rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/params"; - } - - // DenomHash queries a denomination hash information. - rpc DenomHash(QueryDenomHashRequest) returns (QueryDenomHashResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/denom_hashes/{trace=**}"; - } - - // EscrowAddress returns the escrow address for a particular port and channel id. - rpc EscrowAddress(QueryEscrowAddressRequest) returns (QueryEscrowAddressResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/channels/{channel_id}/ports/{port_id}/escrow_address"; - } - - // TotalEscrowForDenom returns the total amount of tokens in escrow based on the denom. - rpc TotalEscrowForDenom(QueryTotalEscrowForDenomRequest) returns (QueryTotalEscrowForDenomResponse) { - option (google.api.http).get = "/ibc/apps/transfer/v1/denoms/{denom=**}/total_escrow"; - } -} - -// QueryDenomTraceRequest is the request type for the Query/DenomTrace RPC -// method -message QueryDenomTraceRequest { - // hash (in hex format) or denom (full denom with ibc prefix) of the denomination trace information. - string hash = 1; -} - -// QueryDenomTraceResponse is the response type for the Query/DenomTrace RPC -// method. -message QueryDenomTraceResponse { - // denom_trace returns the requested denomination trace information. - DenomTrace denom_trace = 1; -} - -// QueryConnectionsRequest is the request type for the Query/DenomTraces RPC -// method -message QueryDenomTracesRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryConnectionsResponse is the response type for the Query/DenomTraces RPC -// method. -message QueryDenomTracesResponse { - // denom_traces returns all denominations trace information. - repeated DenomTrace denom_traces = 1 [(gogoproto.castrepeated) = "Traces", (gogoproto.nullable) = false]; - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryParamsRequest is the request type for the Query/Params RPC method. -message QueryParamsRequest {} - -// QueryParamsResponse is the response type for the Query/Params RPC method. -message QueryParamsResponse { - // params defines the parameters of the module. - Params params = 1; -} - -// QueryDenomHashRequest is the request type for the Query/DenomHash RPC -// method -message QueryDenomHashRequest { - // The denomination trace ([port_id]/[channel_id])+/[denom] - string trace = 1; -} - -// QueryDenomHashResponse is the response type for the Query/DenomHash RPC -// method. -message QueryDenomHashResponse { - // hash (in hex format) of the denomination trace information. - string hash = 1; -} - -// QueryEscrowAddressRequest is the request type for the EscrowAddress RPC method. -message QueryEscrowAddressRequest { - // unique port identifier - string port_id = 1; - // unique channel identifier - string channel_id = 2; -} - -// QueryEscrowAddressResponse is the response type of the EscrowAddress RPC method. -message QueryEscrowAddressResponse { - // the escrow account address - string escrow_address = 1; -} - -// QueryTotalEscrowForDenomRequest is the request type for TotalEscrowForDenom RPC method. -message QueryTotalEscrowForDenomRequest { - string denom = 1; -} - -// QueryTotalEscrowForDenomResponse is the response type for TotalEscrowForDenom RPC method. -message QueryTotalEscrowForDenomResponse { - cosmos.base.v1beta1.Coin amount = 1 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/transfer/v1/transfer.proto b/third_party/proto/ibc/transfer/v1/transfer.proto deleted file mode 100644 index 7f7723762..000000000 --- a/third_party/proto/ibc/transfer/v1/transfer.proto +++ /dev/null @@ -1,28 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -// DenomTrace contains the base denomination for ICS20 fungible tokens and the -// source tracing information path. -message DenomTrace { - // path defines the chain of port/channel identifiers used for tracing the - // source of the fungible token. - string path = 1; - // base denomination of the relayed fungible token. - string base_denom = 2; -} - -// Params defines the set of IBC transfer parameters. -// NOTE: To prevent a single token from being transferred, set the -// TransfersEnabled parameter to true and then set the bank module's SendEnabled -// parameter for the denomination to false. -message Params { - // send_enabled enables or disables all cross-chain token transfers from this - // chain. - bool send_enabled = 1; - // receive_enabled enables or disables all cross-chain token transfers to this - // chain. - bool receive_enabled = 2; -} diff --git a/third_party/proto/ibc/transfer/v1/tx.proto b/third_party/proto/ibc/transfer/v1/tx.proto deleted file mode 100644 index 42c70d3be..000000000 --- a/third_party/proto/ibc/transfer/v1/tx.proto +++ /dev/null @@ -1,79 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -import "amino/amino.proto"; -import "gogoproto/gogo.proto"; -import "cosmos/msg/v1/msg.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "ibc/core/client/v1/client.proto"; -import "ibc/applications/transfer/v1/transfer.proto"; - -// Msg defines the ibc/transfer Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // Transfer defines a rpc handler method for MsgTransfer. - rpc Transfer(MsgTransfer) returns (MsgTransferResponse); - - // UpdateParams defines a rpc handler for MsgUpdateParams. - rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); -} - -// MsgTransfer defines a msg to transfer fungible tokens (i.e Coins) between -// ICS20 enabled chains. See ICS Spec here: -// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures -message MsgTransfer { - option (amino.name) = "cosmos-sdk/MsgTransfer"; - option (cosmos.msg.v1.signer) = "sender"; - - option (gogoproto.goproto_getters) = false; - - // the port on which the packet will be sent - string source_port = 1; - // the channel by which the packet will be sent - string source_channel = 2; - // the tokens to be transferred - cosmos.base.v1beta1.Coin token = 3 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // the sender address - string sender = 4; - // the recipient address on the destination chain - string receiver = 5; - // Timeout height relative to the current block height. - // The timeout is disabled when set to 0. - ibc.core.client.v1.Height timeout_height = 6 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true]; - // Timeout timestamp in absolute nanoseconds since unix epoch. - // The timeout is disabled when set to 0. - uint64 timeout_timestamp = 7; - // optional memo - string memo = 8; -} - -// MsgTransferResponse defines the Msg/Transfer response type. -message MsgTransferResponse { - option (gogoproto.goproto_getters) = false; - - // sequence number of the transfer packet sent - uint64 sequence = 1; -} - -// MsgUpdateParams is the Msg/UpdateParams request type. -message MsgUpdateParams { - option (cosmos.msg.v1.signer) = "signer"; - - option (gogoproto.goproto_getters) = false; - - // signer address - string signer = 1; - - // params defines the transfer parameters to update. - // - // NOTE: All parameters must be supplied. - Params params = 2 [(gogoproto.nullable) = false]; -} - -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. -message MsgUpdateParamsResponse {} \ No newline at end of file diff --git a/third_party/proto/ibc/transfer/v2/packet.proto b/third_party/proto/ibc/transfer/v2/packet.proto deleted file mode 100644 index bff35bdd6..000000000 --- a/third_party/proto/ibc/transfer/v2/packet.proto +++ /dev/null @@ -1,21 +0,0 @@ -syntax = "proto3"; - -package ibc.applications.transfer.v2; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"; - -// FungibleTokenPacketData defines a struct for the packet payload -// See FungibleTokenPacketData spec: -// https://github.com/cosmos/ibc/tree/master/spec/app/ics-020-fungible-token-transfer#data-structures -message FungibleTokenPacketData { - // the token denomination to be transferred - string denom = 1; - // the token amount to be transferred - string amount = 2; - // the sender address - string sender = 3; - // the recipient address on the destination chain - string receiver = 4; - // optional memo - string memo = 5; -} diff --git a/third_party/proto/ibc/types/v1/genesis.proto b/third_party/proto/ibc/types/v1/genesis.proto deleted file mode 100644 index 4b34f6889..000000000 --- a/third_party/proto/ibc/types/v1/genesis.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto3"; - -package ibc.core.types.v1; - -option go_package = "github.com/cosmos/ibc-go/v8/modules/core/types"; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/genesis.proto"; -import "ibc/core/connection/v1/genesis.proto"; -import "ibc/core/channel/v1/genesis.proto"; - -// GenesisState defines the ibc module's genesis state. -message GenesisState { - // ICS002 - Clients genesis state - ibc.core.client.v1.GenesisState client_genesis = 1 [(gogoproto.nullable) = false]; - // ICS003 - Connections genesis state - ibc.core.connection.v1.GenesisState connection_genesis = 2 [(gogoproto.nullable) = false]; - // ICS004 - Channel genesis state - ibc.core.channel.v1.GenesisState channel_genesis = 3 [(gogoproto.nullable) = false]; -} diff --git a/third_party/proto/ibc/wasm/v1/genesis.proto b/third_party/proto/ibc/wasm/v1/genesis.proto deleted file mode 100644 index 637ba1677..000000000 --- a/third_party/proto/ibc/wasm/v1/genesis.proto +++ /dev/null @@ -1,20 +0,0 @@ - -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// GenesisState defines 08-wasm's keeper genesis state -message GenesisState { - // uploaded light client wasm contracts - repeated Contract contracts = 1 [(gogoproto.nullable) = false]; -} - -// Contract stores contract code -message Contract { - option (gogoproto.goproto_getters) = false; - // contract byte code - bytes code_bytes = 1; -} \ No newline at end of file diff --git a/third_party/proto/ibc/wasm/v1/query.proto b/third_party/proto/ibc/wasm/v1/query.proto deleted file mode 100644 index bbbed29dd..000000000 --- a/third_party/proto/ibc/wasm/v1/query.proto +++ /dev/null @@ -1,46 +0,0 @@ -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// Query service for wasm module -service Query { - // Get all Wasm checksums - rpc Checksums(QueryChecksumsRequest) returns (QueryChecksumsResponse) { - option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums"; - } - - // Get Wasm code for given checksum - rpc Code(QueryCodeRequest) returns (QueryCodeResponse) { - option (google.api.http).get = "/ibc/lightclients/wasm/v1/checksums/{checksum}/code"; - } -} - -// QueryChecksumsRequest is the request type for the Query/Checksums RPC method. -message QueryChecksumsRequest { - // pagination defines an optional pagination for the request. - cosmos.base.query.v1beta1.PageRequest pagination = 1; -} - -// QueryChecksumsResponse is the response type for the Query/Checksums RPC method. -message QueryChecksumsResponse { - // checksums is a list of the hex encoded checksums of all wasm codes stored. - repeated string checksums = 1; - - // pagination defines the pagination in the response. - cosmos.base.query.v1beta1.PageResponse pagination = 2; -} - -// QueryCodeRequest is the request type for the Query/Code RPC method. -message QueryCodeRequest { - // checksum is a hex encoded string of the code stored. - string checksum = 1; -} - -// QueryCodeResponse is the response type for the Query/Code RPC method. -message QueryCodeResponse { - bytes data = 1; -} diff --git a/third_party/proto/ibc/wasm/v1/tx.proto b/third_party/proto/ibc/wasm/v1/tx.proto deleted file mode 100644 index d2fc46591..000000000 --- a/third_party/proto/ibc/wasm/v1/tx.proto +++ /dev/null @@ -1,66 +0,0 @@ -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -import "cosmos/msg/v1/msg.proto"; - -// Msg defines the ibc/08-wasm Msg service. -service Msg { - option (cosmos.msg.v1.service) = true; - - // StoreCode defines a rpc handler method for MsgStoreCode. - rpc StoreCode(MsgStoreCode) returns (MsgStoreCodeResponse); - - // RemoveChecksum defines a rpc handler method for MsgRemoveChecksum. - rpc RemoveChecksum(MsgRemoveChecksum) returns (MsgRemoveChecksumResponse); - - // MigrateContract defines a rpc handler method for MsgMigrateContract. - rpc MigrateContract(MsgMigrateContract) returns (MsgMigrateContractResponse); -} - -// MsgStoreCode defines the request type for the StoreCode rpc. -message MsgStoreCode { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // wasm byte code of light client contract. It can be raw or gzip compressed - bytes wasm_byte_code = 2; -} - -// MsgStoreCodeResponse defines the response type for the StoreCode rpc -message MsgStoreCodeResponse { - // checksum is the sha256 hash of the stored code - bytes checksum = 1; -} - -// MsgRemoveChecksum defines the request type for the MsgRemoveChecksum rpc. -message MsgRemoveChecksum { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // checksum is the sha256 hash to be removed from the store - bytes checksum = 2; -} - -// MsgStoreChecksumResponse defines the response type for the StoreCode rpc -message MsgRemoveChecksumResponse {} - -// MsgMigrateContract defines the request type for the MigrateContract rpc. -message MsgMigrateContract { - option (cosmos.msg.v1.signer) = "signer"; - - // signer address - string signer = 1; - // the client id of the contract - string client_id = 2; - // checksum is the sha256 hash of the new wasm byte code for the contract - bytes checksum = 3; - // the json encoded message to be passed to the contract on migration - bytes msg = 4; -} - -// MsgMigrateContractResponse defines the response type for the MigrateContract rpc -message MsgMigrateContractResponse {} diff --git a/third_party/proto/ibc/wasm/v1/wasm.proto b/third_party/proto/ibc/wasm/v1/wasm.proto deleted file mode 100644 index b6a45e3d8..000000000 --- a/third_party/proto/ibc/wasm/v1/wasm.proto +++ /dev/null @@ -1,43 +0,0 @@ - -syntax = "proto3"; -package ibc.lightclients.wasm.v1; - -import "gogoproto/gogo.proto"; -import "ibc/core/client/v1/client.proto"; - -option go_package = "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types"; - -// Wasm light client's Client state -message ClientState { - option (gogoproto.goproto_getters) = false; - // bytes encoding the client state of the underlying light client - // implemented as a Wasm contract. - bytes data = 1; - bytes checksum = 2; - ibc.core.client.v1.Height latest_height = 3 [(gogoproto.nullable) = false]; -} - -// Wasm light client's ConsensusState -message ConsensusState { - option (gogoproto.goproto_getters) = false; - // bytes encoding the consensus state of the underlying light client - // implemented as a Wasm contract. - bytes data = 1; -} - -// Wasm light client message (either header(s) or misbehaviour) -message ClientMessage { - option (gogoproto.goproto_getters) = false; - - bytes data = 1; -} - -// Checksums defines a list of all checksums that are stored -// -// Deprecated: This message is deprecated in favor of storing the checksums -// using a Collections.KeySet. -message Checksums { - option deprecated = true; - - repeated bytes checksums = 1; -} \ No newline at end of file From 5087037130b68ef58b39026d8cedffabfb07f35d Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Fri, 30 Aug 2024 16:32:38 +0300 Subject: [PATCH 29/60] replace cronkeeper for cronmsgserver in bindings --- proto/neutron/cron/genesis.proto | 2 +- proto/neutron/cron/params.proto | 2 +- proto/neutron/cron/query.proto | 2 +- proto/neutron/cron/schedule.proto | 16 ++++++------- proto/neutron/cron/tx.proto | 27 ++++++++++----------- proto/neutron/cron/v1/schedule.proto | 12 +++++----- wasmbinding/message_plugin.go | 32 ++++++++++++++++++++----- wasmbinding/test/custom_message_test.go | 5 +++- x/cron/keeper/keeper.go | 4 ---- x/cron/keeper/msg_server.go | 16 ++++++------- x/cron/keeper/msg_server_test.go | 16 +++++++++++++ x/cron/migrations/v2/store_test.go | 7 ++++++ x/cron/types/genesis.pb.go | 2 +- x/cron/types/params.pb.go | 2 +- x/cron/types/schedule.pb.go | 16 ++++++------- x/cron/types/tx.go | 4 ++++ x/cron/types/tx.pb.go | 25 +++++++++---------- x/cron/types/v1/schedule.pb.go | 12 +++++----- 18 files changed, 121 insertions(+), 81 deletions(-) diff --git a/proto/neutron/cron/genesis.proto b/proto/neutron/cron/genesis.proto index 61b27069a..eba407f97 100644 --- a/proto/neutron/cron/genesis.proto +++ b/proto/neutron/cron/genesis.proto @@ -8,7 +8,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// GenesisState defines the cron module's genesis state. +// Defines the cron module's genesis state. message GenesisState { repeated Schedule scheduleList = 2 [(gogoproto.nullable) = false]; Params params = 1 [(gogoproto.nullable) = false]; diff --git a/proto/neutron/cron/params.proto b/proto/neutron/cron/params.proto index 9bea16a5b..c3c5cf452 100644 --- a/proto/neutron/cron/params.proto +++ b/proto/neutron/cron/params.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Params defines the parameters for the module. +// Defines the parameters for the module. message Params { option (gogoproto.goproto_stringer) = false; // Security address that can remove schedules diff --git a/proto/neutron/cron/query.proto b/proto/neutron/cron/query.proto index 906ccfb1d..60ee505e0 100644 --- a/proto/neutron/cron/query.proto +++ b/proto/neutron/cron/query.proto @@ -10,7 +10,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Query defines the gRPC querier service. +// Defines the gRPC querier service. service Query { // Queries the parameters of the module. rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index a93a5fff6..b6147aed4 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// ExecutionStage defines when messages will be executed in the block +// Defines when messages will be executed in the block enum ExecutionStage { // Execution at the end of the block EXECUTION_STAGE_END_BLOCKER = 0; @@ -13,7 +13,7 @@ enum ExecutionStage { EXECUTION_STAGE_BEGIN_BLOCKER = 1; } -// Schedule defines the schedule for execution +// Defines the schedule for execution message Schedule { // Name of schedule string name = 1; @@ -23,20 +23,20 @@ message Schedule { repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; - // Execution stage when messages will be executed + // Stage when messages will be executed ExecutionStage execution_stage = 5; } -// MsgExecuteContract defines the contract and the message to pass +// Defines the contract and the message to pass message MsgExecuteContract { - // Contract is the address of the smart contract + // The address of the smart contract string contract = 1; - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract string msg = 2; } -// ScheduleCount defines the number of current schedules +// Defines the number of current schedules message ScheduleCount { - // Count is the number of current schedules + // The number of current schedules int32 count = 1; } diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index d01cf89b4..fcb9b383a 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -12,7 +12,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Msg defines the Msg service. +// Defines the Msg service. service Msg { option (cosmos.msg.v1.service) = true; @@ -25,12 +25,12 @@ service Msg { // this line is used by starport scaffolding # proto/tx/rpc } -// MsgAddSchedule is the MsgAddSchedule request type. +// The MsgAddSchedule request type. message MsgAddSchedule { option (amino.name) = "cron/MsgAddSchedule"; option (cosmos.msg.v1.signer) = "authority"; - // Authority is the address of the governance account. + // The address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // Name of the schedule string name = 2; @@ -38,42 +38,40 @@ message MsgAddSchedule { uint64 period = 3; // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - // Execution stage when messages will be executed + // Stage when messages will be executed ExecutionStage execution_stage = 5; } -// MsgAddScheduleResponse defines the response structure for executing a -// MsgAddSchedule message. +// Defines the response structure for executing a MsgAddSchedule message. message MsgAddScheduleResponse {} -// MsgRemoveSchedule is the MsgRemoveSchedule request type. +// The MsgRemoveSchedule request type. message MsgRemoveSchedule { option (amino.name) = "cron/MsgRemoveSchedule"; option (cosmos.msg.v1.signer) = "authority"; - // Authority is the address of the governance account. + // The address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // Name of the schedule string name = 2; } -// MsgRemoveScheduleResponse defines the response structure for executing a -// MsgRemoveSchedule message. +// Defines the response structure for executing a MsgRemoveSchedule message. message MsgRemoveScheduleResponse {} // this line is used by starport scaffolding # proto/tx/message -// MsgUpdateParams is the MsgUpdateParams request type. +// The MsgUpdateParams request type. // // Since: 0.47 message MsgUpdateParams { option (amino.name) = "cron/MsgUpdateParams"; option (cosmos.msg.v1.signer) = "authority"; - // Authority is the address of the governance account. + // The address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // params defines the x/cron parameters to update. + // Defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params params = 2 [ @@ -82,8 +80,7 @@ message MsgUpdateParams { ]; } -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. +// Defines the response structure for executing a MsgUpdateParams message. // // Since: 0.47 message MsgUpdateParamsResponse {} diff --git a/proto/neutron/cron/v1/schedule.proto b/proto/neutron/cron/v1/schedule.proto index ec7494745..8995431fe 100644 --- a/proto/neutron/cron/v1/schedule.proto +++ b/proto/neutron/cron/v1/schedule.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types/v1"; -// Schedule defines the schedule for execution +// Defines the schedule for execution message Schedule { // Name of schedule string name = 1; @@ -17,16 +17,16 @@ message Schedule { uint64 last_execute_height = 4; } -// MsgExecuteContract defines the contract and the message to pass +// Defines the contract and the message to pass message MsgExecuteContract { - // Contract is the address of the smart contract + // The address of the smart contract string contract = 1; - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract string msg = 2; } -// ScheduleCount defines the number of current schedules +// Defines the number of current schedules message ScheduleCount { - // Count is the number of current schedules + // The number of current schedules int32 count = 1; } diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 3e835e206..b8bc6cf6d 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -71,7 +71,8 @@ func CustomMessageDecorator( Adminserver: adminmodulekeeper.NewMsgServerImpl(*adminKeeper), Bank: bankKeeper, TokenFactory: tokenFactoryKeeper, - CronKeeper: cronKeeper, + Cronmsgserver: cronkeeper.NewMsgServerImpl(*cronKeeper), + Cronqueryserver: cronKeeper, AdminKeeper: adminKeeper, ContractmanagerKeeper: contractmanagerKeeper, DexMsgServer: dexkeeper.NewMsgServerImpl(*dexKeeper), @@ -88,7 +89,8 @@ type CustomMessenger struct { Adminserver admintypes.MsgServer Bank *bankkeeper.BaseKeeper TokenFactory *tokenfactorykeeper.Keeper - CronKeeper *cronkeeper.Keeper + Cronmsgserver crontypes.MsgServer + Cronqueryserver crontypes.QueryServer AdminKeeper *adminmodulekeeper.Keeper ContractmanagerKeeper *contractmanagerkeeper.Keeper DexMsgServer dextypes.MsgServer @@ -977,6 +979,8 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin can add schedule") } + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + msgs := make([]crontypes.MsgExecuteContract, 0, len(addSchedule.Msgs)) for _, msg := range addSchedule.Msgs { msgs = append(msgs, crontypes.MsgExecuteContract{ @@ -985,7 +989,13 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs, crontypes.ExecutionStage(crontypes.ExecutionStage_value[addSchedule.ExecutionStage])) + _, err := m.Cronmsgserver.AddSchedule(ctx, &crontypes.MsgAddSchedule{ + Authority: authority.String(), + Name: addSchedule.Name, + Period: addSchedule.Period, + Msgs: msgs, + ExecutionStage: crontypes.ExecutionStage(crontypes.ExecutionStage_value[addSchedule.ExecutionStage]), + }) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), @@ -1004,12 +1014,22 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAddress, removeSchedule *bindings.RemoveSchedule) ([]sdk.Event, [][]byte, [][]*types.Any, error) { - params := m.CronKeeper.GetParams(ctx) - if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.SecurityAddress { + params, err := m.Cronqueryserver.Params(ctx, &crontypes.QueryParamsRequest{}) + if err != nil { + ctx.Logger().Error("failed to get params", "error", err) + return nil, nil, nil, err + } + + if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.Params.SecurityAddress { return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin or security dao can remove schedule") } - m.CronKeeper.RemoveSchedule(ctx, removeSchedule.Name) + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + + m.Cronmsgserver.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ + Authority: authority.String(), + Name: removeSchedule.Name, + }) ctx.Logger().Debug("schedule removed", "from_address", contractAddr.String(), diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 760417c16..e44d5806d 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -21,6 +21,8 @@ import ( adminkeeper "github.com/cosmos/admin-module/v2/x/adminmodule/keeper" + cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" + "github.com/neutron-org/neutron/v4/app/params" "github.com/CosmWasm/wasmd/x/wasm/keeper" @@ -65,7 +67,8 @@ func (suite *CustomMessengerTestSuite) SetupTest() { suite.messenger.Adminserver = adminkeeper.NewMsgServerImpl(suite.neutron.AdminmoduleKeeper) suite.messenger.Bank = &suite.neutron.BankKeeper suite.messenger.TokenFactory = suite.neutron.TokenFactoryKeeper - suite.messenger.CronKeeper = &suite.neutron.CronKeeper + suite.messenger.Cronmsgserver = cronkeeper.NewMsgServerImpl(suite.neutron.CronKeeper) + suite.messenger.Cronqueryserver = suite.neutron.CronKeeper suite.messenger.AdminKeeper = &suite.neutron.AdminmoduleKeeper suite.messenger.ContractmanagerKeeper = &suite.neutron.ContractManagerKeeper suite.contractOwner = keeper.RandomAccountAddress(suite.T()) diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 013cf9ede..070f18b2d 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -97,10 +97,6 @@ func (k *Keeper) AddSchedule( ExecutionStage: executionStage, } - if _, ok := types.ExecutionStage_name[int32(executionStage)]; !ok { - schedule.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - } - k.storeSchedule(ctx, schedule) k.changeTotalCount(ctx, 1) diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index ec69a49d2..c42a0d1c4 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -11,13 +11,13 @@ import ( ) type msgServer struct { - Keeper + keeper Keeper } // NewMsgServerImpl returns an implementation of the MsgServer interface // for the provided Keeper. func NewMsgServerImpl(keeper Keeper) types.MsgServer { - return &msgServer{Keeper: keeper} + return &msgServer{keeper: keeper} } var _ types.MsgServer = msgServer{} @@ -28,13 +28,13 @@ func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) return nil, errors.Wrap(err, "failed to validate MsgAddSchedule") } - authority := k.GetAuthority() + authority := k.keeper.GetAuthority() if authority != req.Authority { return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.Keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { + if err := k.keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { return nil, errors.Wrap(err, "failed to add schedule") } @@ -47,13 +47,13 @@ func (k msgServer) RemoveSchedule(goCtx context.Context, req *types.MsgRemoveSch return nil, errors.Wrap(err, "failed to validate MsgRemoveSchedule") } - authority := k.GetAuthority() + authority := k.keeper.GetAuthority() if authority != req.Authority { return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - k.Keeper.RemoveSchedule(ctx, req.Name) + k.keeper.RemoveSchedule(ctx, req.Name) return &types.MsgRemoveScheduleResponse{}, nil } @@ -64,13 +64,13 @@ func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParam return nil, errors.Wrap(err, "failed to validate MsgUpdateParams") } - authority := k.GetAuthority() + authority := k.keeper.GetAuthority() if authority != req.Authority { return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.SetParams(ctx, req.Params); err != nil { + if err := k.keeper.SetParams(ctx, req.Params); err != nil { return nil, err } diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index 5f4d0b308..bbf8652e6 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -95,6 +95,22 @@ func TestMsgAddScheduleValidate(t *testing.T) { }, "msgs should not be empty", }, + { + "invalid execution stage", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: 7, + }, + "execution stage is invalid", + }, } for _, tt := range tests { diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go index fdc3bf3a8..6b6f46355 100644 --- a/x/cron/migrations/v2/store_test.go +++ b/x/cron/migrations/v2/store_test.go @@ -49,5 +49,12 @@ func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { // Check Schedule has correct ExecutionStage newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) + suite.Equal(newSchedule.Name, schedule.Name) + suite.Equal(newSchedule.Period, schedule.Period) + for i, msg := range newSchedule.Msgs { + suite.Equal(msg.Contract, schedule.Msgs[i].Contract) + suite.Equal(msg.Msg, schedule.Msgs[i].Msg) + } + suite.Equal(newSchedule.LastExecuteHeight, schedule.LastExecuteHeight) suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) } diff --git a/x/cron/types/genesis.pb.go b/x/cron/types/genesis.pb.go index 2d3546994..274598ad7 100644 --- a/x/cron/types/genesis.pb.go +++ b/x/cron/types/genesis.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the cron module's genesis state. +// Defines the cron module's genesis state. type GenesisState struct { ScheduleList []Schedule `protobuf:"bytes,2,rep,name=scheduleList,proto3" json:"scheduleList"` Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` diff --git a/x/cron/types/params.pb.go b/x/cron/types/params.pb.go index c71904ce8..e927ec42a 100644 --- a/x/cron/types/params.pb.go +++ b/x/cron/types/params.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Params defines the parameters for the module. +// Defines the parameters for the module. type Params struct { // Security address that can remove schedules SecurityAddress string `protobuf:"bytes,1,opt,name=security_address,json=securityAddress,proto3" json:"security_address,omitempty"` diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index d595c3457..845a1059a 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// ExecutionStage defines when messages will be executed in the block +// Defines when messages will be executed in the block type ExecutionStage int32 const ( @@ -51,7 +51,7 @@ func (ExecutionStage) EnumDescriptor() ([]byte, []int) { return fileDescriptor_49ace1b59de613ef, []int{0} } -// Schedule defines the schedule for execution +// Defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -61,7 +61,7 @@ type Schedule struct { Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` - // Execution stage when messages will be executed + // Stage when messages will be executed ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } @@ -133,11 +133,11 @@ func (m *Schedule) GetExecutionStage() ExecutionStage { return ExecutionStage_EXECUTION_STAGE_END_BLOCKER } -// MsgExecuteContract defines the contract and the message to pass +// Defines the contract and the message to pass type MsgExecuteContract struct { - // Contract is the address of the smart contract + // The address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` } @@ -188,9 +188,9 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } -// ScheduleCount defines the number of current schedules +// Defines the number of current schedules type ScheduleCount struct { - // Count is the number of current schedules + // The number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` } diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index 1bca78a71..27b4ceec4 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -45,6 +45,10 @@ func (msg *MsgAddSchedule) Validate() error { return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") } + if _, ok := ExecutionStage_name[int32(msg.ExecutionStage)]; !ok { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "execution stage is invalid") + } + return nil } diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 39b7e92b3..141735a4e 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -31,9 +31,9 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgAddSchedule is the MsgAddSchedule request type. +// The MsgAddSchedule request type. type MsgAddSchedule struct { - // Authority is the address of the governance account. + // The address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` // Name of the schedule Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` @@ -41,7 +41,7 @@ type MsgAddSchedule struct { Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` // Msgs that will be executed every certain number of blocks, specified in the `period` field Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` - // Execution stage when messages will be executed + // Stage when messages will be executed ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } @@ -113,8 +113,7 @@ func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { return ExecutionStage_EXECUTION_STAGE_END_BLOCKER } -// MsgAddScheduleResponse defines the response structure for executing a -// MsgAddSchedule message. +// Defines the response structure for executing a MsgAddSchedule message. type MsgAddScheduleResponse struct { } @@ -151,9 +150,9 @@ func (m *MsgAddScheduleResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgAddScheduleResponse proto.InternalMessageInfo -// MsgRemoveSchedule is the MsgRemoveSchedule request type. +// The MsgRemoveSchedule request type. type MsgRemoveSchedule struct { - // Authority is the address of the governance account. + // The address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` // Name of the schedule Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` @@ -206,8 +205,7 @@ func (m *MsgRemoveSchedule) GetName() string { return "" } -// MsgRemoveScheduleResponse defines the response structure for executing a -// MsgRemoveSchedule message. +// Defines the response structure for executing a MsgRemoveSchedule message. type MsgRemoveScheduleResponse struct { } @@ -244,13 +242,13 @@ func (m *MsgRemoveScheduleResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRemoveScheduleResponse proto.InternalMessageInfo -// MsgUpdateParams is the MsgUpdateParams request type. +// The MsgUpdateParams request type. // // Since: 0.47 type MsgUpdateParams struct { - // Authority is the address of the governance account. + // The address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // params defines the x/cron parameters to update. + // Defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` @@ -303,8 +301,7 @@ func (m *MsgUpdateParams) GetParams() Params { return Params{} } -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. +// Defines the response structure for executing a MsgUpdateParams message. // // Since: 0.47 type MsgUpdateParamsResponse struct { diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go index 814f91cbb..3a35f34e6 100644 --- a/x/cron/types/v1/schedule.pb.go +++ b/x/cron/types/v1/schedule.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Schedule defines the schedule for execution +// Defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -96,11 +96,11 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } -// MsgExecuteContract defines the contract and the message to pass +// Defines the contract and the message to pass type MsgExecuteContract struct { - // Contract is the address of the smart contract + // The address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` } @@ -151,9 +151,9 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } -// ScheduleCount defines the number of current schedules +// Defines the number of current schedules type ScheduleCount struct { - // Count is the number of current schedules + // The number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` } From 04622628202a6fe31cfc2b9b84b73e7dbc29b1b3 Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Fri, 30 Aug 2024 16:49:02 +0300 Subject: [PATCH 30/60] add err check and fix test --- wasmbinding/message_plugin.go | 23 +++++++++++++---------- x/cron/keeper/keeper_test.go | 11 +---------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index b8bc6cf6d..a56414b2e 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -979,8 +979,6 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin can add schedule") } - authority := authtypes.NewModuleAddress(admintypes.ModuleName) - msgs := make([]crontypes.MsgExecuteContract, 0, len(addSchedule.Msgs)) for _, msg := range addSchedule.Msgs { msgs = append(msgs, crontypes.MsgExecuteContract{ @@ -990,7 +988,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } _, err := m.Cronmsgserver.AddSchedule(ctx, &crontypes.MsgAddSchedule{ - Authority: authority.String(), + Authority: contractAddr.String(), Name: addSchedule.Name, Period: addSchedule.Period, Msgs: msgs, @@ -1001,7 +999,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre "from_address", contractAddr.String(), "error", err, ) - return nil, nil, nil, errors.Wrap(err, "marshal json failed") + return nil, nil, nil, errors.Wrap(err, "failed to addSchedule") } ctx.Logger().Debug("schedule added", @@ -1016,20 +1014,25 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAddress, removeSchedule *bindings.RemoveSchedule) ([]sdk.Event, [][]byte, [][]*types.Any, error) { params, err := m.Cronqueryserver.Params(ctx, &crontypes.QueryParamsRequest{}) if err != nil { - ctx.Logger().Error("failed to get params", "error", err) - return nil, nil, nil, err + ctx.Logger().Error("failed to removeSchedule", "error", err) + return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") } if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.Params.SecurityAddress { return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin or security dao can remove schedule") } - authority := authtypes.NewModuleAddress(admintypes.ModuleName) - - m.Cronmsgserver.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ - Authority: authority.String(), + _, err = m.Cronmsgserver.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ + Authority: contractAddr.String(), Name: removeSchedule.Name, }) + if err != nil { + ctx.Logger().Error("failed to removeSchedule", + "from_address", contractAddr.String(), + "error", err, + ) + return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") + } ctx.Logger().Debug("schedule removed", "from_address", contractAddr.String(), diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index f680bebe3..d58553c56 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -238,14 +238,6 @@ func TestAddSchedule(t *testing.T) { }, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.NoError(t, err) - err = k.AddSchedule(ctx, "d", 7, []types.MsgExecuteContract{ - { - Contract: "c", - Msg: "m", - }, - }, 7) - require.NoError(t, err) - // second time with same name returns error err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.Error(t, err) @@ -260,10 +252,9 @@ func TestAddSchedule(t *testing.T) { require.Equal(t, scheduleA.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) schedules := k.GetAllSchedules(ctx) - require.Len(t, schedules, 3) + require.Len(t, schedules, 2) require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) - require.Equal(t, schedules[2].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) // remove schedule works k.RemoveSchedule(ctx, "a") From 1fc6f36afc8c28deec62d796a21f34d0ccb5649b Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Fri, 30 Aug 2024 17:55:52 +0300 Subject: [PATCH 31/60] fix test --- wasmbinding/message_plugin.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index a56414b2e..b7dd3ba8e 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -979,6 +979,8 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin can add schedule") } + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + msgs := make([]crontypes.MsgExecuteContract, 0, len(addSchedule.Msgs)) for _, msg := range addSchedule.Msgs { msgs = append(msgs, crontypes.MsgExecuteContract{ @@ -988,7 +990,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } _, err := m.Cronmsgserver.AddSchedule(ctx, &crontypes.MsgAddSchedule{ - Authority: contractAddr.String(), + Authority: authority.String(), Name: addSchedule.Name, Period: addSchedule.Period, Msgs: msgs, @@ -1022,8 +1024,10 @@ func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAd return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin or security dao can remove schedule") } + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + _, err = m.Cronmsgserver.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ - Authority: contractAddr.String(), + Authority: authority.String(), Name: removeSchedule.Name, }) if err != nil { From 45eae55635cadf8ba81226aafc0d0c42b113153f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 08:16:43 +0000 Subject: [PATCH 32/60] Bump github.com/cosmos/ibc-go/v8 from 8.4.0 to 8.5.0 Bumps [github.com/cosmos/ibc-go/v8](https://github.com/cosmos/ibc-go) from 8.4.0 to 8.5.0. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/v8.5.0/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v8.4.0...v8.5.0) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v8 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 20 ++++++++++---------- go.sum | 40 ++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index f6e7b7368..837db6d47 100644 --- a/go.mod +++ b/go.mod @@ -20,11 +20,11 @@ require ( github.com/cosmos/cosmos-db v1.0.2 github.com/cosmos/cosmos-proto v1.0.0-beta.5 github.com/cosmos/cosmos-sdk v0.50.9 - github.com/cosmos/gogoproto v1.6.0 + github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v8 v8.4.0 - github.com/cosmos/ics23/go v0.10.0 + github.com/cosmos/ibc-go/v8 v8.5.0 + github.com/cosmos/ics23/go v0.11.0 github.com/cosmos/interchain-security/v5 v5.1.1 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 @@ -53,11 +53,11 @@ require ( ) require ( - cloud.google.com/go v0.114.0 // indirect - cloud.google.com/go/auth v0.5.1 // indirect + cloud.google.com/go v0.115.0 // indirect + cloud.google.com/go/auth v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect - cloud.google.com/go/iam v1.1.8 // indirect + cloud.google.com/go/iam v1.1.9 // indirect cloud.google.com/go/storage v1.41.0 // indirect cosmossdk.io/api v0.7.5 // indirect cosmossdk.io/collections v0.4.0 // indirect @@ -124,7 +124,7 @@ require ( github.com/google/s2a-go v0.1.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.4 // indirect + github.com/googleapis/gax-go/v2 v2.12.5 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect @@ -201,12 +201,12 @@ require ( golang.org/x/net v0.28.0 // indirect golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.24.0 // indirect golang.org/x/term v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/api v0.180.0 // indirect - google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/api v0.186.0 // indirect + google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 389be92c2..4e52f6f9f 100644 --- a/go.sum +++ b/go.sum @@ -30,8 +30,8 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.102.1/go.mod h1:XZ77E9qnTEnrgEOvr4xzfdX5TRo7fB4T2F4O6+34hIU= cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRYtA= -cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY= -cloud.google.com/go v0.114.0/go.mod h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= cloud.google.com/go/aiplatform v1.22.0/go.mod h1:ig5Nct50bZlzV6NvKaTwmplLLddFx0YReh9WfTO5jKw= cloud.google.com/go/aiplatform v1.24.0/go.mod h1:67UUvRBKG6GTayHKV8DBv2RtR1t93YRu5B1P3x99mYY= cloud.google.com/go/analytics v0.11.0/go.mod h1:DjEWCu41bVbYcKyvlws9Er60YE4a//bK6mnhWvQeFNI= @@ -46,8 +46,8 @@ cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjby cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/auth v0.5.1 h1:0QNO7VThG54LUzKiQxv8C6x1YX7lUrzlAa1nVLF8CIw= -cloud.google.com/go/auth v0.5.1/go.mod h1:vbZT8GjzDf3AVqCcQmqeeM32U9HBFc32vVVAbwDsa6s= +cloud.google.com/go/auth v0.6.0 h1:5x+d6b5zdezZ7gmLWD1m/xNjnaQ2YDhmIz/HH3doy1g= +cloud.google.com/go/auth v0.6.0/go.mod h1:b4acV+jLQDyjwm4OXHYjNvRi4jvGBzHWJRtJcy+2P4g= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -111,8 +111,8 @@ cloud.google.com/go/gkehub v0.10.0/go.mod h1:UIPwxI0DsrpsVoWpLB0stwKCP+WFVG9+y97 cloud.google.com/go/grafeas v0.2.0/go.mod h1:KhxgtF2hb0P191HlY5besjYm6MqTSTj3LSI+M+ByZHc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= -cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= -cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= +cloud.google.com/go/iam v1.1.9 h1:oSkYLVtVme29uGYrOcKcvJRht7cHJpYD09GM9JaR0TE= +cloud.google.com/go/iam v1.1.9/go.mod h1:Nt1eDWNYH9nGQg3d/mY7U1hvfGmsaG9o/kLGoLoLXjQ= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -367,18 +367,18 @@ github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4x github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= -github.com/cosmos/gogoproto v1.6.0 h1:Xm0F/96O5Ox4g6xGgjA41rWaaPjYtOdTi59uBcV2qEE= -github.com/cosmos/gogoproto v1.6.0/go.mod h1:Y+g956rcUf2vr4uwtCcK/1Xx9BWVluCtcI9vsh0GHmk= +github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= +github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.2.0 h1:kVxTmjTh4k0Dh1VNL046v6BXqKziqMDzxo93oh3kOfM= github.com/cosmos/iavl v1.2.0/go.mod h1:HidWWLVAtODJqFD6Hbne2Y0q3SdxByJepHUOeoH4LiI= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 h1:dyLNlDElY6+5zW/BT/dO/3Ad9FpQblfh+9dQpYQodbA= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2/go.mod h1:82hPO/tRawbuFad2gPwChvpZ0JEIoNi91LwVneAYCeM= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v8 v8.4.0 h1:K2PfX0AZ+1XKZytHGEMuSjQXG/MZshPb83RSTQt2+cE= -github.com/cosmos/ibc-go/v8 v8.4.0/go.mod h1:zh6x1osR0hNvEcFrC/lhGD08sMfQmr9wHVvZ/mRWMCs= -github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= -github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= +github.com/cosmos/ibc-go/v8 v8.5.0 h1:OjaSXz480JT8ZuMrASxGgS7XzloZ2NuuJPwZB/fKDgE= +github.com/cosmos/ibc-go/v8 v8.5.0/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= +github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= +github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/interchain-security/v5 v5.0.0-20240802125602-fa1e09444aae h1:/EWV9qryltapge0v4ctvl2jV3Nne5nsbd+GYblj/jWA= github.com/cosmos/interchain-security/v5 v5.0.0-20240802125602-fa1e09444aae/go.mod h1:P3TM8JmE9Q20Jfch3jnFcQ4IXJp5twueRnUudi6XEGI= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= @@ -633,8 +633,8 @@ github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99 github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo= github.com/googleapis/gax-go/v2 v2.6.0/go.mod h1:1mjbznJAPHFpesgE5ucqfYEscaz5kMdcIDwU/6+DDoY= -github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg= -github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI= +github.com/googleapis/gax-go/v2 v2.12.5 h1:8gw9KZK8TiVKB6q3zHY3SBzLnrGp6HQjyfYBYGmXdxA= +github.com/googleapis/gax-go/v2 v2.12.5/go.mod h1:BUDKcWo+RaKq5SC9vVYL0wLADa3VcfswbOMMRmB9H3E= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -1363,8 +1363,8 @@ golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1508,8 +1508,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.180.0 h1:M2D87Yo0rGBPWpo1orwfCLehUUL6E7/TYe5gvMQWDh4= -google.golang.org/api v0.180.0/go.mod h1:51AiyoEg1MJPSZ9zvklA8VnRILPXxn1iVen9v25XHAE= +google.golang.org/api v0.186.0 h1:n2OPp+PPXX0Axh4GuSsL5QL8xQCTb2oDwyzPnQvqUug= +google.golang.org/api v0.186.0/go.mod h1:hvRbBmgoje49RV3xqVXrmP6w93n6ehGgIVPYrGtBFFc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1625,8 +1625,8 @@ google.golang.org/genproto v0.0.0-20221010155953-15ba04fc1c0e/go.mod h1:3526vdqw google.golang.org/genproto v0.0.0-20221014173430-6e2ab493f96b/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz9N9Jx0QA82PqRVauvCz1SGSz739p0f183jM= google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= -google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094 h1:6whtk83KtD3FkGrVb2hFXuQ+ZMbCNdakARIn/aHMmG8= +google.golang.org/genproto v0.0.0-20240701130421-f6361c86f094/go.mod h1:Zs4wYw8z1zr6RNF4cwYb31mvN/EGaKAdQjNCF3DW6K4= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= From 403292ad198dd528fab93e2e0673ba261da99576 Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Mon, 2 Sep 2024 18:54:51 +0300 Subject: [PATCH 33/60] make edits --- wasmbinding/message_plugin.go | 20 +++++++++++--------- wasmbinding/test/custom_message_test.go | 4 ++-- x/cron/keeper/msg_server_test.go | 2 +- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 8a93dffbe..0f3157ba9 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -71,8 +71,8 @@ func CustomMessageDecorator( Adminserver: adminmodulekeeper.NewMsgServerImpl(*adminKeeper), Bank: bankKeeper, TokenFactory: tokenFactoryKeeper, - Cronmsgserver: cronkeeper.NewMsgServerImpl(*cronKeeper), - Cronqueryserver: cronKeeper, + CronMsgServer: cronkeeper.NewMsgServerImpl(*cronKeeper), + CronQueryServer: cronKeeper, AdminKeeper: adminKeeper, ContractmanagerKeeper: contractmanagerKeeper, DexMsgServer: dexkeeper.NewMsgServerImpl(*dexKeeper), @@ -89,8 +89,8 @@ type CustomMessenger struct { Adminserver admintypes.MsgServer Bank *bankkeeper.BaseKeeper TokenFactory *tokenfactorykeeper.Keeper - Cronmsgserver crontypes.MsgServer - Cronqueryserver crontypes.QueryServer + CronMsgServer crontypes.MsgServer + CronQueryServer crontypes.QueryServer AdminKeeper *adminmodulekeeper.Keeper ContractmanagerKeeper *contractmanagerkeeper.Keeper DexMsgServer dextypes.MsgServer @@ -985,7 +985,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - _, err := m.Cronmsgserver.AddSchedule(ctx, &crontypes.MsgAddSchedule{ + _, err := m.CronMsgServer.AddSchedule(ctx, &crontypes.MsgAddSchedule{ Authority: authority.String(), Name: addSchedule.Name, Period: addSchedule.Period, @@ -995,9 +995,10 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), + "name", addSchedule.Name, "error", err, ) - return nil, nil, nil, errors.Wrap(err, "failed to addSchedule") + return nil, nil, nil, errors.Wrapf(err, "failed to add %s schedule", addSchedule.Name) } ctx.Logger().Debug("schedule added", @@ -1010,7 +1011,7 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAddress, removeSchedule *bindings.RemoveSchedule) ([]sdk.Event, [][]byte, [][]*types.Any, error) { - params, err := m.Cronqueryserver.Params(ctx, &crontypes.QueryParamsRequest{}) + params, err := m.CronQueryServer.Params(ctx, &crontypes.QueryParamsRequest{}) if err != nil { ctx.Logger().Error("failed to removeSchedule", "error", err) return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") @@ -1022,16 +1023,17 @@ func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAd authority := authtypes.NewModuleAddress(admintypes.ModuleName) - _, err = m.Cronmsgserver.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ + _, err = m.CronMsgServer.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ Authority: authority.String(), Name: removeSchedule.Name, }) if err != nil { ctx.Logger().Error("failed to removeSchedule", "from_address", contractAddr.String(), + "name", removeSchedule.Name, "error", err, ) - return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") + return nil, nil, nil, errors.Wrapf(err, "failed to remove %s schedule", removeSchedule.Name) } ctx.Logger().Debug("schedule removed", diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index e44d5806d..87ab1cb7f 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -67,8 +67,8 @@ func (suite *CustomMessengerTestSuite) SetupTest() { suite.messenger.Adminserver = adminkeeper.NewMsgServerImpl(suite.neutron.AdminmoduleKeeper) suite.messenger.Bank = &suite.neutron.BankKeeper suite.messenger.TokenFactory = suite.neutron.TokenFactoryKeeper - suite.messenger.Cronmsgserver = cronkeeper.NewMsgServerImpl(suite.neutron.CronKeeper) - suite.messenger.Cronqueryserver = suite.neutron.CronKeeper + suite.messenger.CronMsgServer = cronkeeper.NewMsgServerImpl(suite.neutron.CronKeeper) + suite.messenger.CronQueryServer = suite.neutron.CronKeeper suite.messenger.AdminKeeper = &suite.neutron.AdminmoduleKeeper suite.messenger.ContractmanagerKeeper = &suite.neutron.ContractManagerKeeper suite.contractOwner = keeper.RandomAccountAddress(suite.T()) diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index bbf8652e6..ef10b1ffc 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -143,7 +143,7 @@ func TestMsgRemoveScheduleValidate(t *testing.T) { { "invalid authority", types.MsgRemoveSchedule{ - Authority: "", + Authority: "invalid authority", Name: "name", }, "authority is invalid", From 584d0c81114e7c981cea1af4af0bd554ef8caf0f Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Wed, 4 Sep 2024 14:53:56 +0300 Subject: [PATCH 34/60] add cron msgs to whitelist --- app/proposals_allowlisting.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/proposals_allowlisting.go b/app/proposals_allowlisting.go index f2cba406d..9b360b0ea 100644 --- a/app/proposals_allowlisting.go +++ b/app/proposals_allowlisting.go @@ -75,6 +75,8 @@ func isSdkMessageWhitelisted(msg sdk.Msg) bool { *feeburnertypes.MsgUpdateParams, *feerefundertypes.MsgUpdateParams, *crontypes.MsgUpdateParams, + *crontypes.MsgAddSchedule, + *crontypes.MsgRemoveSchedule, *contractmanagertypes.MsgUpdateParams, *dextypes.MsgUpdateParams, *banktypes.MsgUpdateParams, From 6b9ddc2bdc7cd18852c78fda942f41da311ac7d6 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Wed, 4 Sep 2024 15:04:14 +0300 Subject: [PATCH 35/60] check execution stage in tests --- wasmbinding/test/custom_message_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 35732e0b4..fe15d1d10 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -6,6 +6,7 @@ import ( "testing" contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" + types2 "github.com/neutron-org/neutron/v4/x/cron/types" "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -721,6 +722,10 @@ func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { }, } + schedule, ok := suite.neutron.CronKeeper.GetSchedule(suite.ctx, "schedule1") + suite.True(ok) + suite.Equal(types2.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, schedule.ExecutionStage) + // Dispatch AddSchedule message _, err = suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) From a014b5a6dc379517644785af477be148e8f29941 Mon Sep 17 00:00:00 2001 From: Mike Mozhaev Date: Wed, 4 Sep 2024 16:14:46 +0300 Subject: [PATCH 36/60] Revert "feat: added execution stage for schedules #NTRN-339" --- app/proposals_allowlisting.go | 2 - proto/neutron/cron/genesis.proto | 2 +- proto/neutron/cron/params.proto | 2 +- proto/neutron/cron/query.proto | 8 +- proto/neutron/cron/schedule.proto | 21 +- proto/neutron/cron/tx.proto | 51 +- proto/neutron/cron/v1/schedule.proto | 32 - wasmbinding/bindings/msg.go | 7 +- wasmbinding/message_plugin.go | 43 +- wasmbinding/test/custom_message_test.go | 10 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 3 +- x/cron/keeper/keeper.go | 21 +- x/cron/keeper/keeper_test.go | 87 +- x/cron/keeper/migrations.go | 22 - x/cron/keeper/msg_server.go | 46 +- x/cron/keeper/msg_server_test.go | 165 +--- x/cron/migrations/v2/store.go | 56 -- x/cron/migrations/v2/store_test.go | 60 -- x/cron/module.go | 6 +- x/cron/types/codec.go | 2 - x/cron/types/genesis.pb.go | 2 +- x/cron/types/params.pb.go | 2 +- x/cron/types/query.pb.go | 6 - x/cron/types/schedule.pb.go | 123 +-- x/cron/types/tx.go | 91 +- x/cron/types/tx.pb.go | 1046 ++------------------- x/cron/types/v1/schedule.pb.go | 842 ----------------- 28 files changed, 153 insertions(+), 2607 deletions(-) delete mode 100644 proto/neutron/cron/v1/schedule.proto delete mode 100644 x/cron/keeper/migrations.go delete mode 100644 x/cron/migrations/v2/store.go delete mode 100644 x/cron/migrations/v2/store_test.go delete mode 100644 x/cron/types/v1/schedule.pb.go diff --git a/app/proposals_allowlisting.go b/app/proposals_allowlisting.go index 9b360b0ea..f2cba406d 100644 --- a/app/proposals_allowlisting.go +++ b/app/proposals_allowlisting.go @@ -75,8 +75,6 @@ func isSdkMessageWhitelisted(msg sdk.Msg) bool { *feeburnertypes.MsgUpdateParams, *feerefundertypes.MsgUpdateParams, *crontypes.MsgUpdateParams, - *crontypes.MsgAddSchedule, - *crontypes.MsgRemoveSchedule, *contractmanagertypes.MsgUpdateParams, *dextypes.MsgUpdateParams, *banktypes.MsgUpdateParams, diff --git a/proto/neutron/cron/genesis.proto b/proto/neutron/cron/genesis.proto index eba407f97..61b27069a 100644 --- a/proto/neutron/cron/genesis.proto +++ b/proto/neutron/cron/genesis.proto @@ -8,7 +8,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Defines the cron module's genesis state. +// GenesisState defines the cron module's genesis state. message GenesisState { repeated Schedule scheduleList = 2 [(gogoproto.nullable) = false]; Params params = 1 [(gogoproto.nullable) = false]; diff --git a/proto/neutron/cron/params.proto b/proto/neutron/cron/params.proto index c3c5cf452..9bea16a5b 100644 --- a/proto/neutron/cron/params.proto +++ b/proto/neutron/cron/params.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Defines the parameters for the module. +// Params defines the parameters for the module. message Params { option (gogoproto.goproto_stringer) = false; // Security address that can remove schedules diff --git a/proto/neutron/cron/query.proto b/proto/neutron/cron/query.proto index 60ee505e0..401e9ce9d 100644 --- a/proto/neutron/cron/query.proto +++ b/proto/neutron/cron/query.proto @@ -10,7 +10,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Defines the gRPC querier service. +// Query defines the gRPC querier service. service Query { // Queries the parameters of the module. rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { @@ -30,31 +30,25 @@ service Query { // this line is used by starport scaffolding # 2 } -// The request type for the Query/Params RPC method. message QueryParamsRequest {} -// The response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } -// The request type for the Query/Schedule RPC method. message QueryGetScheduleRequest { string name = 1; } -// The response type for the Query/Params RPC method. message QueryGetScheduleResponse { Schedule schedule = 1 [(gogoproto.nullable) = false]; } -// The request type for the Query/Schedules RPC method. message QuerySchedulesRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } -// The response type for the Query/Params RPC method. message QuerySchedulesResponse { repeated Schedule schedules = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index b6147aed4..5df38de34 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -5,38 +5,25 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Defines when messages will be executed in the block -enum ExecutionStage { - // Execution at the end of the block - EXECUTION_STAGE_END_BLOCKER = 0; - // Execution at the beginning of the block - EXECUTION_STAGE_BEGIN_BLOCKER = 1; -} - -// Defines the schedule for execution message Schedule { // Name of schedule string name = 1; // Period in blocks uint64 period = 2; - // Msgs that will be executed every certain number of blocks, specified in the `period` field + // Msgs that will be executed every period amount of time repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; - // Stage when messages will be executed - ExecutionStage execution_stage = 5; } -// Defines the contract and the message to pass message MsgExecuteContract { - // The address of the smart contract + // Contract is the address of the smart contract string contract = 1; - // JSON encoded message to be passed to the contract + // Msg is json encoded message to be passed to the contract string msg = 2; } -// Defines the number of current schedules message ScheduleCount { - // The number of current schedules + // Count is the number of current schedules int32 count = 1; } diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index fcb9b383a..6bb9d3bf7 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -6,72 +6,32 @@ import "cosmos/msg/v1/msg.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "neutron/cron/params.proto"; -import "neutron/cron/schedule.proto"; // this line is used by starport scaffolding # proto/tx/import option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Defines the Msg service. +// Msg defines the Msg service. service Msg { option (cosmos.msg.v1.service) = true; - // Adds new schedule. - rpc AddSchedule(MsgAddSchedule) returns (MsgAddScheduleResponse); - // Removes schedule. - rpc RemoveSchedule(MsgRemoveSchedule) returns (MsgRemoveScheduleResponse); - // Updates the module parameters. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); // this line is used by starport scaffolding # proto/tx/rpc } -// The MsgAddSchedule request type. -message MsgAddSchedule { - option (amino.name) = "cron/MsgAddSchedule"; - option (cosmos.msg.v1.signer) = "authority"; - - // The address of the governance account. - string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // Name of the schedule - string name = 2; - // Period in blocks - uint64 period = 3; - // Msgs that will be executed every certain number of blocks, specified in the `period` field - repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; - // Stage when messages will be executed - ExecutionStage execution_stage = 5; -} - -// Defines the response structure for executing a MsgAddSchedule message. -message MsgAddScheduleResponse {} - -// The MsgRemoveSchedule request type. -message MsgRemoveSchedule { - option (amino.name) = "cron/MsgRemoveSchedule"; - option (cosmos.msg.v1.signer) = "authority"; - - // The address of the governance account. - string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // Name of the schedule - string name = 2; -} - -// Defines the response structure for executing a MsgRemoveSchedule message. -message MsgRemoveScheduleResponse {} - // this line is used by starport scaffolding # proto/tx/message -// The MsgUpdateParams request type. +// MsgUpdateParams is the MsgUpdateParams request type. // // Since: 0.47 message MsgUpdateParams { option (amino.name) = "cron/MsgUpdateParams"; option (cosmos.msg.v1.signer) = "authority"; - // The address of the governance account. + // Authority is the address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // Defines the x/cron parameters to update. + // params defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params params = 2 [ @@ -80,7 +40,8 @@ message MsgUpdateParams { ]; } -// Defines the response structure for executing a MsgUpdateParams message. +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. // // Since: 0.47 message MsgUpdateParamsResponse {} diff --git a/proto/neutron/cron/v1/schedule.proto b/proto/neutron/cron/v1/schedule.proto deleted file mode 100644 index 8995431fe..000000000 --- a/proto/neutron/cron/v1/schedule.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; -package neutron.cron.v1; - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/neutron-org/neutron/v4/x/cron/types/v1"; - -// Defines the schedule for execution -message Schedule { - // Name of schedule - string name = 1; - // Period in blocks - uint64 period = 2; - // Msgs that will be executed every certain number of blocks, specified in the `period` field - repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; - // Last execution's block height - uint64 last_execute_height = 4; -} - -// Defines the contract and the message to pass -message MsgExecuteContract { - // The address of the smart contract - string contract = 1; - // JSON encoded message to be passed to the contract - string msg = 2; -} - -// Defines the number of current schedules -message ScheduleCount { - // The number of current schedules - int32 count = 1; -} diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 8c57b202a..2aee5622a 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -196,10 +196,9 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` - ExecutionStage string `json:"execution_stage"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 8e00248d9..30d53717d 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -73,8 +73,7 @@ func CustomMessageDecorator( Adminserver: adminmodulekeeper.NewMsgServerImpl(*adminKeeper), Bank: bankKeeper, TokenFactory: tokenFactoryKeeper, - CronMsgServer: cronkeeper.NewMsgServerImpl(*cronKeeper), - CronQueryServer: cronKeeper, + CronKeeper: cronKeeper, AdminKeeper: adminKeeper, ContractmanagerKeeper: contractmanagerKeeper, DexMsgServer: dexkeeper.NewMsgServerImpl(*dexKeeper), @@ -91,8 +90,7 @@ type CustomMessenger struct { Adminserver admintypes.MsgServer Bank *bankkeeper.BaseKeeper TokenFactory *tokenfactorykeeper.Keeper - CronMsgServer crontypes.MsgServer - CronQueryServer crontypes.QueryServer + CronKeeper *cronkeeper.Keeper AdminKeeper *adminmodulekeeper.Keeper ContractmanagerKeeper *contractmanagerkeeper.Keeper DexMsgServer dextypes.MsgServer @@ -991,8 +989,6 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin can add schedule") } - authority := authtypes.NewModuleAddress(admintypes.ModuleName) - msgs := make([]crontypes.MsgExecuteContract, 0, len(addSchedule.Msgs)) for _, msg := range addSchedule.Msgs { msgs = append(msgs, crontypes.MsgExecuteContract{ @@ -1001,20 +997,13 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - _, err := m.CronMsgServer.AddSchedule(ctx, &crontypes.MsgAddSchedule{ - Authority: authority.String(), - Name: addSchedule.Name, - Period: addSchedule.Period, - Msgs: msgs, - ExecutionStage: crontypes.ExecutionStage(crontypes.ExecutionStage_value[addSchedule.ExecutionStage]), - }) + err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), - "name", addSchedule.Name, "error", err, ) - return nil, nil, nil, errors.Wrapf(err, "failed to add %s schedule", addSchedule.Name) + return nil, nil, nil, errors.Wrap(err, "marshal json failed") } ctx.Logger().Debug("schedule added", @@ -1027,30 +1016,12 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAddress, removeSchedule *bindings.RemoveSchedule) ([]sdk.Event, [][]byte, [][]*types.Any, error) { - params, err := m.CronQueryServer.Params(ctx, &crontypes.QueryParamsRequest{}) - if err != nil { - ctx.Logger().Error("failed to removeSchedule", "error", err) - return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") - } - - if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.Params.SecurityAddress { + params := m.CronKeeper.GetParams(ctx) + if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.SecurityAddress { return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin or security dao can remove schedule") } - authority := authtypes.NewModuleAddress(admintypes.ModuleName) - - _, err = m.CronMsgServer.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ - Authority: authority.String(), - Name: removeSchedule.Name, - }) - if err != nil { - ctx.Logger().Error("failed to removeSchedule", - "from_address", contractAddr.String(), - "name", removeSchedule.Name, - "error", err, - ) - return nil, nil, nil, errors.Wrapf(err, "failed to remove %s schedule", removeSchedule.Name) - } + m.CronKeeper.RemoveSchedule(ctx, removeSchedule.Name) ctx.Logger().Debug("schedule removed", "from_address", contractAddr.String(), diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index fe15d1d10..446c7159f 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -6,7 +6,6 @@ import ( "testing" contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" - types2 "github.com/neutron-org/neutron/v4/x/cron/types" "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -24,8 +23,6 @@ import ( adminkeeper "github.com/cosmos/admin-module/v2/x/adminmodule/keeper" - cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" - "github.com/neutron-org/neutron/v4/app/params" "github.com/CosmWasm/wasmd/x/wasm/keeper" @@ -70,8 +67,7 @@ func (suite *CustomMessengerTestSuite) SetupTest() { suite.messenger.Adminserver = adminkeeper.NewMsgServerImpl(suite.neutron.AdminmoduleKeeper) suite.messenger.Bank = &suite.neutron.BankKeeper suite.messenger.TokenFactory = suite.neutron.TokenFactoryKeeper - suite.messenger.CronMsgServer = cronkeeper.NewMsgServerImpl(suite.neutron.CronKeeper) - suite.messenger.CronQueryServer = suite.neutron.CronKeeper + suite.messenger.CronKeeper = &suite.neutron.CronKeeper suite.messenger.AdminKeeper = &suite.neutron.AdminmoduleKeeper suite.messenger.ContractmanagerKeeper = &suite.neutron.ContractManagerKeeper suite.contractOwner = keeper.RandomAccountAddress(suite.T()) @@ -722,10 +718,6 @@ func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { }, } - schedule, ok := suite.neutron.CronKeeper.GetSchedule(suite.ctx, "schedule1") - suite.True(ok) - suite.Equal(types2.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, schedule.ExecutionStage) - // Dispatch AddSchedule message _, err = suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) diff --git a/x/cron/genesis.go b/x/cron/genesis.go index 525840e26..974790399 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStage) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index a132fc8d4..b778f8fba 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -133,9 +133,8 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Period = 1000 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) - item.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 070f18b2d..2be2f49ee 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -66,9 +66,10 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // ExecuteReadySchedules gets all schedules that are due for execution (with limit that is equal to Params.Limit) // and executes messages in each one -func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.ExecutionStage) { +// NOTE that errors in contract calls rollback all already executed messages +func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) - schedules := k.getSchedulesReadyForExecution(ctx, executionStage) + schedules := k.getSchedulesReadyForExecution(ctx) for _, schedule := range schedules { err := k.executeSchedule(ctx, schedule) @@ -76,15 +77,9 @@ func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.Exe } } -// AddSchedule adds a new schedule to be executed every certain number of blocks, specified in the `period`. +// AddSchedule adds new schedule to execution for every block `period`. // First schedule execution is supposed to be on `now + period` block. -func (k *Keeper) AddSchedule( - ctx sdk.Context, - name string, - period uint64, - msgs []types.MsgExecuteContract, - executionStage types.ExecutionStage, -) error { +func (k *Keeper) AddSchedule(ctx sdk.Context, name string, period uint64, msgs []types.MsgExecuteContract) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) } @@ -94,9 +89,7 @@ func (k *Keeper) AddSchedule( Period: period, Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block - ExecutionStage: executionStage, } - k.storeSchedule(ctx, schedule) k.changeTotalCount(ctx, 1) @@ -148,7 +141,7 @@ func (k *Keeper) GetScheduleCount(ctx sdk.Context) int32 { return k.getScheduleCount(ctx) } -func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context, executionStage types.ExecutionStage) []types.Schedule { +func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule { params := k.GetParams(ctx) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ScheduleKey) count := uint64(0) @@ -162,7 +155,7 @@ func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context, executionStage t var schedule types.Schedule k.cdc.MustUnmarshal(iterator.Value(), &schedule) - if k.intervalPassed(ctx, schedule) && schedule.ExecutionStage == executionStage { + if k.intervalPassed(ctx, schedule) { res = append(res, schedule) count++ diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index d58553c56..8abe2060c 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -44,7 +44,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { schedules := []types.Schedule{ { Name: "1_unready1", - Period: 10, + Period: 3, Msgs: []types.MsgExecuteContract{ { Contract: "1_neutron", @@ -52,11 +52,10 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "2_ready1", - Period: 4, + Period: 3, Msgs: []types.MsgExecuteContract{ { Contract: "2_neutron", @@ -64,11 +63,10 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "3_ready2", - Period: 4, + Period: 3, Msgs: []types.MsgExecuteContract{ { Contract: "3_neutron", @@ -76,14 +74,12 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "4_unready2", - Period: 10, + Period: 3, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "5_ready3", @@ -95,34 +91,22 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - { - Name: "6_ready4", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "6_neutron", - Msg: "6_msg", - }, - }, - LastExecuteHeight: 0, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) require.NoError(t, err) } count := k.GetScheduleCount(ctx) - require.Equal(t, count, int32(6)) + require.Equal(t, count, int32(5)) ctx = ctx.WithBlockHeight(5) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr).AnyTimes() + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "2_neutron", @@ -136,26 +120,25 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + k.ExecuteReadySchedules(ctx) unready1, _ := k.GetSchedule(ctx, "1_unready1") ready1, _ := k.GetSchedule(ctx, "2_ready1") ready2, _ := k.GetSchedule(ctx, "3_ready2") unready2, _ := k.GetSchedule(ctx, "4_unready2") ready3, _ := k.GetSchedule(ctx, "5_ready3") - ready4, _ := k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(0), ready3.LastExecuteHeight) - require.Equal(t, uint64(0), ready4.LastExecuteHeight) // let's make another call at the next height // Notice that now only one ready schedule left because we got limit of 2 at once ctx = ctx.WithBlockHeight(6) + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "5_neutron", @@ -163,46 +146,19 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + k.ExecuteReadySchedules(ctx) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") ready2, _ = k.GetSchedule(ctx, "3_ready2") unready2, _ = k.GetSchedule(ctx, "4_unready2") ready3, _ = k.GetSchedule(ctx, "5_ready3") - ready4, _ = k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(6), ready3.LastExecuteHeight) - require.Equal(t, uint64(0), ready4.LastExecuteHeight) - - ctx = ctx.WithBlockHeight(7) - - wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ - Sender: testutil.TestOwnerAddress, - Contract: "6_neutron", - Msg: []byte("6_msg"), - Funds: sdk.NewCoins(), - }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - - k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) - - unready1, _ = k.GetSchedule(ctx, "1_unready1") - ready1, _ = k.GetSchedule(ctx, "2_ready1") - ready2, _ = k.GetSchedule(ctx, "3_ready2") - unready2, _ = k.GetSchedule(ctx, "4_unready2") - ready3, _ = k.GetSchedule(ctx, "5_ready3") - ready4, _ = k.GetSchedule(ctx, "6_ready4") - - require.Equal(t, uint64(4), unready1.LastExecuteHeight) - require.Equal(t, uint64(5), ready1.LastExecuteHeight) - require.Equal(t, uint64(5), ready2.LastExecuteHeight) - require.Equal(t, uint64(4), unready2.LastExecuteHeight) - require.Equal(t, uint64(6), ready3.LastExecuteHeight) - require.Equal(t, uint64(7), ready4.LastExecuteHeight) } func TestAddSchedule(t *testing.T) { @@ -227,19 +183,11 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) - require.NoError(t, err) - - err = k.AddSchedule(ctx, "b", 7, []types.MsgExecuteContract{ - { - Contract: "c", - Msg: "m", - }, - }, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + }) require.NoError(t, err) // second time with same name returns error - err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}) require.Error(t, err) scheduleA, found := k.GetSchedule(ctx, "a") @@ -249,12 +197,6 @@ func TestAddSchedule(t *testing.T) { require.Equal(t, scheduleA.Msgs, []types.MsgExecuteContract{ {Contract: "c", Msg: "m"}, }) - require.Equal(t, scheduleA.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) - - schedules := k.GetAllSchedules(ctx) - require.Len(t, schedules, 2) - require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) - require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) // remove schedule works k.RemoveSchedule(ctx, "a") @@ -281,10 +223,9 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStage) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs) require.NoError(t, err) } diff --git a/x/cron/keeper/migrations.go b/x/cron/keeper/migrations.go deleted file mode 100644 index 0166a8da9..000000000 --- a/x/cron/keeper/migrations.go +++ /dev/null @@ -1,22 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" -) - -// Migrator is a struct for handling in-place store migrations. -type Migrator struct { - keeper Keeper -} - -// NewMigrator returns a new Migrator. -func NewMigrator(keeper Keeper) Migrator { - return Migrator{keeper: keeper} -} - -// Migrate1to2 migrates from version 1 to 2. -func (m Migrator) Migrate1to2(ctx sdk.Context) error { - return v2.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey) -} diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index c42a0d1c4..e49e578ab 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -11,66 +11,30 @@ import ( ) type msgServer struct { - keeper Keeper + Keeper } // NewMsgServerImpl returns an implementation of the MsgServer interface // for the provided Keeper. func NewMsgServerImpl(keeper Keeper) types.MsgServer { - return &msgServer{keeper: keeper} + return &msgServer{Keeper: keeper} } var _ types.MsgServer = msgServer{} -// AddSchedule adds new schedule -func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) (*types.MsgAddScheduleResponse, error) { - if err := req.Validate(); err != nil { - return nil, errors.Wrap(err, "failed to validate MsgAddSchedule") - } - - authority := k.keeper.GetAuthority() - if authority != req.Authority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) - } - - ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { - return nil, errors.Wrap(err, "failed to add schedule") - } - - return &types.MsgAddScheduleResponse{}, nil -} - -// RemoveSchedule removes schedule -func (k msgServer) RemoveSchedule(goCtx context.Context, req *types.MsgRemoveSchedule) (*types.MsgRemoveScheduleResponse, error) { - if err := req.Validate(); err != nil { - return nil, errors.Wrap(err, "failed to validate MsgRemoveSchedule") - } - - authority := k.keeper.GetAuthority() - if authority != req.Authority { - return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) - } - - ctx := sdk.UnwrapSDKContext(goCtx) - k.keeper.RemoveSchedule(ctx, req.Name) - - return &types.MsgRemoveScheduleResponse{}, nil -} - // UpdateParams updates the module parameters -func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { +func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "failed to validate MsgUpdateParams") } - authority := k.keeper.GetAuthority() + authority := k.GetAuthority() if authority != req.Authority { return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.keeper.SetParams(ctx, req.Params); err != nil { + if err := k.SetParams(ctx, req.Params); err != nil { return nil, err } diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index ef10b1ffc..17a3655ac 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -6,171 +6,12 @@ import ( "github.com/stretchr/testify/require" "github.com/neutron-org/neutron/v4/testutil" - testkeeper "github.com/neutron-org/neutron/v4/testutil/cron/keeper" - cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" + "github.com/neutron-org/neutron/v4/testutil/cron/keeper" "github.com/neutron-org/neutron/v4/x/cron/types" ) -func TestMsgAddScheduleValidate(t *testing.T) { - k, ctx := testkeeper.CronKeeper(t, nil, nil) - msgServer := cronkeeper.NewMsgServerImpl(*k) - - tests := []struct { - name string - msg types.MsgAddSchedule - expectedErr string - }{ - { - "empty authority", - types.MsgAddSchedule{ - Authority: "", - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - "authority is invalid", - }, - { - "invalid authority", - types.MsgAddSchedule{ - Authority: "invalid authority", - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - "authority is invalid", - }, - { - "invalid name", - types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - "name is invalid", - }, - { - "invalid period", - types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 0, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - "period is invalid", - }, - { - "empty msgs", - types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{}, - ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, - }, - "msgs should not be empty", - }, - { - "invalid execution stage", - types.MsgAddSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "name", - Period: 3, - Msgs: []types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - ExecutionStage: 7, - }, - "execution stage is invalid", - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - resp, err := msgServer.AddSchedule(ctx, &tt.msg) - require.ErrorContains(t, err, tt.expectedErr) - require.Nil(t, resp) - }) - } -} - -func TestMsgRemoveScheduleValidate(t *testing.T) { - k, ctx := testkeeper.CronKeeper(t, nil, nil) - msgServer := cronkeeper.NewMsgServerImpl(*k) - - tests := []struct { - name string - msg types.MsgRemoveSchedule - expectedErr string - }{ - { - "empty authority", - types.MsgRemoveSchedule{ - Authority: "", - Name: "name", - }, - "authority is invalid", - }, - { - "invalid authority", - types.MsgRemoveSchedule{ - Authority: "invalid authority", - Name: "name", - }, - "authority is invalid", - }, - { - "invalid name", - types.MsgRemoveSchedule{ - Authority: testutil.TestOwnerAddress, - Name: "", - }, - "name is invalid", - }, - } - - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - resp, err := msgServer.RemoveSchedule(ctx, &tt.msg) - require.ErrorContains(t, err, tt.expectedErr) - require.Nil(t, resp) - }) - } -} - func TestMsgUpdateParamsValidate(t *testing.T) { - k, ctx := testkeeper.CronKeeper(t, nil, nil) - msgServer := cronkeeper.NewMsgServerImpl(*k) + k, ctx := keeper.CronKeeper(t, nil, nil) tests := []struct { name string @@ -216,7 +57,7 @@ func TestMsgUpdateParamsValidate(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - resp, err := msgServer.UpdateParams(ctx, &tt.msg) + resp, err := k.UpdateParams(ctx, &tt.msg) require.ErrorContains(t, err, tt.expectedErr) require.Nil(t, resp) }) diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go deleted file mode 100644 index f3311aba0..000000000 --- a/x/cron/migrations/v2/store.go +++ /dev/null @@ -1,56 +0,0 @@ -package v2 - -import ( - "cosmossdk.io/errors" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/neutron-org/neutron/v4/x/cron/types" -) - -// MigrateStore performs in-place store migrations. -// The migration adds execution stage for schedules. -func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { - return migrateSchedules(ctx, cdc, storeKey) -} - -type migrationUpdate struct { - key []byte - val []byte -} - -func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { - ctx.Logger().Info("Migrating cron Schedules...") - - store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) - iterator := storetypes.KVStorePrefixIterator(store, []byte{}) - schedulesToUpdate := make([]migrationUpdate, 0) - - for ; iterator.Valid(); iterator.Next() { - var schedule types.Schedule - cdc.MustUnmarshal(iterator.Value(), &schedule) - // Set execution in EndBlocker - schedule.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - - schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ - key: iterator.Key(), - val: cdc.MustMarshal(&schedule), - }) - } - - err := iterator.Close() - if err != nil { - return errors.Wrap(err, "iterator failed to close during migration") - } - - // Store the updated Schedules - for _, v := range schedulesToUpdate { - store.Set(v.key, v.val) - } - - ctx.Logger().Info("Finished migrating cron Schedules...") - - return nil -} diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go deleted file mode 100644 index 6b6f46355..000000000 --- a/x/cron/migrations/v2/store_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package v2_test - -import ( - "testing" - - "cosmossdk.io/store/prefix" - "github.com/stretchr/testify/suite" - - "github.com/neutron-org/neutron/v4/testutil" - v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" - "github.com/neutron-org/neutron/v4/x/cron/types" - v1types "github.com/neutron-org/neutron/v4/x/cron/types/v1" -) - -type V2CronMigrationTestSuite struct { - testutil.IBCConnectionTestSuite -} - -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(V2CronMigrationTestSuite)) -} - -func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { - var ( - app = suite.GetNeutronZoneApp(suite.ChainA) - storeKey = app.GetKey(types.StoreKey) - ctx = suite.ChainA.GetContext() - cdc = app.AppCodec() - ) - - schedule := v1types.Schedule{ - Name: "name", - Period: 3, - Msgs: []v1types.MsgExecuteContract{ - { - Contract: "contract", - Msg: "msg", - }, - }, - LastExecuteHeight: 1, - } - - store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) - bz := cdc.MustMarshal(&schedule) - store.Set(types.GetScheduleKey(schedule.Name), bz) - - // Run migration - suite.NoError(v2.MigrateStore(ctx, cdc, storeKey)) - - // Check Schedule has correct ExecutionStage - newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) - suite.Equal(newSchedule.Name, schedule.Name) - suite.Equal(newSchedule.Period, schedule.Period) - for i, msg := range newSchedule.Msgs { - suite.Equal(msg.Contract, schedule.Msgs[i].Contract) - suite.Equal(msg.Msg, schedule.Msgs[i].Msg) - } - suite.Equal(newSchedule.LastExecuteHeight, schedule.LastExecuteHeight) - suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) -} diff --git a/x/cron/module.go b/x/cron/module.go index 3471b0379..60dc09b91 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -155,12 +155,10 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block -func (am AppModule) BeginBlock(ctx sdk.Context) { - am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) -} +func (am AppModule) BeginBlock(_ sdk.Context) {} // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { - am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx)) return []abci.ValidatorUpdate{}, nil } diff --git a/x/cron/types/codec.go b/x/cron/types/codec.go index 6772e97b9..a52eff2c6 100644 --- a/x/cron/types/codec.go +++ b/x/cron/types/codec.go @@ -15,8 +15,6 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgUpdateParams{}, - &MsgAddSchedule{}, - &MsgRemoveSchedule{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/cron/types/genesis.pb.go b/x/cron/types/genesis.pb.go index 274598ad7..2d3546994 100644 --- a/x/cron/types/genesis.pb.go +++ b/x/cron/types/genesis.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Defines the cron module's genesis state. +// GenesisState defines the cron module's genesis state. type GenesisState struct { ScheduleList []Schedule `protobuf:"bytes,2,rep,name=scheduleList,proto3" json:"scheduleList"` Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` diff --git a/x/cron/types/params.pb.go b/x/cron/types/params.pb.go index e927ec42a..c71904ce8 100644 --- a/x/cron/types/params.pb.go +++ b/x/cron/types/params.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Defines the parameters for the module. +// Params defines the parameters for the module. type Params struct { // Security address that can remove schedules SecurityAddress string `protobuf:"bytes,1,opt,name=security_address,json=securityAddress,proto3" json:"security_address,omitempty"` diff --git a/x/cron/types/query.pb.go b/x/cron/types/query.pb.go index 912a44eaa..c34c6c3f9 100644 --- a/x/cron/types/query.pb.go +++ b/x/cron/types/query.pb.go @@ -30,7 +30,6 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// The request type for the Query/Params RPC method. type QueryParamsRequest struct { } @@ -67,7 +66,6 @@ func (m *QueryParamsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo -// The response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` @@ -113,7 +111,6 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } -// The request type for the Query/Schedule RPC method. type QueryGetScheduleRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -158,7 +155,6 @@ func (m *QueryGetScheduleRequest) GetName() string { return "" } -// The response type for the Query/Params RPC method. type QueryGetScheduleResponse struct { Schedule Schedule `protobuf:"bytes,1,opt,name=schedule,proto3" json:"schedule"` } @@ -203,7 +199,6 @@ func (m *QueryGetScheduleResponse) GetSchedule() Schedule { return Schedule{} } -// The request type for the Query/Schedules RPC method. type QuerySchedulesRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -248,7 +243,6 @@ func (m *QuerySchedulesRequest) GetPagination() *query.PageRequest { return nil } -// The response type for the Query/Params RPC method. type QuerySchedulesResponse struct { Schedules []Schedule `protobuf:"bytes,1,rep,name=schedules,proto3" json:"schedules"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index 845a1059a..cda29cf72 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -23,46 +23,15 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Defines when messages will be executed in the block -type ExecutionStage int32 - -const ( - // Execution at the end of the block - ExecutionStage_EXECUTION_STAGE_END_BLOCKER ExecutionStage = 0 - // Execution at the beginning of the block - ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER ExecutionStage = 1 -) - -var ExecutionStage_name = map[int32]string{ - 0: "EXECUTION_STAGE_END_BLOCKER", - 1: "EXECUTION_STAGE_BEGIN_BLOCKER", -} - -var ExecutionStage_value = map[string]int32{ - "EXECUTION_STAGE_END_BLOCKER": 0, - "EXECUTION_STAGE_BEGIN_BLOCKER": 1, -} - -func (x ExecutionStage) String() string { - return proto.EnumName(ExecutionStage_name, int32(x)) -} - -func (ExecutionStage) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_49ace1b59de613ef, []int{0} -} - -// Defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Period in blocks Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every certain number of blocks, specified in the `period` field + // Msgs that will be executed every period amount of time Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` - // Stage when messages will be executed - ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -126,18 +95,10 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } -func (m *Schedule) GetExecutionStage() ExecutionStage { - if m != nil { - return m.ExecutionStage - } - return ExecutionStage_EXECUTION_STAGE_END_BLOCKER -} - -// Defines the contract and the message to pass type MsgExecuteContract struct { - // The address of the smart contract + // Contract is the address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` - // JSON encoded message to be passed to the contract + // Msg is json encoded message to be passed to the contract Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` } @@ -188,9 +149,8 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } -// Defines the number of current schedules type ScheduleCount struct { - // The number of current schedules + // Count is the number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` } @@ -235,7 +195,6 @@ func (m *ScheduleCount) GetCount() int32 { } func init() { - proto.RegisterEnum("neutron.cron.ExecutionStage", ExecutionStage_name, ExecutionStage_value) proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") @@ -244,32 +203,27 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 393 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xc1, 0xaa, 0xd3, 0x40, - 0x18, 0x85, 0x33, 0x36, 0x2d, 0xed, 0xa8, 0xb5, 0x8e, 0x45, 0x42, 0xab, 0x69, 0x2c, 0x08, 0x41, - 0x30, 0x81, 0xea, 0xca, 0x9d, 0x89, 0x43, 0x5b, 0xd4, 0x16, 0xd2, 0x0a, 0xe2, 0x26, 0xa4, 0xe9, - 0x30, 0x09, 0x34, 0x99, 0x92, 0x99, 0x48, 0x7d, 0x0b, 0x1f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, 0xb4, - 0x2b, 0xdf, 0xe2, 0x92, 0x49, 0x5a, 0x6e, 0xef, 0xdd, 0x84, 0x73, 0x38, 0xdf, 0xe1, 0x9f, 0xf9, - 0x33, 0xb0, 0x9f, 0x92, 0x5c, 0x64, 0x2c, 0xb5, 0xc3, 0xe2, 0xc3, 0xc3, 0x88, 0xac, 0xf3, 0x0d, - 0xb1, 0xb6, 0x19, 0x13, 0x0c, 0x3d, 0xaa, 0x42, 0xab, 0x08, 0x7b, 0x5d, 0xca, 0x28, 0x93, 0x81, - 0x5d, 0xa8, 0x92, 0x19, 0xfe, 0x07, 0xb0, 0xb9, 0xa8, 0x6a, 0x08, 0x41, 0x35, 0x0d, 0x12, 0xa2, - 0x01, 0x03, 0x98, 0x2d, 0x4f, 0x6a, 0xf4, 0x1c, 0x36, 0xb6, 0x24, 0x8b, 0xd9, 0x5a, 0x7b, 0x60, - 0x00, 0x53, 0xf5, 0x2a, 0x87, 0x3e, 0x40, 0x35, 0xe1, 0x94, 0x6b, 0x35, 0xa3, 0x66, 0x3e, 0x1c, - 0x19, 0xd6, 0xed, 0x59, 0xd6, 0x57, 0x4e, 0xf1, 0x8e, 0x84, 0xb9, 0x20, 0x2e, 0x4b, 0x45, 0x16, - 0x84, 0xc2, 0x51, 0xf7, 0x7f, 0x07, 0x8a, 0x27, 0x3b, 0xc8, 0x82, 0xcf, 0x36, 0x01, 0x17, 0x3e, - 0x29, 0x19, 0x3f, 0x22, 0x31, 0x8d, 0x84, 0xa6, 0xca, 0x01, 0x4f, 0x8b, 0xa8, 0x6a, 0x4f, 0x64, - 0x80, 0x30, 0x7c, 0x52, 0xa2, 0x31, 0x4b, 0x7d, 0x2e, 0x02, 0x4a, 0xb4, 0xba, 0x01, 0xcc, 0xf6, - 0xe8, 0xc5, 0xf5, 0x58, 0x7c, 0x86, 0x16, 0x05, 0xe3, 0xb5, 0xc9, 0x95, 0x1f, 0x3a, 0x10, 0xdd, - 0x3f, 0x18, 0xea, 0xc1, 0x66, 0x58, 0xe9, 0xea, 0xe2, 0x17, 0x8f, 0x3a, 0xb0, 0x96, 0x70, 0x2a, - 0x6f, 0xde, 0xf2, 0x0a, 0x39, 0x7c, 0x0d, 0x1f, 0x9f, 0xd7, 0xe5, 0xb2, 0x3c, 0x15, 0xa8, 0x0b, - 0xeb, 0x61, 0x21, 0x64, 0xb7, 0xee, 0x95, 0xe6, 0xcd, 0x12, 0xb6, 0xaf, 0x0f, 0x83, 0x06, 0xb0, - 0x8f, 0xbf, 0x63, 0xf7, 0xdb, 0x72, 0x3a, 0x9f, 0xf9, 0x8b, 0xe5, 0xc7, 0x31, 0xf6, 0xf1, 0xec, - 0x93, 0xef, 0x7c, 0x99, 0xbb, 0x9f, 0xb1, 0xd7, 0x51, 0xd0, 0x2b, 0xf8, 0xf2, 0x2e, 0xe0, 0xe0, - 0xf1, 0x74, 0x76, 0x41, 0x80, 0x33, 0xd9, 0x1f, 0x75, 0x70, 0x38, 0xea, 0xe0, 0xdf, 0x51, 0x07, - 0xbf, 0x4f, 0xba, 0x72, 0x38, 0xe9, 0xca, 0x9f, 0x93, 0xae, 0xfc, 0xb0, 0x68, 0x2c, 0xa2, 0x7c, - 0x65, 0x85, 0x2c, 0xb1, 0xab, 0x95, 0xbc, 0x65, 0x19, 0x3d, 0x6b, 0xfb, 0xe7, 0x7b, 0x7b, 0x57, - 0xbe, 0x11, 0xf1, 0x6b, 0x4b, 0xf8, 0xaa, 0x21, 0xff, 0xfe, 0xbb, 0x9b, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x2e, 0xa9, 0x20, 0xa0, 0x40, 0x02, 0x00, 0x00, + // 309 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xfb, 0x30, + 0x18, 0xc6, 0x9b, 0xff, 0xba, 0xb1, 0xe5, 0xaf, 0xa0, 0x71, 0x48, 0x99, 0x10, 0x4b, 0x41, 0xe8, + 0xc5, 0x14, 0xd4, 0x93, 0xc7, 0x0e, 0x61, 0x17, 0x2f, 0xf5, 0xe6, 0x65, 0x74, 0x59, 0x48, 0x0b, + 0x6b, 0x53, 0x9a, 0x54, 0xe6, 0xb7, 0xf0, 0x33, 0xf8, 0x69, 0x76, 0xdc, 0xd1, 0x93, 0x48, 0xfb, + 0x45, 0x24, 0x69, 0x26, 0x82, 0x97, 0xf0, 0x7b, 0x78, 0xde, 0x27, 0xef, 0xfb, 0x26, 0xf0, 0xa2, + 0x64, 0x8d, 0xaa, 0x45, 0x19, 0x51, 0x7d, 0x48, 0x9a, 0xb1, 0x75, 0xb3, 0x61, 0xa4, 0xaa, 0x85, + 0x12, 0xe8, 0xc8, 0x9a, 0x44, 0x9b, 0xb3, 0x29, 0x17, 0x5c, 0x18, 0x23, 0xd2, 0xd4, 0xd7, 0x04, + 0xef, 0x00, 0x8e, 0x9f, 0x6c, 0x0c, 0x21, 0xe8, 0x96, 0x69, 0xc1, 0x3c, 0xe0, 0x83, 0x70, 0x92, + 0x18, 0x46, 0xe7, 0x70, 0x54, 0xb1, 0x3a, 0x17, 0x6b, 0xef, 0x9f, 0x0f, 0x42, 0x37, 0xb1, 0x0a, + 0xdd, 0x43, 0xb7, 0x90, 0x5c, 0x7a, 0x03, 0x7f, 0x10, 0xfe, 0xbf, 0xf1, 0xc9, 0xef, 0x5e, 0xe4, + 0x51, 0xf2, 0x87, 0x2d, 0xa3, 0x8d, 0x62, 0x73, 0x51, 0xaa, 0x3a, 0xa5, 0x2a, 0x76, 0x77, 0x9f, + 0x97, 0x4e, 0x62, 0x32, 0x88, 0xc0, 0xb3, 0x4d, 0x2a, 0xd5, 0x92, 0xf5, 0x35, 0xcb, 0x8c, 0xe5, + 0x3c, 0x53, 0x9e, 0x6b, 0x1a, 0x9c, 0x6a, 0xcb, 0xa6, 0x17, 0xc6, 0x08, 0x62, 0x88, 0xfe, 0xde, + 0x88, 0x66, 0x70, 0x4c, 0x2d, 0xdb, 0x89, 0x7f, 0x34, 0x3a, 0x81, 0x83, 0x42, 0x72, 0x33, 0xf2, + 0x24, 0xd1, 0x18, 0x5c, 0xc1, 0xe3, 0xc3, 0x9e, 0x73, 0xd1, 0x94, 0x0a, 0x4d, 0xe1, 0x90, 0x6a, + 0x30, 0xd9, 0x61, 0xd2, 0x8b, 0x78, 0xb1, 0x6b, 0x31, 0xd8, 0xb7, 0x18, 0x7c, 0xb5, 0x18, 0xbc, + 0x75, 0xd8, 0xd9, 0x77, 0xd8, 0xf9, 0xe8, 0xb0, 0xf3, 0x4c, 0x78, 0xae, 0xb2, 0x66, 0x45, 0xa8, + 0x28, 0x22, 0xbb, 0xec, 0xb5, 0xa8, 0xf9, 0x81, 0xa3, 0x97, 0xbb, 0x68, 0xdb, 0x7f, 0x83, 0x7a, + 0xad, 0x98, 0x5c, 0x8d, 0xcc, 0x03, 0xdf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x19, 0x38, + 0x8d, 0xa3, 0x01, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -292,11 +246,6 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ExecutionStage != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.ExecutionStage)) - i-- - dAtA[i] = 0x28 - } if m.LastExecuteHeight != 0 { i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) i-- @@ -429,9 +378,6 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } - if m.ExecutionStage != 0 { - n += 1 + sovSchedule(uint64(m.ExecutionStage)) - } return n } @@ -603,25 +549,6 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { break } } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) - } - m.ExecutionStage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ExecutionStage |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } default: iNdEx = preIndex skippy, err := skipSchedule(dAtA[iNdEx:]) diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index 27b4ceec4..eb48677cb 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -1,95 +1,10 @@ package types import ( - "cosmossdk.io/errors" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) -var _ sdk.Msg = &MsgAddSchedule{} - -func (msg *MsgAddSchedule) Route() string { - return RouterKey -} - -func (msg *MsgAddSchedule) Type() string { - return "add-schedule" -} - -func (msg *MsgAddSchedule) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.Authority) - if err != nil { // should never happen as valid basic rejects invalid addresses - panic(err.Error()) - } - return []sdk.AccAddress{authority} -} - -func (msg *MsgAddSchedule) GetSignBytes() []byte { - return ModuleCdc.MustMarshalJSON(msg) -} - -func (msg *MsgAddSchedule) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { - return errors.Wrap(err, "authority is invalid") - } - - if msg.Name == "" { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") - } - - if msg.Period == 0 { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "period is invalid") - } - - if len(msg.Msgs) == 0 { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") - } - - if _, ok := ExecutionStage_name[int32(msg.ExecutionStage)]; !ok { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "execution stage is invalid") - } - - return nil -} - -//---------------------------------------------------------------- - -var _ sdk.Msg = &MsgRemoveSchedule{} - -func (msg *MsgRemoveSchedule) Route() string { - return RouterKey -} - -func (msg *MsgRemoveSchedule) Type() string { - return "remove-schedule" -} - -func (msg *MsgRemoveSchedule) GetSigners() []sdk.AccAddress { - authority, err := sdk.AccAddressFromBech32(msg.Authority) - if err != nil { // should never happen as valid basic rejects invalid addresses - panic(err.Error()) - } - return []sdk.AccAddress{authority} -} - -func (msg *MsgRemoveSchedule) GetSignBytes() []byte { - return ModuleCdc.MustMarshalJSON(msg) -} - -func (msg *MsgRemoveSchedule) Validate() error { - if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { - return errors.Wrap(err, "authority is invalid") - } - - if msg.Name == "" { - return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") - } - - return nil -} - -//---------------------------------------------------------------- - var _ sdk.Msg = &MsgUpdateParams{} func (msg *MsgUpdateParams) Route() string { @@ -114,11 +29,11 @@ func (msg *MsgUpdateParams) GetSignBytes() []byte { func (msg *MsgUpdateParams) Validate() error { if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { - return errors.Wrap(err, "authority is invalid") + return errorsmod.Wrap(err, "authority is invalid") } if _, err := sdk.AccAddressFromBech32(msg.Params.SecurityAddress); err != nil { - return errors.Wrap(err, "security_address is invalid") + return errorsmod.Wrap(err, "security_address is invalid") } return nil diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 141735a4e..217bb879c 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -31,224 +31,13 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// The MsgAddSchedule request type. -type MsgAddSchedule struct { - // The address of the governance account. - Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // Name of the schedule - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - // Period in blocks - Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every certain number of blocks, specified in the `period` field - Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` - // Stage when messages will be executed - ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` -} - -func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } -func (m *MsgAddSchedule) String() string { return proto.CompactTextString(m) } -func (*MsgAddSchedule) ProtoMessage() {} -func (*MsgAddSchedule) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{0} -} -func (m *MsgAddSchedule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgAddSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgAddSchedule.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgAddSchedule) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgAddSchedule.Merge(m, src) -} -func (m *MsgAddSchedule) XXX_Size() int { - return m.Size() -} -func (m *MsgAddSchedule) XXX_DiscardUnknown() { - xxx_messageInfo_MsgAddSchedule.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgAddSchedule proto.InternalMessageInfo - -func (m *MsgAddSchedule) GetAuthority() string { - if m != nil { - return m.Authority - } - return "" -} - -func (m *MsgAddSchedule) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *MsgAddSchedule) GetPeriod() uint64 { - if m != nil { - return m.Period - } - return 0 -} - -func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { - if m != nil { - return m.Msgs - } - return nil -} - -func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { - if m != nil { - return m.ExecutionStage - } - return ExecutionStage_EXECUTION_STAGE_END_BLOCKER -} - -// Defines the response structure for executing a MsgAddSchedule message. -type MsgAddScheduleResponse struct { -} - -func (m *MsgAddScheduleResponse) Reset() { *m = MsgAddScheduleResponse{} } -func (m *MsgAddScheduleResponse) String() string { return proto.CompactTextString(m) } -func (*MsgAddScheduleResponse) ProtoMessage() {} -func (*MsgAddScheduleResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{1} -} -func (m *MsgAddScheduleResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgAddScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgAddScheduleResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgAddScheduleResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgAddScheduleResponse.Merge(m, src) -} -func (m *MsgAddScheduleResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgAddScheduleResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgAddScheduleResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgAddScheduleResponse proto.InternalMessageInfo - -// The MsgRemoveSchedule request type. -type MsgRemoveSchedule struct { - // The address of the governance account. - Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // Name of the schedule - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` -} - -func (m *MsgRemoveSchedule) Reset() { *m = MsgRemoveSchedule{} } -func (m *MsgRemoveSchedule) String() string { return proto.CompactTextString(m) } -func (*MsgRemoveSchedule) ProtoMessage() {} -func (*MsgRemoveSchedule) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{2} -} -func (m *MsgRemoveSchedule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRemoveSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRemoveSchedule.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRemoveSchedule) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRemoveSchedule.Merge(m, src) -} -func (m *MsgRemoveSchedule) XXX_Size() int { - return m.Size() -} -func (m *MsgRemoveSchedule) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRemoveSchedule.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRemoveSchedule proto.InternalMessageInfo - -func (m *MsgRemoveSchedule) GetAuthority() string { - if m != nil { - return m.Authority - } - return "" -} - -func (m *MsgRemoveSchedule) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -// Defines the response structure for executing a MsgRemoveSchedule message. -type MsgRemoveScheduleResponse struct { -} - -func (m *MsgRemoveScheduleResponse) Reset() { *m = MsgRemoveScheduleResponse{} } -func (m *MsgRemoveScheduleResponse) String() string { return proto.CompactTextString(m) } -func (*MsgRemoveScheduleResponse) ProtoMessage() {} -func (*MsgRemoveScheduleResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{3} -} -func (m *MsgRemoveScheduleResponse) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgRemoveScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgRemoveScheduleResponse.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgRemoveScheduleResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgRemoveScheduleResponse.Merge(m, src) -} -func (m *MsgRemoveScheduleResponse) XXX_Size() int { - return m.Size() -} -func (m *MsgRemoveScheduleResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgRemoveScheduleResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgRemoveScheduleResponse proto.InternalMessageInfo - -// The MsgUpdateParams request type. +// MsgUpdateParams is the MsgUpdateParams request type. // // Since: 0.47 type MsgUpdateParams struct { - // The address of the governance account. + // Authority is the address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // Defines the x/cron parameters to update. + // params defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` @@ -258,7 +47,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{4} + return fileDescriptor_c9e0a673aba8d6fd, []int{0} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -301,7 +90,8 @@ func (m *MsgUpdateParams) GetParams() Params { return Params{} } -// Defines the response structure for executing a MsgUpdateParams message. +// MsgUpdateParamsResponse defines the response structure for executing a +// MsgUpdateParams message. // // Since: 0.47 type MsgUpdateParamsResponse struct { @@ -311,7 +101,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{5} + return fileDescriptor_c9e0a673aba8d6fd, []int{1} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -341,10 +131,6 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { - proto.RegisterType((*MsgAddSchedule)(nil), "neutron.cron.MsgAddSchedule") - proto.RegisterType((*MsgAddScheduleResponse)(nil), "neutron.cron.MsgAddScheduleResponse") - proto.RegisterType((*MsgRemoveSchedule)(nil), "neutron.cron.MsgRemoveSchedule") - proto.RegisterType((*MsgRemoveScheduleResponse)(nil), "neutron.cron.MsgRemoveScheduleResponse") proto.RegisterType((*MsgUpdateParams)(nil), "neutron.cron.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "neutron.cron.MsgUpdateParamsResponse") } @@ -352,42 +138,28 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 554 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x6b, 0xdb, 0x40, - 0x14, 0xf6, 0xd9, 0x8e, 0xc1, 0xe7, 0xe0, 0x10, 0xd5, 0x75, 0x64, 0x25, 0x55, 0x8c, 0x68, 0x1b, - 0xd7, 0x10, 0x89, 0xba, 0xa5, 0x05, 0x6f, 0x71, 0x31, 0x74, 0x11, 0xb4, 0x72, 0xbb, 0x64, 0x09, - 0x8a, 0x74, 0x9c, 0x05, 0x95, 0x4e, 0xe8, 0x4e, 0xc6, 0xd9, 0x4a, 0xc7, 0x4c, 0xed, 0x5f, 0xd0, - 0xb5, 0xd0, 0xc5, 0x43, 0xff, 0x88, 0x8c, 0xa1, 0x53, 0xa7, 0x52, 0xec, 0xc1, 0xff, 0x46, 0xd1, - 0xaf, 0x44, 0x17, 0x41, 0x0a, 0x85, 0x2c, 0xa7, 0x7b, 0xef, 0xfb, 0xde, 0xd3, 0x77, 0xdf, 0x3d, - 0x0e, 0xde, 0xf7, 0x50, 0xc8, 0x02, 0xe2, 0x69, 0x56, 0xb4, 0xb0, 0xb9, 0xea, 0x07, 0x84, 0x11, - 0x61, 0x33, 0x4d, 0xab, 0x51, 0x5a, 0xda, 0x36, 0x5d, 0xc7, 0x23, 0x5a, 0xbc, 0x26, 0x04, 0x69, - 0xc7, 0x22, 0xd4, 0x25, 0x54, 0x73, 0x29, 0xd6, 0x66, 0x4f, 0xa3, 0x4f, 0x0a, 0x74, 0x12, 0xe0, - 0x24, 0x8e, 0xb4, 0x24, 0x48, 0xa1, 0x16, 0x26, 0x98, 0x24, 0xf9, 0x68, 0x97, 0x15, 0x70, 0x0a, - 0x7c, 0x33, 0x30, 0xdd, 0xac, 0x60, 0x97, 0x83, 0xa8, 0x35, 0x45, 0x76, 0xf8, 0x01, 0x25, 0xa0, - 0xf2, 0xb5, 0x0c, 0x9b, 0x3a, 0xc5, 0x47, 0xb6, 0x3d, 0x49, 0x01, 0xe1, 0x05, 0xac, 0x9b, 0x21, - 0x9b, 0x92, 0xc0, 0x61, 0x67, 0x22, 0xe8, 0x82, 0x5e, 0x7d, 0x24, 0xfe, 0xfc, 0x71, 0xd8, 0x4a, - 0x55, 0x1c, 0xd9, 0x76, 0x80, 0x28, 0x9d, 0xb0, 0xc0, 0xf1, 0xb0, 0x71, 0x4d, 0x15, 0x04, 0x58, - 0xf5, 0x4c, 0x17, 0x89, 0xe5, 0xa8, 0xc4, 0x88, 0xf7, 0x42, 0x1b, 0xd6, 0x7c, 0x14, 0x38, 0xc4, - 0x16, 0x2b, 0x5d, 0xd0, 0xab, 0x1a, 0x69, 0x24, 0x0c, 0x61, 0xd5, 0xa5, 0x98, 0x8a, 0xd5, 0x6e, - 0xa5, 0xd7, 0x18, 0x74, 0xd5, 0xbc, 0x51, 0xaa, 0x4e, 0xf1, 0x78, 0x8e, 0xac, 0x90, 0xa1, 0x57, - 0xc4, 0x63, 0x81, 0x69, 0xb1, 0x51, 0xf5, 0xe2, 0xf7, 0x7e, 0xc9, 0x88, 0x6b, 0x84, 0x31, 0xdc, - 0x42, 0x31, 0xec, 0x10, 0xef, 0x84, 0x32, 0x13, 0x23, 0x71, 0xa3, 0x0b, 0x7a, 0xcd, 0xc1, 0x1e, - 0xdf, 0x66, 0x9c, 0x91, 0x26, 0x11, 0xc7, 0x68, 0x22, 0x2e, 0x1e, 0x3e, 0xfe, 0xb4, 0x5e, 0xf4, - 0xaf, 0xe5, 0x9f, 0xaf, 0x17, 0xfd, 0x7b, 0xb1, 0x43, 0xbc, 0x1d, 0x8a, 0x08, 0xdb, 0x7c, 0xc6, - 0x40, 0xd4, 0x27, 0x1e, 0x45, 0xca, 0x39, 0x80, 0xdb, 0x3a, 0xc5, 0x06, 0x72, 0xc9, 0x0c, 0xdd, - 0x85, 0x7d, 0xc3, 0x27, 0x45, 0x8d, 0xed, 0x4c, 0x23, 0xff, 0x5b, 0x65, 0x17, 0x76, 0x0a, 0xc9, - 0x2b, 0xa5, 0xdf, 0x01, 0xdc, 0xd2, 0x29, 0x7e, 0xef, 0xdb, 0x26, 0x43, 0x6f, 0xe2, 0xe1, 0xf8, - 0x6f, 0x9d, 0x2f, 0x61, 0x2d, 0x19, 0xaf, 0x58, 0x69, 0x63, 0xd0, 0xe2, 0x5d, 0x4f, 0xba, 0x8f, - 0xea, 0xd1, 0x85, 0x7d, 0x5b, 0x2f, 0xfa, 0xc0, 0x48, 0xe9, 0xc3, 0x83, 0xe2, 0x61, 0x5a, 0xd9, - 0x61, 0xf2, 0xca, 0x94, 0x0e, 0xdc, 0xb9, 0x91, 0xca, 0x0e, 0x32, 0xf8, 0x52, 0x86, 0x15, 0x9d, - 0x62, 0xe1, 0x2d, 0x6c, 0xe4, 0x47, 0x76, 0xaf, 0x30, 0x40, 0x39, 0x54, 0x7a, 0x78, 0x1b, 0x9a, - 0xb5, 0x16, 0x8e, 0x61, 0xf3, 0xc6, 0x4d, 0xee, 0x17, 0xea, 0x78, 0x82, 0x74, 0xf0, 0x0f, 0xc2, - 0x55, 0xef, 0x77, 0x70, 0x93, 0xf3, 0xfe, 0x41, 0xa1, 0x30, 0x0f, 0x4b, 0x8f, 0x6e, 0x85, 0xb3, - 0xae, 0xd2, 0xc6, 0xc7, 0xc8, 0xdf, 0xd1, 0xeb, 0x8b, 0xa5, 0x0c, 0x2e, 0x97, 0x32, 0xf8, 0xb3, - 0x94, 0xc1, 0xe7, 0x95, 0x5c, 0xba, 0x5c, 0xc9, 0xa5, 0x5f, 0x2b, 0xb9, 0x74, 0xac, 0x62, 0x87, - 0x4d, 0xc3, 0x53, 0xd5, 0x22, 0xae, 0x96, 0x76, 0x3c, 0x24, 0x01, 0xce, 0xf6, 0xda, 0xec, 0xb9, - 0x36, 0x4f, 0x9f, 0xac, 0x33, 0x1f, 0xd1, 0xd3, 0x5a, 0xfc, 0x26, 0x3c, 0xfb, 0x1b, 0x00, 0x00, - 0xff, 0xff, 0xf7, 0xca, 0x79, 0x29, 0xcf, 0x04, 0x00, 0x00, + // 335 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0x4b, 0x2d, 0x2d, + 0x29, 0xca, 0xcf, 0xd3, 0x4f, 0x06, 0x11, 0x25, 0x15, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, + 0x3c, 0x50, 0x61, 0x3d, 0x90, 0xb0, 0x94, 0x60, 0x62, 0x6e, 0x66, 0x5e, 0xbe, 0x3e, 0x98, 0x84, + 0x28, 0x90, 0x12, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0xcf, 0x2d, 0x4e, 0xd7, 0x2f, 0x33, + 0x04, 0x51, 0x50, 0x09, 0x49, 0x88, 0x44, 0x3c, 0x98, 0xa7, 0x0f, 0xe1, 0x40, 0xa5, 0x44, 0xd2, + 0xf3, 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16, 0x4c, 0x03, 0x8a, 0x0b, 0x0a, 0x12, 0x8b, 0x12, 0x73, + 0xa1, 0x1a, 0x94, 0x56, 0x33, 0x72, 0xf1, 0xfb, 0x16, 0xa7, 0x87, 0x16, 0xa4, 0x24, 0x96, 0xa4, + 0x06, 0x80, 0x65, 0x84, 0xcc, 0xb8, 0x38, 0x13, 0x4b, 0x4b, 0x32, 0xf2, 0x8b, 0x32, 0x4b, 0x2a, + 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x9d, 0x24, 0x2e, 0x6d, 0xd1, 0x15, 0x81, 0xda, 0xe4, 0x98, + 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x1e, 0x84, 0x50, 0x2a, 0x64, + 0xce, 0xc5, 0x06, 0x31, 0x5b, 0x82, 0x49, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x44, 0x0f, 0xd9, 0x8b, + 0x7a, 0x10, 0xd3, 0x9d, 0x38, 0x4f, 0xdc, 0x93, 0x67, 0x58, 0xf1, 0x7c, 0x83, 0x16, 0x63, 0x10, + 0x54, 0xb9, 0x95, 0x7a, 0xd3, 0xf3, 0x0d, 0x5a, 0x08, 0x83, 0xba, 0x9e, 0x6f, 0xd0, 0x12, 0x01, + 0x3b, 0x15, 0xcd, 0x65, 0x4a, 0x92, 0x5c, 0xe2, 0x68, 0x42, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, + 0xc5, 0xa9, 0x46, 0x49, 0x5c, 0xcc, 0xbe, 0xc5, 0xe9, 0x42, 0x21, 0x5c, 0x3c, 0x28, 0x7e, 0x91, + 0x45, 0x75, 0x03, 0x9a, 0x6e, 0x29, 0x55, 0xbc, 0xd2, 0x30, 0xc3, 0xa5, 0x58, 0x1b, 0x40, 0xee, + 0x75, 0xf2, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, + 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xbd, 0xf4, 0xcc, + 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xa8, 0x89, 0xba, 0xf9, 0x45, 0xe9, 0x30, + 0xb6, 0x7e, 0x99, 0x89, 0x7e, 0x05, 0x34, 0xfe, 0x2b, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xa1, + 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x60, 0xa1, 0xa6, 0xeb, 0x1c, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -402,11 +174,6 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { - // Adds new schedule. - AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) - // Removes schedule. - RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) - // Updates the module parameters. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -418,24 +185,6 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } -func (c *msgClient) AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) { - out := new(MsgAddScheduleResponse) - err := c.cc.Invoke(ctx, "/neutron.cron.Msg/AddSchedule", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *msgClient) RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) { - out := new(MsgRemoveScheduleResponse) - err := c.cc.Invoke(ctx, "/neutron.cron.Msg/RemoveSchedule", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/neutron.cron.Msg/UpdateParams", in, out, opts...) @@ -447,11 +196,6 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { - // Adds new schedule. - AddSchedule(context.Context, *MsgAddSchedule) (*MsgAddScheduleResponse, error) - // Removes schedule. - RemoveSchedule(context.Context, *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) - // Updates the module parameters. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -459,12 +203,6 @@ type MsgServer interface { type UnimplementedMsgServer struct { } -func (*UnimplementedMsgServer) AddSchedule(ctx context.Context, req *MsgAddSchedule) (*MsgAddScheduleResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method AddSchedule not implemented") -} -func (*UnimplementedMsgServer) RemoveSchedule(ctx context.Context, req *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method RemoveSchedule not implemented") -} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -473,42 +211,6 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } -func _Msg_AddSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgAddSchedule) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).AddSchedule(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/neutron.cron.Msg/AddSchedule", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).AddSchedule(ctx, req.(*MsgAddSchedule)) - } - return interceptor(ctx, in, info, handler) -} - -func _Msg_RemoveSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgRemoveSchedule) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MsgServer).RemoveSchedule(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/neutron.cron.Msg/RemoveSchedule", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).RemoveSchedule(ctx, req.(*MsgRemoveSchedule)) - } - return interceptor(ctx, in, info, handler) -} - func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -531,14 +233,6 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "neutron.cron.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ - { - MethodName: "AddSchedule", - Handler: _Msg_AddSchedule_Handler, - }, - { - MethodName: "RemoveSchedule", - Handler: _Msg_RemoveSchedule_Handler, - }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -548,7 +242,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "neutron/cron/tx.proto", } -func (m *MsgAddSchedule) Marshal() (dAtA []byte, err error) { +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -558,47 +252,26 @@ func (m *MsgAddSchedule) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgAddSchedule) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.ExecutionStage != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.ExecutionStage)) - i-- - dAtA[i] = 0x28 - } - if len(m.Msgs) > 0 { - for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x22 + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) } - if m.Period != 0 { - i = encodeVarintTx(dAtA, i, uint64(m.Period)) - i-- - dAtA[i] = 0x18 - } - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x12 - } + i-- + dAtA[i] = 0x12 if len(m.Authority) > 0 { i -= len(m.Authority) copy(dAtA[i:], m.Authority) @@ -609,7 +282,7 @@ func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgAddScheduleResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -619,12 +292,12 @@ func (m *MsgAddScheduleResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgAddScheduleResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgAddScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -632,226 +305,39 @@ func (m *MsgAddScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func (m *MsgRemoveSchedule) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ } - return dAtA[:n], nil -} - -func (m *MsgRemoveSchedule) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) + dAtA[offset] = uint8(v) + return base } - -func (m *MsgRemoveSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } var l int _ = l - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0x12 - } - if len(m.Authority) > 0 { - i -= len(m.Authority) - copy(dAtA[i:], m.Authority) - i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) - i-- - dAtA[i] = 0xa + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) } - return len(dAtA) - i, nil + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n } -func (m *MsgRemoveScheduleResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 } - return dAtA[:n], nil -} - -func (m *MsgRemoveScheduleResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgRemoveScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i var l int _ = l - return len(dAtA) - i, nil -} - -func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if len(m.Authority) > 0 { - i -= len(m.Authority) - copy(dAtA[i:], m.Authority) - i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - return len(dAtA) - i, nil -} - -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *MsgAddSchedule) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Name) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - if m.Period != 0 { - n += 1 + sovTx(uint64(m.Period)) - } - if len(m.Msgs) > 0 { - for _, e := range m.Msgs { - l = e.Size() - n += 1 + l + sovTx(uint64(l)) - } - } - if m.ExecutionStage != 0 { - n += 1 + sovTx(uint64(m.ExecutionStage)) - } - return n -} - -func (m *MsgAddScheduleResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgRemoveSchedule) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = len(m.Name) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - return n -} - -func (m *MsgRemoveScheduleResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n -} - -func (m *MsgUpdateParams) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) - } - l = m.Params.Size() - n += 1 + l + sovTx(uint64(l)) - return n -} - -func (m *MsgUpdateParamsResponse) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - return n + return n } func sovTx(x uint64) (n int) { @@ -860,406 +346,6 @@ func sovTx(x uint64) (n int) { func sozTx(x uint64) (n int) { return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgAddSchedule: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAddSchedule: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Authority = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) - } - m.Period = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Period |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Msgs", 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 - } - m.Msgs = append(m.Msgs, MsgExecuteContract{}) - if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) - } - m.ExecutionStage = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.ExecutionStage |= ExecutionStage(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgAddScheduleResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgAddScheduleResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgAddScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRemoveSchedule) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRemoveSchedule: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRemoveSchedule: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Authority = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgRemoveScheduleResponse) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgRemoveScheduleResponse: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgRemoveScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - default: - iNdEx = preIndex - skippy, err := skipTx(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTx - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go deleted file mode 100644 index 3a35f34e6..000000000 --- a/x/cron/types/v1/schedule.pb.go +++ /dev/null @@ -1,842 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: neutron/cron/v1/schedule.proto - -package v1 - -import ( - fmt "fmt" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -// Defines the schedule for execution -type Schedule struct { - // Name of schedule - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // Period in blocks - Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every certain number of blocks, specified in the `period` field - Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` - // Last execution's block height - LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` -} - -func (m *Schedule) Reset() { *m = Schedule{} } -func (m *Schedule) String() string { return proto.CompactTextString(m) } -func (*Schedule) ProtoMessage() {} -func (*Schedule) Descriptor() ([]byte, []int) { - return fileDescriptor_cd4938034d592826, []int{0} -} -func (m *Schedule) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Schedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Schedule.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *Schedule) XXX_Merge(src proto.Message) { - xxx_messageInfo_Schedule.Merge(m, src) -} -func (m *Schedule) XXX_Size() int { - return m.Size() -} -func (m *Schedule) XXX_DiscardUnknown() { - xxx_messageInfo_Schedule.DiscardUnknown(m) -} - -var xxx_messageInfo_Schedule proto.InternalMessageInfo - -func (m *Schedule) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *Schedule) GetPeriod() uint64 { - if m != nil { - return m.Period - } - return 0 -} - -func (m *Schedule) GetMsgs() []MsgExecuteContract { - if m != nil { - return m.Msgs - } - return nil -} - -func (m *Schedule) GetLastExecuteHeight() uint64 { - if m != nil { - return m.LastExecuteHeight - } - return 0 -} - -// Defines the contract and the message to pass -type MsgExecuteContract struct { - // The address of the smart contract - Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` - // JSON encoded message to be passed to the contract - Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` -} - -func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } -func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } -func (*MsgExecuteContract) ProtoMessage() {} -func (*MsgExecuteContract) Descriptor() ([]byte, []int) { - return fileDescriptor_cd4938034d592826, []int{1} -} -func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *MsgExecuteContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_MsgExecuteContract.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *MsgExecuteContract) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgExecuteContract.Merge(m, src) -} -func (m *MsgExecuteContract) XXX_Size() int { - return m.Size() -} -func (m *MsgExecuteContract) XXX_DiscardUnknown() { - xxx_messageInfo_MsgExecuteContract.DiscardUnknown(m) -} - -var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo - -func (m *MsgExecuteContract) GetContract() string { - if m != nil { - return m.Contract - } - return "" -} - -func (m *MsgExecuteContract) GetMsg() string { - if m != nil { - return m.Msg - } - return "" -} - -// Defines the number of current schedules -type ScheduleCount struct { - // The number of current schedules - Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` -} - -func (m *ScheduleCount) Reset() { *m = ScheduleCount{} } -func (m *ScheduleCount) String() string { return proto.CompactTextString(m) } -func (*ScheduleCount) ProtoMessage() {} -func (*ScheduleCount) Descriptor() ([]byte, []int) { - return fileDescriptor_cd4938034d592826, []int{2} -} -func (m *ScheduleCount) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ScheduleCount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ScheduleCount.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *ScheduleCount) XXX_Merge(src proto.Message) { - xxx_messageInfo_ScheduleCount.Merge(m, src) -} -func (m *ScheduleCount) XXX_Size() int { - return m.Size() -} -func (m *ScheduleCount) XXX_DiscardUnknown() { - xxx_messageInfo_ScheduleCount.DiscardUnknown(m) -} - -var xxx_messageInfo_ScheduleCount proto.InternalMessageInfo - -func (m *ScheduleCount) GetCount() int32 { - if m != nil { - return m.Count - } - return 0 -} - -func init() { - proto.RegisterType((*Schedule)(nil), "neutron.cron.v1.Schedule") - proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.v1.MsgExecuteContract") - proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.v1.ScheduleCount") -} - -func init() { proto.RegisterFile("neutron/cron/v1/schedule.proto", fileDescriptor_cd4938034d592826) } - -var fileDescriptor_cd4938034d592826 = []byte{ - // 316 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xc1, 0x4a, 0xc3, 0x30, - 0x18, 0xc7, 0x1b, 0xd7, 0x8d, 0x2d, 0x22, 0x6a, 0x1c, 0x52, 0x76, 0x88, 0x63, 0x22, 0xec, 0x62, - 0x42, 0xd5, 0xab, 0x97, 0x0d, 0x41, 0x10, 0x2f, 0xf5, 0xe6, 0x65, 0x6c, 0x59, 0x48, 0x07, 0x6b, - 0x53, 0x9a, 0xb4, 0xcc, 0xb7, 0xf0, 0x25, 0x7c, 0x97, 0x1d, 0x77, 0xf4, 0x24, 0xd2, 0xbe, 0x88, - 0x24, 0xcd, 0x3c, 0xe8, 0x25, 0xfc, 0xfe, 0xfc, 0xbf, 0x7f, 0xbe, 0xef, 0x4b, 0x20, 0x4e, 0x79, - 0xa1, 0x73, 0x99, 0x52, 0x66, 0x8e, 0x32, 0xa4, 0x8a, 0xc5, 0x7c, 0x59, 0xac, 0x39, 0xc9, 0x72, - 0xa9, 0x25, 0x3a, 0x76, 0x3e, 0x31, 0x3e, 0x29, 0xc3, 0x41, 0x5f, 0x48, 0x21, 0xad, 0x47, 0x0d, - 0x35, 0x65, 0xa3, 0x0f, 0x00, 0xbb, 0x2f, 0x2e, 0x89, 0x10, 0xf4, 0xd3, 0x79, 0xc2, 0x03, 0x30, - 0x04, 0xe3, 0x5e, 0x64, 0x19, 0x9d, 0xc3, 0x4e, 0xc6, 0xf3, 0x95, 0x5c, 0x06, 0x07, 0x43, 0x30, - 0xf6, 0x23, 0xa7, 0xd0, 0x3d, 0xf4, 0x13, 0x25, 0x54, 0xd0, 0x1a, 0xb6, 0xc6, 0x87, 0x37, 0x97, - 0xe4, 0x4f, 0x3b, 0xf2, 0xac, 0xc4, 0xc3, 0x86, 0xb3, 0x42, 0xf3, 0xa9, 0x4c, 0x75, 0x3e, 0x67, - 0x7a, 0xe2, 0x6f, 0xbf, 0x2e, 0xbc, 0xc8, 0xc6, 0x10, 0x81, 0x67, 0xeb, 0xb9, 0xd2, 0x33, 0xde, - 0xd4, 0xcc, 0x62, 0xbe, 0x12, 0xb1, 0x0e, 0x7c, 0xdb, 0xe3, 0xd4, 0x58, 0x2e, 0xfd, 0x68, 0x8d, - 0xd1, 0x04, 0xa2, 0xff, 0x37, 0xa2, 0x01, 0xec, 0x32, 0xc7, 0x6e, 0xe8, 0x5f, 0x8d, 0x4e, 0x60, - 0x2b, 0x51, 0xc2, 0x4e, 0xdd, 0x8b, 0x0c, 0x8e, 0xae, 0xe0, 0xd1, 0x7e, 0xd5, 0xa9, 0x2c, 0x52, - 0x8d, 0xfa, 0xb0, 0xcd, 0x0c, 0xd8, 0x6c, 0x3b, 0x6a, 0xc4, 0xe4, 0x69, 0x5b, 0x61, 0xb0, 0xab, - 0x30, 0xf8, 0xae, 0x30, 0x78, 0xaf, 0xb1, 0xb7, 0xab, 0xb1, 0xf7, 0x59, 0x63, 0xef, 0x35, 0x14, - 0x2b, 0x1d, 0x17, 0x0b, 0xc2, 0x64, 0x42, 0xdd, 0xbe, 0xd7, 0x32, 0x17, 0x7b, 0xa6, 0xe5, 0x1d, - 0xdd, 0x34, 0xff, 0xa1, 0xdf, 0x32, 0xae, 0x68, 0x19, 0x2e, 0x3a, 0xf6, 0x99, 0x6f, 0x7f, 0x02, - 0x00, 0x00, 0xff, 0xff, 0x4d, 0x2d, 0x47, 0x23, 0xaf, 0x01, 0x00, 0x00, -} - -func (m *Schedule) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *Schedule) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.LastExecuteHeight != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) - i-- - dAtA[i] = 0x20 - } - if len(m.Msgs) > 0 { - for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintSchedule(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - } - } - if m.Period != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.Period)) - i-- - dAtA[i] = 0x10 - } - if len(m.Name) > 0 { - i -= len(m.Name) - copy(dAtA[i:], m.Name) - i = encodeVarintSchedule(dAtA, i, uint64(len(m.Name))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *MsgExecuteContract) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *MsgExecuteContract) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.Msg) > 0 { - i -= len(m.Msg) - copy(dAtA[i:], m.Msg) - i = encodeVarintSchedule(dAtA, i, uint64(len(m.Msg))) - i-- - dAtA[i] = 0x12 - } - if len(m.Contract) > 0 { - i -= len(m.Contract) - copy(dAtA[i:], m.Contract) - i = encodeVarintSchedule(dAtA, i, uint64(len(m.Contract))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *ScheduleCount) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *ScheduleCount) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ScheduleCount) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.Count != 0 { - i = encodeVarintSchedule(dAtA, i, uint64(m.Count)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func encodeVarintSchedule(dAtA []byte, offset int, v uint64) int { - offset -= sovSchedule(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *Schedule) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Name) - if l > 0 { - n += 1 + l + sovSchedule(uint64(l)) - } - if m.Period != 0 { - n += 1 + sovSchedule(uint64(m.Period)) - } - if len(m.Msgs) > 0 { - for _, e := range m.Msgs { - l = e.Size() - n += 1 + l + sovSchedule(uint64(l)) - } - } - if m.LastExecuteHeight != 0 { - n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) - } - return n -} - -func (m *MsgExecuteContract) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Contract) - if l > 0 { - n += 1 + l + sovSchedule(uint64(l)) - } - l = len(m.Msg) - if l > 0 { - n += 1 + l + sovSchedule(uint64(l)) - } - return n -} - -func (m *ScheduleCount) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.Count != 0 { - n += 1 + sovSchedule(uint64(m.Count)) - } - return n -} - -func sovSchedule(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozSchedule(x uint64) (n int) { - return sovSchedule(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *Schedule) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Schedule: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Schedule: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSchedule - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSchedule - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Name = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) - } - m.Period = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Period |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthSchedule - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthSchedule - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Msgs = append(m.Msgs, MsgExecuteContract{}) - if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LastExecuteHeight", wireType) - } - m.LastExecuteHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LastExecuteHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipSchedule(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSchedule - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: MsgExecuteContract: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: MsgExecuteContract: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSchedule - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSchedule - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Contract = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthSchedule - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSchedule - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Msg = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipSchedule(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSchedule - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ScheduleCount) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ScheduleCount: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ScheduleCount: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) - } - m.Count = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSchedule - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Count |= int32(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipSchedule(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSchedule - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipSchedule(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSchedule - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSchedule - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowSchedule - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthSchedule - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupSchedule - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthSchedule - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthSchedule = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowSchedule = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupSchedule = fmt.Errorf("proto: unexpected end of group") -) From 43048ffbb365d3b17234831d9c52a224b1777ace Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Wed, 4 Sep 2024 16:26:45 +0300 Subject: [PATCH 37/60] bring it back --- app/proposals_allowlisting.go | 2 + proto/neutron/cron/genesis.proto | 2 +- proto/neutron/cron/params.proto | 2 +- proto/neutron/cron/query.proto | 8 +- proto/neutron/cron/schedule.proto | 21 +- proto/neutron/cron/tx.proto | 51 +- proto/neutron/cron/v1/schedule.proto | 32 + wasmbinding/bindings/msg.go | 7 +- wasmbinding/message_plugin.go | 43 +- wasmbinding/test/custom_message_test.go | 10 +- x/cron/genesis.go | 2 +- x/cron/keeper/grpc_query_schedule_test.go | 3 +- x/cron/keeper/keeper.go | 21 +- x/cron/keeper/keeper_test.go | 87 +- x/cron/keeper/migrations.go | 22 + x/cron/keeper/msg_server.go | 46 +- x/cron/keeper/msg_server_test.go | 165 +++- x/cron/migrations/v2/store.go | 56 ++ x/cron/migrations/v2/store_test.go | 60 ++ x/cron/module.go | 6 +- x/cron/types/codec.go | 2 + x/cron/types/genesis.pb.go | 2 +- x/cron/types/params.pb.go | 2 +- x/cron/types/query.pb.go | 6 + x/cron/types/schedule.pb.go | 123 ++- x/cron/types/tx.go | 91 +- x/cron/types/tx.pb.go | 1056 +++++++++++++++++++-- x/cron/types/v1/schedule.pb.go | 842 ++++++++++++++++ 28 files changed, 2612 insertions(+), 158 deletions(-) create mode 100644 proto/neutron/cron/v1/schedule.proto create mode 100644 x/cron/keeper/migrations.go create mode 100644 x/cron/migrations/v2/store.go create mode 100644 x/cron/migrations/v2/store_test.go create mode 100644 x/cron/types/v1/schedule.pb.go diff --git a/app/proposals_allowlisting.go b/app/proposals_allowlisting.go index f2cba406d..9b360b0ea 100644 --- a/app/proposals_allowlisting.go +++ b/app/proposals_allowlisting.go @@ -75,6 +75,8 @@ func isSdkMessageWhitelisted(msg sdk.Msg) bool { *feeburnertypes.MsgUpdateParams, *feerefundertypes.MsgUpdateParams, *crontypes.MsgUpdateParams, + *crontypes.MsgAddSchedule, + *crontypes.MsgRemoveSchedule, *contractmanagertypes.MsgUpdateParams, *dextypes.MsgUpdateParams, *banktypes.MsgUpdateParams, diff --git a/proto/neutron/cron/genesis.proto b/proto/neutron/cron/genesis.proto index 61b27069a..eba407f97 100644 --- a/proto/neutron/cron/genesis.proto +++ b/proto/neutron/cron/genesis.proto @@ -8,7 +8,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// GenesisState defines the cron module's genesis state. +// Defines the cron module's genesis state. message GenesisState { repeated Schedule scheduleList = 2 [(gogoproto.nullable) = false]; Params params = 1 [(gogoproto.nullable) = false]; diff --git a/proto/neutron/cron/params.proto b/proto/neutron/cron/params.proto index 9bea16a5b..c3c5cf452 100644 --- a/proto/neutron/cron/params.proto +++ b/proto/neutron/cron/params.proto @@ -5,7 +5,7 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Params defines the parameters for the module. +// Defines the parameters for the module. message Params { option (gogoproto.goproto_stringer) = false; // Security address that can remove schedules diff --git a/proto/neutron/cron/query.proto b/proto/neutron/cron/query.proto index 401e9ce9d..60ee505e0 100644 --- a/proto/neutron/cron/query.proto +++ b/proto/neutron/cron/query.proto @@ -10,7 +10,7 @@ import "neutron/cron/schedule.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Query defines the gRPC querier service. +// Defines the gRPC querier service. service Query { // Queries the parameters of the module. rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { @@ -30,25 +30,31 @@ service Query { // this line is used by starport scaffolding # 2 } +// The request type for the Query/Params RPC method. message QueryParamsRequest {} +// The response type for the Query/Params RPC method. message QueryParamsResponse { // params holds all the parameters of this module. Params params = 1 [(gogoproto.nullable) = false]; } +// The request type for the Query/Schedule RPC method. message QueryGetScheduleRequest { string name = 1; } +// The response type for the Query/Params RPC method. message QueryGetScheduleResponse { Schedule schedule = 1 [(gogoproto.nullable) = false]; } +// The request type for the Query/Schedules RPC method. message QuerySchedulesRequest { cosmos.base.query.v1beta1.PageRequest pagination = 1; } +// The response type for the Query/Params RPC method. message QuerySchedulesResponse { repeated Schedule schedules = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; diff --git a/proto/neutron/cron/schedule.proto b/proto/neutron/cron/schedule.proto index 5df38de34..b6147aed4 100644 --- a/proto/neutron/cron/schedule.proto +++ b/proto/neutron/cron/schedule.proto @@ -5,25 +5,38 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; +// Defines when messages will be executed in the block +enum ExecutionStage { + // Execution at the end of the block + EXECUTION_STAGE_END_BLOCKER = 0; + // Execution at the beginning of the block + EXECUTION_STAGE_BEGIN_BLOCKER = 1; +} + +// Defines the schedule for execution message Schedule { // Name of schedule string name = 1; // Period in blocks uint64 period = 2; - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; // Last execution's block height uint64 last_execute_height = 4; + // Stage when messages will be executed + ExecutionStage execution_stage = 5; } +// Defines the contract and the message to pass message MsgExecuteContract { - // Contract is the address of the smart contract + // The address of the smart contract string contract = 1; - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract string msg = 2; } +// Defines the number of current schedules message ScheduleCount { - // Count is the number of current schedules + // The number of current schedules int32 count = 1; } diff --git a/proto/neutron/cron/tx.proto b/proto/neutron/cron/tx.proto index 6bb9d3bf7..fcb9b383a 100644 --- a/proto/neutron/cron/tx.proto +++ b/proto/neutron/cron/tx.proto @@ -6,32 +6,72 @@ import "cosmos/msg/v1/msg.proto"; import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; import "neutron/cron/params.proto"; +import "neutron/cron/schedule.proto"; // this line is used by starport scaffolding # proto/tx/import option go_package = "github.com/neutron-org/neutron/v4/x/cron/types"; -// Msg defines the Msg service. +// Defines the Msg service. service Msg { option (cosmos.msg.v1.service) = true; + // Adds new schedule. + rpc AddSchedule(MsgAddSchedule) returns (MsgAddScheduleResponse); + // Removes schedule. + rpc RemoveSchedule(MsgRemoveSchedule) returns (MsgRemoveScheduleResponse); + // Updates the module parameters. rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); // this line is used by starport scaffolding # proto/tx/rpc } +// The MsgAddSchedule request type. +message MsgAddSchedule { + option (amino.name) = "cron/MsgAddSchedule"; + option (cosmos.msg.v1.signer) = "authority"; + + // The address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // Name of the schedule + string name = 2; + // Period in blocks + uint64 period = 3; + // Msgs that will be executed every certain number of blocks, specified in the `period` field + repeated MsgExecuteContract msgs = 4 [(gogoproto.nullable) = false]; + // Stage when messages will be executed + ExecutionStage execution_stage = 5; +} + +// Defines the response structure for executing a MsgAddSchedule message. +message MsgAddScheduleResponse {} + +// The MsgRemoveSchedule request type. +message MsgRemoveSchedule { + option (amino.name) = "cron/MsgRemoveSchedule"; + option (cosmos.msg.v1.signer) = "authority"; + + // The address of the governance account. + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // Name of the schedule + string name = 2; +} + +// Defines the response structure for executing a MsgRemoveSchedule message. +message MsgRemoveScheduleResponse {} + // this line is used by starport scaffolding # proto/tx/message -// MsgUpdateParams is the MsgUpdateParams request type. +// The MsgUpdateParams request type. // // Since: 0.47 message MsgUpdateParams { option (amino.name) = "cron/MsgUpdateParams"; option (cosmos.msg.v1.signer) = "authority"; - // Authority is the address of the governance account. + // The address of the governance account. string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // params defines the x/cron parameters to update. + // Defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params params = 2 [ @@ -40,8 +80,7 @@ message MsgUpdateParams { ]; } -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. +// Defines the response structure for executing a MsgUpdateParams message. // // Since: 0.47 message MsgUpdateParamsResponse {} diff --git a/proto/neutron/cron/v1/schedule.proto b/proto/neutron/cron/v1/schedule.proto new file mode 100644 index 000000000..8995431fe --- /dev/null +++ b/proto/neutron/cron/v1/schedule.proto @@ -0,0 +1,32 @@ +syntax = "proto3"; +package neutron.cron.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/neutron-org/neutron/v4/x/cron/types/v1"; + +// Defines the schedule for execution +message Schedule { + // Name of schedule + string name = 1; + // Period in blocks + uint64 period = 2; + // Msgs that will be executed every certain number of blocks, specified in the `period` field + repeated MsgExecuteContract msgs = 3 [(gogoproto.nullable) = false]; + // Last execution's block height + uint64 last_execute_height = 4; +} + +// Defines the contract and the message to pass +message MsgExecuteContract { + // The address of the smart contract + string contract = 1; + // JSON encoded message to be passed to the contract + string msg = 2; +} + +// Defines the number of current schedules +message ScheduleCount { + // The number of current schedules + int32 count = 1; +} diff --git a/wasmbinding/bindings/msg.go b/wasmbinding/bindings/msg.go index 2aee5622a..8c57b202a 100644 --- a/wasmbinding/bindings/msg.go +++ b/wasmbinding/bindings/msg.go @@ -196,9 +196,10 @@ type ForceTransfer struct { // AddSchedule adds new schedule to the cron module type AddSchedule struct { - Name string `json:"name"` - Period uint64 `json:"period"` - Msgs []MsgExecuteContract `json:"msgs"` + Name string `json:"name"` + Period uint64 `json:"period"` + Msgs []MsgExecuteContract `json:"msgs"` + ExecutionStage string `json:"execution_stage"` } // AddScheduleResponse holds response AddSchedule diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index 30d53717d..8e00248d9 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -73,7 +73,8 @@ func CustomMessageDecorator( Adminserver: adminmodulekeeper.NewMsgServerImpl(*adminKeeper), Bank: bankKeeper, TokenFactory: tokenFactoryKeeper, - CronKeeper: cronKeeper, + CronMsgServer: cronkeeper.NewMsgServerImpl(*cronKeeper), + CronQueryServer: cronKeeper, AdminKeeper: adminKeeper, ContractmanagerKeeper: contractmanagerKeeper, DexMsgServer: dexkeeper.NewMsgServerImpl(*dexKeeper), @@ -90,7 +91,8 @@ type CustomMessenger struct { Adminserver admintypes.MsgServer Bank *bankkeeper.BaseKeeper TokenFactory *tokenfactorykeeper.Keeper - CronKeeper *cronkeeper.Keeper + CronMsgServer crontypes.MsgServer + CronQueryServer crontypes.QueryServer AdminKeeper *adminmodulekeeper.Keeper ContractmanagerKeeper *contractmanagerkeeper.Keeper DexMsgServer dextypes.MsgServer @@ -989,6 +991,8 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin can add schedule") } + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + msgs := make([]crontypes.MsgExecuteContract, 0, len(addSchedule.Msgs)) for _, msg := range addSchedule.Msgs { msgs = append(msgs, crontypes.MsgExecuteContract{ @@ -997,13 +1001,20 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre }) } - err := m.CronKeeper.AddSchedule(ctx, addSchedule.Name, addSchedule.Period, msgs) + _, err := m.CronMsgServer.AddSchedule(ctx, &crontypes.MsgAddSchedule{ + Authority: authority.String(), + Name: addSchedule.Name, + Period: addSchedule.Period, + Msgs: msgs, + ExecutionStage: crontypes.ExecutionStage(crontypes.ExecutionStage_value[addSchedule.ExecutionStage]), + }) if err != nil { ctx.Logger().Error("failed to addSchedule", "from_address", contractAddr.String(), + "name", addSchedule.Name, "error", err, ) - return nil, nil, nil, errors.Wrap(err, "marshal json failed") + return nil, nil, nil, errors.Wrapf(err, "failed to add %s schedule", addSchedule.Name) } ctx.Logger().Debug("schedule added", @@ -1016,12 +1027,30 @@ func (m *CustomMessenger) addSchedule(ctx sdk.Context, contractAddr sdk.AccAddre } func (m *CustomMessenger) removeSchedule(ctx sdk.Context, contractAddr sdk.AccAddress, removeSchedule *bindings.RemoveSchedule) ([]sdk.Event, [][]byte, [][]*types.Any, error) { - params := m.CronKeeper.GetParams(ctx) - if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.SecurityAddress { + params, err := m.CronQueryServer.Params(ctx, &crontypes.QueryParamsRequest{}) + if err != nil { + ctx.Logger().Error("failed to removeSchedule", "error", err) + return nil, nil, nil, errors.Wrap(err, "failed to removeSchedule") + } + + if !m.isAdmin(ctx, contractAddr) && contractAddr.String() != params.Params.SecurityAddress { return nil, nil, nil, errors.Wrap(sdkerrors.ErrUnauthorized, "only admin or security dao can remove schedule") } - m.CronKeeper.RemoveSchedule(ctx, removeSchedule.Name) + authority := authtypes.NewModuleAddress(admintypes.ModuleName) + + _, err = m.CronMsgServer.RemoveSchedule(ctx, &crontypes.MsgRemoveSchedule{ + Authority: authority.String(), + Name: removeSchedule.Name, + }) + if err != nil { + ctx.Logger().Error("failed to removeSchedule", + "from_address", contractAddr.String(), + "name", removeSchedule.Name, + "error", err, + ) + return nil, nil, nil, errors.Wrapf(err, "failed to remove %s schedule", removeSchedule.Name) + } ctx.Logger().Debug("schedule removed", "from_address", contractAddr.String(), diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 446c7159f..fe15d1d10 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -6,6 +6,7 @@ import ( "testing" contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" + types2 "github.com/neutron-org/neutron/v4/x/cron/types" "cosmossdk.io/math" wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" @@ -23,6 +24,8 @@ import ( adminkeeper "github.com/cosmos/admin-module/v2/x/adminmodule/keeper" + cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" + "github.com/neutron-org/neutron/v4/app/params" "github.com/CosmWasm/wasmd/x/wasm/keeper" @@ -67,7 +70,8 @@ func (suite *CustomMessengerTestSuite) SetupTest() { suite.messenger.Adminserver = adminkeeper.NewMsgServerImpl(suite.neutron.AdminmoduleKeeper) suite.messenger.Bank = &suite.neutron.BankKeeper suite.messenger.TokenFactory = suite.neutron.TokenFactoryKeeper - suite.messenger.CronKeeper = &suite.neutron.CronKeeper + suite.messenger.CronMsgServer = cronkeeper.NewMsgServerImpl(suite.neutron.CronKeeper) + suite.messenger.CronQueryServer = suite.neutron.CronKeeper suite.messenger.AdminKeeper = &suite.neutron.AdminmoduleKeeper suite.messenger.ContractmanagerKeeper = &suite.neutron.ContractManagerKeeper suite.contractOwner = keeper.RandomAccountAddress(suite.T()) @@ -718,6 +722,10 @@ func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { }, } + schedule, ok := suite.neutron.CronKeeper.GetSchedule(suite.ctx, "schedule1") + suite.True(ok) + suite.Equal(types2.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, schedule.ExecutionStage) + // Dispatch AddSchedule message _, err = suite.executeNeutronMsg(suite.contractAddress, msg) suite.NoError(err) diff --git a/x/cron/genesis.go b/x/cron/genesis.go index 974790399..525840e26 100644 --- a/x/cron/genesis.go +++ b/x/cron/genesis.go @@ -11,7 +11,7 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { // Set all the schedules for _, elem := range genState.ScheduleList { - err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs) + err := k.AddSchedule(ctx, elem.Name, elem.Period, elem.Msgs, elem.ExecutionStage) if err != nil { panic(err) } diff --git a/x/cron/keeper/grpc_query_schedule_test.go b/x/cron/keeper/grpc_query_schedule_test.go index b778f8fba..a132fc8d4 100644 --- a/x/cron/keeper/grpc_query_schedule_test.go +++ b/x/cron/keeper/grpc_query_schedule_test.go @@ -133,8 +133,9 @@ func createNSchedule(t *testing.T, ctx sdk.Context, k *cronkeeper.Keeper, n int3 item.Period = 1000 item.Msgs = nil item.LastExecuteHeight = uint64(ctx.BlockHeight()) + item.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) res[idx] = item diff --git a/x/cron/keeper/keeper.go b/x/cron/keeper/keeper.go index 2be2f49ee..070f18b2d 100644 --- a/x/cron/keeper/keeper.go +++ b/x/cron/keeper/keeper.go @@ -66,10 +66,9 @@ func (k *Keeper) Logger(ctx sdk.Context) log.Logger { // ExecuteReadySchedules gets all schedules that are due for execution (with limit that is equal to Params.Limit) // and executes messages in each one -// NOTE that errors in contract calls rollback all already executed messages -func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context) { +func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context, executionStage types.ExecutionStage) { telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), LabelExecuteReadySchedules) - schedules := k.getSchedulesReadyForExecution(ctx) + schedules := k.getSchedulesReadyForExecution(ctx, executionStage) for _, schedule := range schedules { err := k.executeSchedule(ctx, schedule) @@ -77,9 +76,15 @@ func (k *Keeper) ExecuteReadySchedules(ctx sdk.Context) { } } -// AddSchedule adds new schedule to execution for every block `period`. +// AddSchedule adds a new schedule to be executed every certain number of blocks, specified in the `period`. // First schedule execution is supposed to be on `now + period` block. -func (k *Keeper) AddSchedule(ctx sdk.Context, name string, period uint64, msgs []types.MsgExecuteContract) error { +func (k *Keeper) AddSchedule( + ctx sdk.Context, + name string, + period uint64, + msgs []types.MsgExecuteContract, + executionStage types.ExecutionStage, +) error { if k.scheduleExists(ctx, name) { return fmt.Errorf("schedule already exists with name=%v", name) } @@ -89,7 +94,9 @@ func (k *Keeper) AddSchedule(ctx sdk.Context, name string, period uint64, msgs [ Period: period, Msgs: msgs, LastExecuteHeight: uint64(ctx.BlockHeight()), // let's execute newly added schedule on `now + period` block + ExecutionStage: executionStage, } + k.storeSchedule(ctx, schedule) k.changeTotalCount(ctx, 1) @@ -141,7 +148,7 @@ func (k *Keeper) GetScheduleCount(ctx sdk.Context) int32 { return k.getScheduleCount(ctx) } -func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule { +func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context, executionStage types.ExecutionStage) []types.Schedule { params := k.GetParams(ctx) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ScheduleKey) count := uint64(0) @@ -155,7 +162,7 @@ func (k *Keeper) getSchedulesReadyForExecution(ctx sdk.Context) []types.Schedule var schedule types.Schedule k.cdc.MustUnmarshal(iterator.Value(), &schedule) - if k.intervalPassed(ctx, schedule) { + if k.intervalPassed(ctx, schedule) && schedule.ExecutionStage == executionStage { res = append(res, schedule) count++ diff --git a/x/cron/keeper/keeper_test.go b/x/cron/keeper/keeper_test.go index 8abe2060c..d58553c56 100644 --- a/x/cron/keeper/keeper_test.go +++ b/x/cron/keeper/keeper_test.go @@ -44,7 +44,7 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { schedules := []types.Schedule{ { Name: "1_unready1", - Period: 3, + Period: 10, Msgs: []types.MsgExecuteContract{ { Contract: "1_neutron", @@ -52,10 +52,11 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 4, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "2_ready1", - Period: 3, + Period: 4, Msgs: []types.MsgExecuteContract{ { Contract: "2_neutron", @@ -63,10 +64,11 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "3_ready2", - Period: 3, + Period: 4, Msgs: []types.MsgExecuteContract{ { Contract: "3_neutron", @@ -74,12 +76,14 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "4_unready2", - Period: 3, + Period: 10, Msgs: []types.MsgExecuteContract{}, LastExecuteHeight: 4, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, }, { Name: "5_ready3", @@ -91,22 +95,34 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { }, }, LastExecuteHeight: 0, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + { + Name: "6_ready4", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "6_neutron", + Msg: "6_msg", + }, + }, + LastExecuteHeight: 0, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, }, } for _, item := range schedules { ctx = ctx.WithBlockHeight(int64(item.LastExecuteHeight)) - err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs) + err := k.AddSchedule(ctx, item.Name, item.Period, item.Msgs, item.ExecutionStage) require.NoError(t, err) } count := k.GetScheduleCount(ctx) - require.Equal(t, count, int32(5)) + require.Equal(t, count, int32(6)) ctx = ctx.WithBlockHeight(5) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr).AnyTimes() wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "2_neutron", @@ -120,25 +136,26 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) unready1, _ := k.GetSchedule(ctx, "1_unready1") ready1, _ := k.GetSchedule(ctx, "2_ready1") ready2, _ := k.GetSchedule(ctx, "3_ready2") unready2, _ := k.GetSchedule(ctx, "4_unready2") ready3, _ := k.GetSchedule(ctx, "5_ready3") + ready4, _ := k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(0), ready3.LastExecuteHeight) + require.Equal(t, uint64(0), ready4.LastExecuteHeight) // let's make another call at the next height // Notice that now only one ready schedule left because we got limit of 2 at once ctx = ctx.WithBlockHeight(6) - accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(addr) wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ Sender: testutil.TestOwnerAddress, Contract: "5_neutron", @@ -146,19 +163,46 @@ func TestKeeperExecuteReadySchedules(t *testing.T) { Funds: sdk.NewCoins(), }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) - k.ExecuteReadySchedules(ctx) + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) unready1, _ = k.GetSchedule(ctx, "1_unready1") ready1, _ = k.GetSchedule(ctx, "2_ready1") ready2, _ = k.GetSchedule(ctx, "3_ready2") unready2, _ = k.GetSchedule(ctx, "4_unready2") ready3, _ = k.GetSchedule(ctx, "5_ready3") + ready4, _ = k.GetSchedule(ctx, "6_ready4") require.Equal(t, uint64(4), unready1.LastExecuteHeight) require.Equal(t, uint64(5), ready1.LastExecuteHeight) require.Equal(t, uint64(5), ready2.LastExecuteHeight) require.Equal(t, uint64(4), unready2.LastExecuteHeight) require.Equal(t, uint64(6), ready3.LastExecuteHeight) + require.Equal(t, uint64(0), ready4.LastExecuteHeight) + + ctx = ctx.WithBlockHeight(7) + + wasmMsgServer.EXPECT().ExecuteContract(gomock.Any(), &wasmtypes.MsgExecuteContract{ + Sender: testutil.TestOwnerAddress, + Contract: "6_neutron", + Msg: []byte("6_msg"), + Funds: sdk.NewCoins(), + }).Return(&wasmtypes.MsgExecuteContractResponse{}, nil) + + k.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) + + unready1, _ = k.GetSchedule(ctx, "1_unready1") + ready1, _ = k.GetSchedule(ctx, "2_ready1") + ready2, _ = k.GetSchedule(ctx, "3_ready2") + unready2, _ = k.GetSchedule(ctx, "4_unready2") + ready3, _ = k.GetSchedule(ctx, "5_ready3") + ready4, _ = k.GetSchedule(ctx, "6_ready4") + + require.Equal(t, uint64(4), unready1.LastExecuteHeight) + require.Equal(t, uint64(5), ready1.LastExecuteHeight) + require.Equal(t, uint64(5), ready2.LastExecuteHeight) + require.Equal(t, uint64(4), unready2.LastExecuteHeight) + require.Equal(t, uint64(6), ready3.LastExecuteHeight) + require.Equal(t, uint64(7), ready4.LastExecuteHeight) } func TestAddSchedule(t *testing.T) { @@ -183,11 +227,19 @@ func TestAddSchedule(t *testing.T) { Contract: "c", Msg: "m", }, - }) + }, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + require.NoError(t, err) + + err = k.AddSchedule(ctx, "b", 7, []types.MsgExecuteContract{ + { + Contract: "c", + Msg: "m", + }, + }, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.NoError(t, err) // second time with same name returns error - err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}) + err = k.AddSchedule(ctx, "a", 5, []types.MsgExecuteContract{}, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) require.Error(t, err) scheduleA, found := k.GetSchedule(ctx, "a") @@ -197,6 +249,12 @@ func TestAddSchedule(t *testing.T) { require.Equal(t, scheduleA.Msgs, []types.MsgExecuteContract{ {Contract: "c", Msg: "m"}, }) + require.Equal(t, scheduleA.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + + schedules := k.GetAllSchedules(ctx) + require.Len(t, schedules, 2) + require.Equal(t, schedules[0].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + require.Equal(t, schedules[1].ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) // remove schedule works k.RemoveSchedule(ctx, "a") @@ -223,9 +281,10 @@ func TestGetAllSchedules(t *testing.T) { Period: 5, Msgs: nil, LastExecuteHeight: uint64(ctx.BlockHeight()), + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER, } expectedSchedules = append(expectedSchedules, s) - err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs) + err := k.AddSchedule(ctx, s.Name, s.Period, s.Msgs, s.ExecutionStage) require.NoError(t, err) } diff --git a/x/cron/keeper/migrations.go b/x/cron/keeper/migrations.go new file mode 100644 index 000000000..0166a8da9 --- /dev/null +++ b/x/cron/keeper/migrations.go @@ -0,0 +1,22 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + keeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(keeper Keeper) Migrator { + return Migrator{keeper: keeper} +} + +// Migrate1to2 migrates from version 1 to 2. +func (m Migrator) Migrate1to2(ctx sdk.Context) error { + return v2.MigrateStore(ctx, m.keeper.cdc, m.keeper.storeKey) +} diff --git a/x/cron/keeper/msg_server.go b/x/cron/keeper/msg_server.go index e49e578ab..c42a0d1c4 100644 --- a/x/cron/keeper/msg_server.go +++ b/x/cron/keeper/msg_server.go @@ -11,30 +11,66 @@ import ( ) type msgServer struct { - Keeper + keeper Keeper } // NewMsgServerImpl returns an implementation of the MsgServer interface // for the provided Keeper. func NewMsgServerImpl(keeper Keeper) types.MsgServer { - return &msgServer{Keeper: keeper} + return &msgServer{keeper: keeper} } var _ types.MsgServer = msgServer{} +// AddSchedule adds new schedule +func (k msgServer) AddSchedule(goCtx context.Context, req *types.MsgAddSchedule) (*types.MsgAddScheduleResponse, error) { + if err := req.Validate(); err != nil { + return nil, errors.Wrap(err, "failed to validate MsgAddSchedule") + } + + authority := k.keeper.GetAuthority() + if authority != req.Authority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + if err := k.keeper.AddSchedule(ctx, req.Name, req.Period, req.Msgs, req.ExecutionStage); err != nil { + return nil, errors.Wrap(err, "failed to add schedule") + } + + return &types.MsgAddScheduleResponse{}, nil +} + +// RemoveSchedule removes schedule +func (k msgServer) RemoveSchedule(goCtx context.Context, req *types.MsgRemoveSchedule) (*types.MsgRemoveScheduleResponse, error) { + if err := req.Validate(); err != nil { + return nil, errors.Wrap(err, "failed to validate MsgRemoveSchedule") + } + + authority := k.keeper.GetAuthority() + if authority != req.Authority { + return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + k.keeper.RemoveSchedule(ctx, req.Name) + + return &types.MsgRemoveScheduleResponse{}, nil +} + // UpdateParams updates the module parameters -func (k Keeper) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { +func (k msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { if err := req.Validate(); err != nil { return nil, errors.Wrap(err, "failed to validate MsgUpdateParams") } - authority := k.GetAuthority() + authority := k.keeper.GetAuthority() if authority != req.Authority { return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid authority; expected %s, got %s", authority, req.Authority) } ctx := sdk.UnwrapSDKContext(goCtx) - if err := k.SetParams(ctx, req.Params); err != nil { + if err := k.keeper.SetParams(ctx, req.Params); err != nil { return nil, err } diff --git a/x/cron/keeper/msg_server_test.go b/x/cron/keeper/msg_server_test.go index 17a3655ac..ef10b1ffc 100644 --- a/x/cron/keeper/msg_server_test.go +++ b/x/cron/keeper/msg_server_test.go @@ -6,12 +6,171 @@ import ( "github.com/stretchr/testify/require" "github.com/neutron-org/neutron/v4/testutil" - "github.com/neutron-org/neutron/v4/testutil/cron/keeper" + testkeeper "github.com/neutron-org/neutron/v4/testutil/cron/keeper" + cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" "github.com/neutron-org/neutron/v4/x/cron/types" ) +func TestMsgAddScheduleValidate(t *testing.T) { + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) + + tests := []struct { + name string + msg types.MsgAddSchedule + expectedErr string + }{ + { + "empty authority", + types.MsgAddSchedule{ + Authority: "", + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + "authority is invalid", + }, + { + "invalid authority", + types.MsgAddSchedule{ + Authority: "invalid authority", + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + "authority is invalid", + }, + { + "invalid name", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + "name is invalid", + }, + { + "invalid period", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 0, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + "period is invalid", + }, + { + "empty msgs", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{}, + ExecutionStage: types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER, + }, + "msgs should not be empty", + }, + { + "invalid execution stage", + types.MsgAddSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "name", + Period: 3, + Msgs: []types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + ExecutionStage: 7, + }, + "execution stage is invalid", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + resp, err := msgServer.AddSchedule(ctx, &tt.msg) + require.ErrorContains(t, err, tt.expectedErr) + require.Nil(t, resp) + }) + } +} + +func TestMsgRemoveScheduleValidate(t *testing.T) { + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) + + tests := []struct { + name string + msg types.MsgRemoveSchedule + expectedErr string + }{ + { + "empty authority", + types.MsgRemoveSchedule{ + Authority: "", + Name: "name", + }, + "authority is invalid", + }, + { + "invalid authority", + types.MsgRemoveSchedule{ + Authority: "invalid authority", + Name: "name", + }, + "authority is invalid", + }, + { + "invalid name", + types.MsgRemoveSchedule{ + Authority: testutil.TestOwnerAddress, + Name: "", + }, + "name is invalid", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + resp, err := msgServer.RemoveSchedule(ctx, &tt.msg) + require.ErrorContains(t, err, tt.expectedErr) + require.Nil(t, resp) + }) + } +} + func TestMsgUpdateParamsValidate(t *testing.T) { - k, ctx := keeper.CronKeeper(t, nil, nil) + k, ctx := testkeeper.CronKeeper(t, nil, nil) + msgServer := cronkeeper.NewMsgServerImpl(*k) tests := []struct { name string @@ -57,7 +216,7 @@ func TestMsgUpdateParamsValidate(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - resp, err := k.UpdateParams(ctx, &tt.msg) + resp, err := msgServer.UpdateParams(ctx, &tt.msg) require.ErrorContains(t, err, tt.expectedErr) require.Nil(t, resp) }) diff --git a/x/cron/migrations/v2/store.go b/x/cron/migrations/v2/store.go new file mode 100644 index 000000000..f3311aba0 --- /dev/null +++ b/x/cron/migrations/v2/store.go @@ -0,0 +1,56 @@ +package v2 + +import ( + "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/neutron-org/neutron/v4/x/cron/types" +) + +// MigrateStore performs in-place store migrations. +// The migration adds execution stage for schedules. +func MigrateStore(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + return migrateSchedules(ctx, cdc, storeKey) +} + +type migrationUpdate struct { + key []byte + val []byte +} + +func migrateSchedules(ctx sdk.Context, cdc codec.BinaryCodec, storeKey storetypes.StoreKey) error { + ctx.Logger().Info("Migrating cron Schedules...") + + store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) + iterator := storetypes.KVStorePrefixIterator(store, []byte{}) + schedulesToUpdate := make([]migrationUpdate, 0) + + for ; iterator.Valid(); iterator.Next() { + var schedule types.Schedule + cdc.MustUnmarshal(iterator.Value(), &schedule) + // Set execution in EndBlocker + schedule.ExecutionStage = types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER + + schedulesToUpdate = append(schedulesToUpdate, migrationUpdate{ + key: iterator.Key(), + val: cdc.MustMarshal(&schedule), + }) + } + + err := iterator.Close() + if err != nil { + return errors.Wrap(err, "iterator failed to close during migration") + } + + // Store the updated Schedules + for _, v := range schedulesToUpdate { + store.Set(v.key, v.val) + } + + ctx.Logger().Info("Finished migrating cron Schedules...") + + return nil +} diff --git a/x/cron/migrations/v2/store_test.go b/x/cron/migrations/v2/store_test.go new file mode 100644 index 000000000..6b6f46355 --- /dev/null +++ b/x/cron/migrations/v2/store_test.go @@ -0,0 +1,60 @@ +package v2_test + +import ( + "testing" + + "cosmossdk.io/store/prefix" + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v4/testutil" + v2 "github.com/neutron-org/neutron/v4/x/cron/migrations/v2" + "github.com/neutron-org/neutron/v4/x/cron/types" + v1types "github.com/neutron-org/neutron/v4/x/cron/types/v1" +) + +type V2CronMigrationTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(V2CronMigrationTestSuite)) +} + +func (suite *V2CronMigrationTestSuite) TestScheduleUpgrade() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + storeKey = app.GetKey(types.StoreKey) + ctx = suite.ChainA.GetContext() + cdc = app.AppCodec() + ) + + schedule := v1types.Schedule{ + Name: "name", + Period: 3, + Msgs: []v1types.MsgExecuteContract{ + { + Contract: "contract", + Msg: "msg", + }, + }, + LastExecuteHeight: 1, + } + + store := prefix.NewStore(ctx.KVStore(storeKey), types.ScheduleKey) + bz := cdc.MustMarshal(&schedule) + store.Set(types.GetScheduleKey(schedule.Name), bz) + + // Run migration + suite.NoError(v2.MigrateStore(ctx, cdc, storeKey)) + + // Check Schedule has correct ExecutionStage + newSchedule, _ := app.CronKeeper.GetSchedule(ctx, schedule.Name) + suite.Equal(newSchedule.Name, schedule.Name) + suite.Equal(newSchedule.Period, schedule.Period) + for i, msg := range newSchedule.Msgs { + suite.Equal(msg.Contract, schedule.Msgs[i].Contract) + suite.Equal(msg.Msg, schedule.Msgs[i].Msg) + } + suite.Equal(newSchedule.LastExecuteHeight, schedule.LastExecuteHeight) + suite.Equal(newSchedule.ExecutionStage, types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) +} diff --git a/x/cron/module.go b/x/cron/module.go index 60dc09b91..3471b0379 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -155,10 +155,12 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block -func (am AppModule) BeginBlock(_ sdk.Context) {} +func (am AppModule) BeginBlock(ctx sdk.Context) { + am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) +} // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { - am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx)) + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) return []abci.ValidatorUpdate{}, nil } diff --git a/x/cron/types/codec.go b/x/cron/types/codec.go index a52eff2c6..6772e97b9 100644 --- a/x/cron/types/codec.go +++ b/x/cron/types/codec.go @@ -15,6 +15,8 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { registry.RegisterImplementations( (*sdk.Msg)(nil), &MsgUpdateParams{}, + &MsgAddSchedule{}, + &MsgRemoveSchedule{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/cron/types/genesis.pb.go b/x/cron/types/genesis.pb.go index 2d3546994..274598ad7 100644 --- a/x/cron/types/genesis.pb.go +++ b/x/cron/types/genesis.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// GenesisState defines the cron module's genesis state. +// Defines the cron module's genesis state. type GenesisState struct { ScheduleList []Schedule `protobuf:"bytes,2,rep,name=scheduleList,proto3" json:"scheduleList"` Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` diff --git a/x/cron/types/params.pb.go b/x/cron/types/params.pb.go index c71904ce8..e927ec42a 100644 --- a/x/cron/types/params.pb.go +++ b/x/cron/types/params.pb.go @@ -23,7 +23,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// Params defines the parameters for the module. +// Defines the parameters for the module. type Params struct { // Security address that can remove schedules SecurityAddress string `protobuf:"bytes,1,opt,name=security_address,json=securityAddress,proto3" json:"security_address,omitempty"` diff --git a/x/cron/types/query.pb.go b/x/cron/types/query.pb.go index c34c6c3f9..912a44eaa 100644 --- a/x/cron/types/query.pb.go +++ b/x/cron/types/query.pb.go @@ -30,6 +30,7 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// The request type for the Query/Params RPC method. type QueryParamsRequest struct { } @@ -66,6 +67,7 @@ func (m *QueryParamsRequest) XXX_DiscardUnknown() { var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo +// The response type for the Query/Params RPC method. type QueryParamsResponse struct { // params holds all the parameters of this module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` @@ -111,6 +113,7 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +// The request type for the Query/Schedule RPC method. type QueryGetScheduleRequest struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` } @@ -155,6 +158,7 @@ func (m *QueryGetScheduleRequest) GetName() string { return "" } +// The response type for the Query/Params RPC method. type QueryGetScheduleResponse struct { Schedule Schedule `protobuf:"bytes,1,opt,name=schedule,proto3" json:"schedule"` } @@ -199,6 +203,7 @@ func (m *QueryGetScheduleResponse) GetSchedule() Schedule { return Schedule{} } +// The request type for the Query/Schedules RPC method. type QuerySchedulesRequest struct { Pagination *query.PageRequest `protobuf:"bytes,1,opt,name=pagination,proto3" json:"pagination,omitempty"` } @@ -243,6 +248,7 @@ func (m *QuerySchedulesRequest) GetPagination() *query.PageRequest { return nil } +// The response type for the Query/Params RPC method. type QuerySchedulesResponse struct { Schedules []Schedule `protobuf:"bytes,1,rep,name=schedules,proto3" json:"schedules"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` diff --git a/x/cron/types/schedule.pb.go b/x/cron/types/schedule.pb.go index cda29cf72..845a1059a 100644 --- a/x/cron/types/schedule.pb.go +++ b/x/cron/types/schedule.pb.go @@ -23,15 +23,46 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// Defines when messages will be executed in the block +type ExecutionStage int32 + +const ( + // Execution at the end of the block + ExecutionStage_EXECUTION_STAGE_END_BLOCKER ExecutionStage = 0 + // Execution at the beginning of the block + ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER ExecutionStage = 1 +) + +var ExecutionStage_name = map[int32]string{ + 0: "EXECUTION_STAGE_END_BLOCKER", + 1: "EXECUTION_STAGE_BEGIN_BLOCKER", +} + +var ExecutionStage_value = map[string]int32{ + "EXECUTION_STAGE_END_BLOCKER": 0, + "EXECUTION_STAGE_BEGIN_BLOCKER": 1, +} + +func (x ExecutionStage) String() string { + return proto.EnumName(ExecutionStage_name, int32(x)) +} + +func (ExecutionStage) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_49ace1b59de613ef, []int{0} +} + +// Defines the schedule for execution type Schedule struct { // Name of schedule Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Period in blocks Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` - // Msgs that will be executed every period amount of time + // Msgs that will be executed every certain number of blocks, specified in the `period` field Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` // Last execution's block height LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` + // Stage when messages will be executed + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` } func (m *Schedule) Reset() { *m = Schedule{} } @@ -95,10 +126,18 @@ func (m *Schedule) GetLastExecuteHeight() uint64 { return 0 } +func (m *Schedule) GetExecutionStage() ExecutionStage { + if m != nil { + return m.ExecutionStage + } + return ExecutionStage_EXECUTION_STAGE_END_BLOCKER +} + +// Defines the contract and the message to pass type MsgExecuteContract struct { - // Contract is the address of the smart contract + // The address of the smart contract Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` - // Msg is json encoded message to be passed to the contract + // JSON encoded message to be passed to the contract Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` } @@ -149,8 +188,9 @@ func (m *MsgExecuteContract) GetMsg() string { return "" } +// Defines the number of current schedules type ScheduleCount struct { - // Count is the number of current schedules + // The number of current schedules Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` } @@ -195,6 +235,7 @@ func (m *ScheduleCount) GetCount() int32 { } func init() { + proto.RegisterEnum("neutron.cron.ExecutionStage", ExecutionStage_name, ExecutionStage_value) proto.RegisterType((*Schedule)(nil), "neutron.cron.Schedule") proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.MsgExecuteContract") proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.ScheduleCount") @@ -203,27 +244,32 @@ func init() { func init() { proto.RegisterFile("neutron/cron/schedule.proto", fileDescriptor_49ace1b59de613ef) } var fileDescriptor_49ace1b59de613ef = []byte{ - // 309 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xfb, 0x30, - 0x18, 0xc6, 0x9b, 0xff, 0xba, 0xb1, 0xe5, 0xaf, 0xa0, 0x71, 0x48, 0x99, 0x10, 0x4b, 0x41, 0xe8, - 0xc5, 0x14, 0xd4, 0x93, 0xc7, 0x0e, 0x61, 0x17, 0x2f, 0xf5, 0xe6, 0x65, 0x74, 0x59, 0x48, 0x0b, - 0x6b, 0x53, 0x9a, 0x54, 0xe6, 0xb7, 0xf0, 0x33, 0xf8, 0x69, 0x76, 0xdc, 0xd1, 0x93, 0x48, 0xfb, - 0x45, 0x24, 0x69, 0x26, 0x82, 0x97, 0xf0, 0x7b, 0x78, 0xde, 0x27, 0xef, 0xfb, 0x26, 0xf0, 0xa2, - 0x64, 0x8d, 0xaa, 0x45, 0x19, 0x51, 0x7d, 0x48, 0x9a, 0xb1, 0x75, 0xb3, 0x61, 0xa4, 0xaa, 0x85, - 0x12, 0xe8, 0xc8, 0x9a, 0x44, 0x9b, 0xb3, 0x29, 0x17, 0x5c, 0x18, 0x23, 0xd2, 0xd4, 0xd7, 0x04, - 0xef, 0x00, 0x8e, 0x9f, 0x6c, 0x0c, 0x21, 0xe8, 0x96, 0x69, 0xc1, 0x3c, 0xe0, 0x83, 0x70, 0x92, - 0x18, 0x46, 0xe7, 0x70, 0x54, 0xb1, 0x3a, 0x17, 0x6b, 0xef, 0x9f, 0x0f, 0x42, 0x37, 0xb1, 0x0a, - 0xdd, 0x43, 0xb7, 0x90, 0x5c, 0x7a, 0x03, 0x7f, 0x10, 0xfe, 0xbf, 0xf1, 0xc9, 0xef, 0x5e, 0xe4, - 0x51, 0xf2, 0x87, 0x2d, 0xa3, 0x8d, 0x62, 0x73, 0x51, 0xaa, 0x3a, 0xa5, 0x2a, 0x76, 0x77, 0x9f, - 0x97, 0x4e, 0x62, 0x32, 0x88, 0xc0, 0xb3, 0x4d, 0x2a, 0xd5, 0x92, 0xf5, 0x35, 0xcb, 0x8c, 0xe5, - 0x3c, 0x53, 0x9e, 0x6b, 0x1a, 0x9c, 0x6a, 0xcb, 0xa6, 0x17, 0xc6, 0x08, 0x62, 0x88, 0xfe, 0xde, - 0x88, 0x66, 0x70, 0x4c, 0x2d, 0xdb, 0x89, 0x7f, 0x34, 0x3a, 0x81, 0x83, 0x42, 0x72, 0x33, 0xf2, - 0x24, 0xd1, 0x18, 0x5c, 0xc1, 0xe3, 0xc3, 0x9e, 0x73, 0xd1, 0x94, 0x0a, 0x4d, 0xe1, 0x90, 0x6a, - 0x30, 0xd9, 0x61, 0xd2, 0x8b, 0x78, 0xb1, 0x6b, 0x31, 0xd8, 0xb7, 0x18, 0x7c, 0xb5, 0x18, 0xbc, - 0x75, 0xd8, 0xd9, 0x77, 0xd8, 0xf9, 0xe8, 0xb0, 0xf3, 0x4c, 0x78, 0xae, 0xb2, 0x66, 0x45, 0xa8, - 0x28, 0x22, 0xbb, 0xec, 0xb5, 0xa8, 0xf9, 0x81, 0xa3, 0x97, 0xbb, 0x68, 0xdb, 0x7f, 0x83, 0x7a, - 0xad, 0x98, 0x5c, 0x8d, 0xcc, 0x03, 0xdf, 0x7e, 0x07, 0x00, 0x00, 0xff, 0xff, 0x4e, 0x19, 0x38, - 0x8d, 0xa3, 0x01, 0x00, 0x00, + // 393 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0xc1, 0xaa, 0xd3, 0x40, + 0x18, 0x85, 0x33, 0x36, 0x2d, 0xed, 0xa8, 0xb5, 0x8e, 0x45, 0x42, 0xab, 0x69, 0x2c, 0x08, 0x41, + 0x30, 0x81, 0xea, 0xca, 0x9d, 0x89, 0x43, 0x5b, 0xd4, 0x16, 0xd2, 0x0a, 0xe2, 0x26, 0xa4, 0xe9, + 0x30, 0x09, 0x34, 0x99, 0x92, 0x99, 0x48, 0x7d, 0x0b, 0x1f, 0xab, 0xcb, 0x2e, 0x5d, 0x89, 0xb4, + 0x2b, 0xdf, 0xe2, 0x92, 0x49, 0x5a, 0x6e, 0xef, 0xdd, 0x84, 0x73, 0x38, 0xdf, 0xe1, 0x9f, 0xf9, + 0x33, 0xb0, 0x9f, 0x92, 0x5c, 0x64, 0x2c, 0xb5, 0xc3, 0xe2, 0xc3, 0xc3, 0x88, 0xac, 0xf3, 0x0d, + 0xb1, 0xb6, 0x19, 0x13, 0x0c, 0x3d, 0xaa, 0x42, 0xab, 0x08, 0x7b, 0x5d, 0xca, 0x28, 0x93, 0x81, + 0x5d, 0xa8, 0x92, 0x19, 0xfe, 0x07, 0xb0, 0xb9, 0xa8, 0x6a, 0x08, 0x41, 0x35, 0x0d, 0x12, 0xa2, + 0x01, 0x03, 0x98, 0x2d, 0x4f, 0x6a, 0xf4, 0x1c, 0x36, 0xb6, 0x24, 0x8b, 0xd9, 0x5a, 0x7b, 0x60, + 0x00, 0x53, 0xf5, 0x2a, 0x87, 0x3e, 0x40, 0x35, 0xe1, 0x94, 0x6b, 0x35, 0xa3, 0x66, 0x3e, 0x1c, + 0x19, 0xd6, 0xed, 0x59, 0xd6, 0x57, 0x4e, 0xf1, 0x8e, 0x84, 0xb9, 0x20, 0x2e, 0x4b, 0x45, 0x16, + 0x84, 0xc2, 0x51, 0xf7, 0x7f, 0x07, 0x8a, 0x27, 0x3b, 0xc8, 0x82, 0xcf, 0x36, 0x01, 0x17, 0x3e, + 0x29, 0x19, 0x3f, 0x22, 0x31, 0x8d, 0x84, 0xa6, 0xca, 0x01, 0x4f, 0x8b, 0xa8, 0x6a, 0x4f, 0x64, + 0x80, 0x30, 0x7c, 0x52, 0xa2, 0x31, 0x4b, 0x7d, 0x2e, 0x02, 0x4a, 0xb4, 0xba, 0x01, 0xcc, 0xf6, + 0xe8, 0xc5, 0xf5, 0x58, 0x7c, 0x86, 0x16, 0x05, 0xe3, 0xb5, 0xc9, 0x95, 0x1f, 0x3a, 0x10, 0xdd, + 0x3f, 0x18, 0xea, 0xc1, 0x66, 0x58, 0xe9, 0xea, 0xe2, 0x17, 0x8f, 0x3a, 0xb0, 0x96, 0x70, 0x2a, + 0x6f, 0xde, 0xf2, 0x0a, 0x39, 0x7c, 0x0d, 0x1f, 0x9f, 0xd7, 0xe5, 0xb2, 0x3c, 0x15, 0xa8, 0x0b, + 0xeb, 0x61, 0x21, 0x64, 0xb7, 0xee, 0x95, 0xe6, 0xcd, 0x12, 0xb6, 0xaf, 0x0f, 0x83, 0x06, 0xb0, + 0x8f, 0xbf, 0x63, 0xf7, 0xdb, 0x72, 0x3a, 0x9f, 0xf9, 0x8b, 0xe5, 0xc7, 0x31, 0xf6, 0xf1, 0xec, + 0x93, 0xef, 0x7c, 0x99, 0xbb, 0x9f, 0xb1, 0xd7, 0x51, 0xd0, 0x2b, 0xf8, 0xf2, 0x2e, 0xe0, 0xe0, + 0xf1, 0x74, 0x76, 0x41, 0x80, 0x33, 0xd9, 0x1f, 0x75, 0x70, 0x38, 0xea, 0xe0, 0xdf, 0x51, 0x07, + 0xbf, 0x4f, 0xba, 0x72, 0x38, 0xe9, 0xca, 0x9f, 0x93, 0xae, 0xfc, 0xb0, 0x68, 0x2c, 0xa2, 0x7c, + 0x65, 0x85, 0x2c, 0xb1, 0xab, 0x95, 0xbc, 0x65, 0x19, 0x3d, 0x6b, 0xfb, 0xe7, 0x7b, 0x7b, 0x57, + 0xbe, 0x11, 0xf1, 0x6b, 0x4b, 0xf8, 0xaa, 0x21, 0xff, 0xfe, 0xbb, 0x9b, 0x00, 0x00, 0x00, 0xff, + 0xff, 0x2e, 0xa9, 0x20, 0xa0, 0x40, 0x02, 0x00, 0x00, } func (m *Schedule) Marshal() (dAtA []byte, err error) { @@ -246,6 +292,11 @@ func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.ExecutionStage != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.ExecutionStage)) + i-- + dAtA[i] = 0x28 + } if m.LastExecuteHeight != 0 { i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) i-- @@ -378,6 +429,9 @@ func (m *Schedule) Size() (n int) { if m.LastExecuteHeight != 0 { n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) } + if m.ExecutionStage != 0 { + n += 1 + sovSchedule(uint64(m.ExecutionStage)) + } return n } @@ -549,6 +603,25 @@ func (m *Schedule) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) + } + m.ExecutionStage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipSchedule(dAtA[iNdEx:]) diff --git a/x/cron/types/tx.go b/x/cron/types/tx.go index eb48677cb..27b4ceec4 100644 --- a/x/cron/types/tx.go +++ b/x/cron/types/tx.go @@ -1,10 +1,95 @@ package types import ( - errorsmod "cosmossdk.io/errors" + "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) +var _ sdk.Msg = &MsgAddSchedule{} + +func (msg *MsgAddSchedule) Route() string { + return RouterKey +} + +func (msg *MsgAddSchedule) Type() string { + return "add-schedule" +} + +func (msg *MsgAddSchedule) GetSigners() []sdk.AccAddress { + authority, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { // should never happen as valid basic rejects invalid addresses + panic(err.Error()) + } + return []sdk.AccAddress{authority} +} + +func (msg *MsgAddSchedule) GetSignBytes() []byte { + return ModuleCdc.MustMarshalJSON(msg) +} + +func (msg *MsgAddSchedule) Validate() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errors.Wrap(err, "authority is invalid") + } + + if msg.Name == "" { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") + } + + if msg.Period == 0 { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "period is invalid") + } + + if len(msg.Msgs) == 0 { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "msgs should not be empty") + } + + if _, ok := ExecutionStage_name[int32(msg.ExecutionStage)]; !ok { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "execution stage is invalid") + } + + return nil +} + +//---------------------------------------------------------------- + +var _ sdk.Msg = &MsgRemoveSchedule{} + +func (msg *MsgRemoveSchedule) Route() string { + return RouterKey +} + +func (msg *MsgRemoveSchedule) Type() string { + return "remove-schedule" +} + +func (msg *MsgRemoveSchedule) GetSigners() []sdk.AccAddress { + authority, err := sdk.AccAddressFromBech32(msg.Authority) + if err != nil { // should never happen as valid basic rejects invalid addresses + panic(err.Error()) + } + return []sdk.AccAddress{authority} +} + +func (msg *MsgRemoveSchedule) GetSignBytes() []byte { + return ModuleCdc.MustMarshalJSON(msg) +} + +func (msg *MsgRemoveSchedule) Validate() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errors.Wrap(err, "authority is invalid") + } + + if msg.Name == "" { + return errors.Wrap(sdkerrors.ErrInvalidRequest, "name is invalid") + } + + return nil +} + +//---------------------------------------------------------------- + var _ sdk.Msg = &MsgUpdateParams{} func (msg *MsgUpdateParams) Route() string { @@ -29,11 +114,11 @@ func (msg *MsgUpdateParams) GetSignBytes() []byte { func (msg *MsgUpdateParams) Validate() error { if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { - return errorsmod.Wrap(err, "authority is invalid") + return errors.Wrap(err, "authority is invalid") } if _, err := sdk.AccAddressFromBech32(msg.Params.SecurityAddress); err != nil { - return errorsmod.Wrap(err, "security_address is invalid") + return errors.Wrap(err, "security_address is invalid") } return nil diff --git a/x/cron/types/tx.pb.go b/x/cron/types/tx.pb.go index 217bb879c..141735a4e 100644 --- a/x/cron/types/tx.pb.go +++ b/x/cron/types/tx.pb.go @@ -31,13 +31,224 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// MsgUpdateParams is the MsgUpdateParams request type. +// The MsgAddSchedule request type. +type MsgAddSchedule struct { + // The address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Name of the schedule + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // Period in blocks + Period uint64 `protobuf:"varint,3,opt,name=period,proto3" json:"period,omitempty"` + // Msgs that will be executed every certain number of blocks, specified in the `period` field + Msgs []MsgExecuteContract `protobuf:"bytes,4,rep,name=msgs,proto3" json:"msgs"` + // Stage when messages will be executed + ExecutionStage ExecutionStage `protobuf:"varint,5,opt,name=execution_stage,json=executionStage,proto3,enum=neutron.cron.ExecutionStage" json:"execution_stage,omitempty"` +} + +func (m *MsgAddSchedule) Reset() { *m = MsgAddSchedule{} } +func (m *MsgAddSchedule) String() string { return proto.CompactTextString(m) } +func (*MsgAddSchedule) ProtoMessage() {} +func (*MsgAddSchedule) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{0} +} +func (m *MsgAddSchedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddSchedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddSchedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddSchedule.Merge(m, src) +} +func (m *MsgAddSchedule) XXX_Size() int { + return m.Size() +} +func (m *MsgAddSchedule) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddSchedule.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddSchedule proto.InternalMessageInfo + +func (m *MsgAddSchedule) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgAddSchedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *MsgAddSchedule) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + +func (m *MsgAddSchedule) GetMsgs() []MsgExecuteContract { + if m != nil { + return m.Msgs + } + return nil +} + +func (m *MsgAddSchedule) GetExecutionStage() ExecutionStage { + if m != nil { + return m.ExecutionStage + } + return ExecutionStage_EXECUTION_STAGE_END_BLOCKER +} + +// Defines the response structure for executing a MsgAddSchedule message. +type MsgAddScheduleResponse struct { +} + +func (m *MsgAddScheduleResponse) Reset() { *m = MsgAddScheduleResponse{} } +func (m *MsgAddScheduleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAddScheduleResponse) ProtoMessage() {} +func (*MsgAddScheduleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{1} +} +func (m *MsgAddScheduleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAddScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAddScheduleResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAddScheduleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAddScheduleResponse.Merge(m, src) +} +func (m *MsgAddScheduleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAddScheduleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAddScheduleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAddScheduleResponse proto.InternalMessageInfo + +// The MsgRemoveSchedule request type. +type MsgRemoveSchedule struct { + // The address of the governance account. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // Name of the schedule + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` +} + +func (m *MsgRemoveSchedule) Reset() { *m = MsgRemoveSchedule{} } +func (m *MsgRemoveSchedule) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveSchedule) ProtoMessage() {} +func (*MsgRemoveSchedule) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{2} +} +func (m *MsgRemoveSchedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveSchedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveSchedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveSchedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveSchedule.Merge(m, src) +} +func (m *MsgRemoveSchedule) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveSchedule) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveSchedule.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveSchedule proto.InternalMessageInfo + +func (m *MsgRemoveSchedule) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgRemoveSchedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +// Defines the response structure for executing a MsgRemoveSchedule message. +type MsgRemoveScheduleResponse struct { +} + +func (m *MsgRemoveScheduleResponse) Reset() { *m = MsgRemoveScheduleResponse{} } +func (m *MsgRemoveScheduleResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRemoveScheduleResponse) ProtoMessage() {} +func (*MsgRemoveScheduleResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c9e0a673aba8d6fd, []int{3} +} +func (m *MsgRemoveScheduleResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRemoveScheduleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRemoveScheduleResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRemoveScheduleResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRemoveScheduleResponse.Merge(m, src) +} +func (m *MsgRemoveScheduleResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRemoveScheduleResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRemoveScheduleResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRemoveScheduleResponse proto.InternalMessageInfo + +// The MsgUpdateParams request type. // // Since: 0.47 type MsgUpdateParams struct { - // Authority is the address of the governance account. + // The address of the governance account. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // params defines the x/cron parameters to update. + // Defines the x/cron parameters to update. // // NOTE: All parameters must be supplied. Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` @@ -47,7 +258,7 @@ func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParams) ProtoMessage() {} func (*MsgUpdateParams) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{0} + return fileDescriptor_c9e0a673aba8d6fd, []int{4} } func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -90,8 +301,7 @@ func (m *MsgUpdateParams) GetParams() Params { return Params{} } -// MsgUpdateParamsResponse defines the response structure for executing a -// MsgUpdateParams message. +// Defines the response structure for executing a MsgUpdateParams message. // // Since: 0.47 type MsgUpdateParamsResponse struct { @@ -101,7 +311,7 @@ func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateParamsResponse) ProtoMessage() {} func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_c9e0a673aba8d6fd, []int{1} + return fileDescriptor_c9e0a673aba8d6fd, []int{5} } func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -131,6 +341,10 @@ func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo func init() { + proto.RegisterType((*MsgAddSchedule)(nil), "neutron.cron.MsgAddSchedule") + proto.RegisterType((*MsgAddScheduleResponse)(nil), "neutron.cron.MsgAddScheduleResponse") + proto.RegisterType((*MsgRemoveSchedule)(nil), "neutron.cron.MsgRemoveSchedule") + proto.RegisterType((*MsgRemoveScheduleResponse)(nil), "neutron.cron.MsgRemoveScheduleResponse") proto.RegisterType((*MsgUpdateParams)(nil), "neutron.cron.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "neutron.cron.MsgUpdateParamsResponse") } @@ -138,28 +352,42 @@ func init() { func init() { proto.RegisterFile("neutron/cron/tx.proto", fileDescriptor_c9e0a673aba8d6fd) } var fileDescriptor_c9e0a673aba8d6fd = []byte{ - // 335 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0xcd, 0x4b, 0x2d, 0x2d, - 0x29, 0xca, 0xcf, 0xd3, 0x4f, 0x06, 0x11, 0x25, 0x15, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, - 0x3c, 0x50, 0x61, 0x3d, 0x90, 0xb0, 0x94, 0x60, 0x62, 0x6e, 0x66, 0x5e, 0xbe, 0x3e, 0x98, 0x84, - 0x28, 0x90, 0x12, 0x4f, 0xce, 0x2f, 0xce, 0xcd, 0x2f, 0xd6, 0xcf, 0x2d, 0x4e, 0xd7, 0x2f, 0x33, - 0x04, 0x51, 0x50, 0x09, 0x49, 0x88, 0x44, 0x3c, 0x98, 0xa7, 0x0f, 0xe1, 0x40, 0xa5, 0x44, 0xd2, - 0xf3, 0xd3, 0xf3, 0x21, 0xe2, 0x20, 0x16, 0x4c, 0x03, 0x8a, 0x0b, 0x0a, 0x12, 0x8b, 0x12, 0x73, - 0xa1, 0x1a, 0x94, 0x56, 0x33, 0x72, 0xf1, 0xfb, 0x16, 0xa7, 0x87, 0x16, 0xa4, 0x24, 0x96, 0xa4, - 0x06, 0x80, 0x65, 0x84, 0xcc, 0xb8, 0x38, 0x13, 0x4b, 0x4b, 0x32, 0xf2, 0x8b, 0x32, 0x4b, 0x2a, - 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x9d, 0x24, 0x2e, 0x6d, 0xd1, 0x15, 0x81, 0xda, 0xe4, 0x98, - 0x92, 0x52, 0x94, 0x5a, 0x5c, 0x1c, 0x5c, 0x52, 0x94, 0x99, 0x97, 0x1e, 0x84, 0x50, 0x2a, 0x64, - 0xce, 0xc5, 0x06, 0x31, 0x5b, 0x82, 0x49, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x44, 0x0f, 0xd9, 0x8b, - 0x7a, 0x10, 0xd3, 0x9d, 0x38, 0x4f, 0xdc, 0x93, 0x67, 0x58, 0xf1, 0x7c, 0x83, 0x16, 0x63, 0x10, - 0x54, 0xb9, 0x95, 0x7a, 0xd3, 0xf3, 0x0d, 0x5a, 0x08, 0x83, 0xba, 0x9e, 0x6f, 0xd0, 0x12, 0x01, - 0x3b, 0x15, 0xcd, 0x65, 0x4a, 0x92, 0x5c, 0xe2, 0x68, 0x42, 0x41, 0xa9, 0xc5, 0x05, 0xf9, 0x79, - 0xc5, 0xa9, 0x46, 0x49, 0x5c, 0xcc, 0xbe, 0xc5, 0xe9, 0x42, 0x21, 0x5c, 0x3c, 0x28, 0x7e, 0x91, - 0x45, 0x75, 0x03, 0x9a, 0x6e, 0x29, 0x55, 0xbc, 0xd2, 0x30, 0xc3, 0xa5, 0x58, 0x1b, 0x40, 0xee, - 0x75, 0xf2, 0x38, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, 0x07, 0x8f, 0xe4, 0x18, 0x27, - 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, 0x86, 0x28, 0xbd, 0xf4, 0xcc, - 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0xa8, 0x89, 0xba, 0xf9, 0x45, 0xe9, 0x30, - 0xb6, 0x7e, 0x99, 0x89, 0x7e, 0x05, 0x34, 0xfe, 0x2b, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xa1, - 0x6f, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x60, 0xa1, 0xa6, 0xeb, 0x1c, 0x02, 0x00, 0x00, + // 554 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0xbf, 0x6b, 0xdb, 0x40, + 0x14, 0xf6, 0xd9, 0x8e, 0xc1, 0xe7, 0xe0, 0x10, 0xd5, 0x75, 0x64, 0x25, 0x55, 0x8c, 0x68, 0x1b, + 0xd7, 0x10, 0x89, 0xba, 0xa5, 0x05, 0x6f, 0x71, 0x31, 0x74, 0x11, 0xb4, 0x72, 0xbb, 0x64, 0x09, + 0x8a, 0x74, 0x9c, 0x05, 0x95, 0x4e, 0xe8, 0x4e, 0xc6, 0xd9, 0x4a, 0xc7, 0x4c, 0xed, 0x5f, 0xd0, + 0xb5, 0xd0, 0xc5, 0x43, 0xff, 0x88, 0x8c, 0xa1, 0x53, 0xa7, 0x52, 0xec, 0xc1, 0xff, 0x46, 0xd1, + 0xaf, 0x44, 0x17, 0x41, 0x0a, 0x85, 0x2c, 0xa7, 0x7b, 0xef, 0xfb, 0xde, 0xd3, 0x77, 0xdf, 0x3d, + 0x0e, 0xde, 0xf7, 0x50, 0xc8, 0x02, 0xe2, 0x69, 0x56, 0xb4, 0xb0, 0xb9, 0xea, 0x07, 0x84, 0x11, + 0x61, 0x33, 0x4d, 0xab, 0x51, 0x5a, 0xda, 0x36, 0x5d, 0xc7, 0x23, 0x5a, 0xbc, 0x26, 0x04, 0x69, + 0xc7, 0x22, 0xd4, 0x25, 0x54, 0x73, 0x29, 0xd6, 0x66, 0x4f, 0xa3, 0x4f, 0x0a, 0x74, 0x12, 0xe0, + 0x24, 0x8e, 0xb4, 0x24, 0x48, 0xa1, 0x16, 0x26, 0x98, 0x24, 0xf9, 0x68, 0x97, 0x15, 0x70, 0x0a, + 0x7c, 0x33, 0x30, 0xdd, 0xac, 0x60, 0x97, 0x83, 0xa8, 0x35, 0x45, 0x76, 0xf8, 0x01, 0x25, 0xa0, + 0xf2, 0xb5, 0x0c, 0x9b, 0x3a, 0xc5, 0x47, 0xb6, 0x3d, 0x49, 0x01, 0xe1, 0x05, 0xac, 0x9b, 0x21, + 0x9b, 0x92, 0xc0, 0x61, 0x67, 0x22, 0xe8, 0x82, 0x5e, 0x7d, 0x24, 0xfe, 0xfc, 0x71, 0xd8, 0x4a, + 0x55, 0x1c, 0xd9, 0x76, 0x80, 0x28, 0x9d, 0xb0, 0xc0, 0xf1, 0xb0, 0x71, 0x4d, 0x15, 0x04, 0x58, + 0xf5, 0x4c, 0x17, 0x89, 0xe5, 0xa8, 0xc4, 0x88, 0xf7, 0x42, 0x1b, 0xd6, 0x7c, 0x14, 0x38, 0xc4, + 0x16, 0x2b, 0x5d, 0xd0, 0xab, 0x1a, 0x69, 0x24, 0x0c, 0x61, 0xd5, 0xa5, 0x98, 0x8a, 0xd5, 0x6e, + 0xa5, 0xd7, 0x18, 0x74, 0xd5, 0xbc, 0x51, 0xaa, 0x4e, 0xf1, 0x78, 0x8e, 0xac, 0x90, 0xa1, 0x57, + 0xc4, 0x63, 0x81, 0x69, 0xb1, 0x51, 0xf5, 0xe2, 0xf7, 0x7e, 0xc9, 0x88, 0x6b, 0x84, 0x31, 0xdc, + 0x42, 0x31, 0xec, 0x10, 0xef, 0x84, 0x32, 0x13, 0x23, 0x71, 0xa3, 0x0b, 0x7a, 0xcd, 0xc1, 0x1e, + 0xdf, 0x66, 0x9c, 0x91, 0x26, 0x11, 0xc7, 0x68, 0x22, 0x2e, 0x1e, 0x3e, 0xfe, 0xb4, 0x5e, 0xf4, + 0xaf, 0xe5, 0x9f, 0xaf, 0x17, 0xfd, 0x7b, 0xb1, 0x43, 0xbc, 0x1d, 0x8a, 0x08, 0xdb, 0x7c, 0xc6, + 0x40, 0xd4, 0x27, 0x1e, 0x45, 0xca, 0x39, 0x80, 0xdb, 0x3a, 0xc5, 0x06, 0x72, 0xc9, 0x0c, 0xdd, + 0x85, 0x7d, 0xc3, 0x27, 0x45, 0x8d, 0xed, 0x4c, 0x23, 0xff, 0x5b, 0x65, 0x17, 0x76, 0x0a, 0xc9, + 0x2b, 0xa5, 0xdf, 0x01, 0xdc, 0xd2, 0x29, 0x7e, 0xef, 0xdb, 0x26, 0x43, 0x6f, 0xe2, 0xe1, 0xf8, + 0x6f, 0x9d, 0x2f, 0x61, 0x2d, 0x19, 0xaf, 0x58, 0x69, 0x63, 0xd0, 0xe2, 0x5d, 0x4f, 0xba, 0x8f, + 0xea, 0xd1, 0x85, 0x7d, 0x5b, 0x2f, 0xfa, 0xc0, 0x48, 0xe9, 0xc3, 0x83, 0xe2, 0x61, 0x5a, 0xd9, + 0x61, 0xf2, 0xca, 0x94, 0x0e, 0xdc, 0xb9, 0x91, 0xca, 0x0e, 0x32, 0xf8, 0x52, 0x86, 0x15, 0x9d, + 0x62, 0xe1, 0x2d, 0x6c, 0xe4, 0x47, 0x76, 0xaf, 0x30, 0x40, 0x39, 0x54, 0x7a, 0x78, 0x1b, 0x9a, + 0xb5, 0x16, 0x8e, 0x61, 0xf3, 0xc6, 0x4d, 0xee, 0x17, 0xea, 0x78, 0x82, 0x74, 0xf0, 0x0f, 0xc2, + 0x55, 0xef, 0x77, 0x70, 0x93, 0xf3, 0xfe, 0x41, 0xa1, 0x30, 0x0f, 0x4b, 0x8f, 0x6e, 0x85, 0xb3, + 0xae, 0xd2, 0xc6, 0xc7, 0xc8, 0xdf, 0xd1, 0xeb, 0x8b, 0xa5, 0x0c, 0x2e, 0x97, 0x32, 0xf8, 0xb3, + 0x94, 0xc1, 0xe7, 0x95, 0x5c, 0xba, 0x5c, 0xc9, 0xa5, 0x5f, 0x2b, 0xb9, 0x74, 0xac, 0x62, 0x87, + 0x4d, 0xc3, 0x53, 0xd5, 0x22, 0xae, 0x96, 0x76, 0x3c, 0x24, 0x01, 0xce, 0xf6, 0xda, 0xec, 0xb9, + 0x36, 0x4f, 0x9f, 0xac, 0x33, 0x1f, 0xd1, 0xd3, 0x5a, 0xfc, 0x26, 0x3c, 0xfb, 0x1b, 0x00, 0x00, + 0xff, 0xff, 0xf7, 0xca, 0x79, 0x29, 0xcf, 0x04, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -174,6 +402,11 @@ const _ = grpc.SupportPackageIsVersion4 // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MsgClient interface { + // Adds new schedule. + AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) + // Removes schedule. + RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) + // Updates the module parameters. UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) } @@ -185,6 +418,24 @@ func NewMsgClient(cc grpc1.ClientConn) MsgClient { return &msgClient{cc} } +func (c *msgClient) AddSchedule(ctx context.Context, in *MsgAddSchedule, opts ...grpc.CallOption) (*MsgAddScheduleResponse, error) { + out := new(MsgAddScheduleResponse) + err := c.cc.Invoke(ctx, "/neutron.cron.Msg/AddSchedule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) RemoveSchedule(ctx context.Context, in *MsgRemoveSchedule, opts ...grpc.CallOption) (*MsgRemoveScheduleResponse, error) { + out := new(MsgRemoveScheduleResponse) + err := c.cc.Invoke(ctx, "/neutron.cron.Msg/RemoveSchedule", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { out := new(MsgUpdateParamsResponse) err := c.cc.Invoke(ctx, "/neutron.cron.Msg/UpdateParams", in, out, opts...) @@ -196,6 +447,11 @@ func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts // MsgServer is the server API for Msg service. type MsgServer interface { + // Adds new schedule. + AddSchedule(context.Context, *MsgAddSchedule) (*MsgAddScheduleResponse, error) + // Removes schedule. + RemoveSchedule(context.Context, *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) + // Updates the module parameters. UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) } @@ -203,6 +459,12 @@ type MsgServer interface { type UnimplementedMsgServer struct { } +func (*UnimplementedMsgServer) AddSchedule(ctx context.Context, req *MsgAddSchedule) (*MsgAddScheduleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddSchedule not implemented") +} +func (*UnimplementedMsgServer) RemoveSchedule(ctx context.Context, req *MsgRemoveSchedule) (*MsgRemoveScheduleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveSchedule not implemented") +} func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") } @@ -211,6 +473,42 @@ func RegisterMsgServer(s grpc1.Server, srv MsgServer) { s.RegisterService(&_Msg_serviceDesc, srv) } +func _Msg_AddSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAddSchedule) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AddSchedule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/neutron.cron.Msg/AddSchedule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AddSchedule(ctx, req.(*MsgAddSchedule)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_RemoveSchedule_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRemoveSchedule) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).RemoveSchedule(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/neutron.cron.Msg/RemoveSchedule", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).RemoveSchedule(ctx, req.(*MsgRemoveSchedule)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUpdateParams) if err := dec(in); err != nil { @@ -233,6 +531,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ ServiceName: "neutron.cron.Msg", HandlerType: (*MsgServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "AddSchedule", + Handler: _Msg_AddSchedule_Handler, + }, + { + MethodName: "RemoveSchedule", + Handler: _Msg_RemoveSchedule_Handler, + }, { MethodName: "UpdateParams", Handler: _Msg_UpdateParams_Handler, @@ -242,7 +548,7 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Metadata: "neutron/cron/tx.proto", } -func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { +func (m *MsgAddSchedule) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -252,26 +558,47 @@ func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAddSchedule) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAddSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - { - size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err + if m.ExecutionStage != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.ExecutionStage)) + i-- + dAtA[i] = 0x28 + } + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 } - i -= size - i = encodeVarintTx(dAtA, i, uint64(size)) } - i-- - dAtA[i] = 0x12 + if m.Period != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x18 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } if len(m.Authority) > 0 { i -= len(m.Authority) copy(dAtA[i:], m.Authority) @@ -282,7 +609,7 @@ func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgAddScheduleResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -292,12 +619,12 @@ func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgAddScheduleResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgAddScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -305,46 +632,633 @@ func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func encodeVarintTx(dAtA []byte, offset int, v uint64) int { - offset -= sovTx(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *MsgRemoveSchedule) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *MsgUpdateParams) Size() (n int) { - if m == nil { - return 0 - } + +func (m *MsgRemoveSchedule) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveSchedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - l = len(m.Authority) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintTx(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 } - l = m.Params.Size() - n += 1 + l + sovTx(uint64(l)) - return n + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } -func (m *MsgUpdateParamsResponse) Size() (n int) { - if m == nil { - return 0 +func (m *MsgRemoveScheduleResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } + return dAtA[:n], nil +} + +func (m *MsgRemoveScheduleResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRemoveScheduleResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - return n + return len(dAtA) - i, nil } -func sovTx(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozTx(x uint64) (n int) { - return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAddSchedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Period != 0 { + n += 1 + sovTx(uint64(m.Period)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovTx(uint64(l)) + } + } + if m.ExecutionStage != 0 { + n += 1 + sovTx(uint64(m.ExecutionStage)) + } + return n +} + +func (m *MsgAddScheduleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgRemoveSchedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgRemoveScheduleResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgAddSchedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddSchedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddSchedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", 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 + } + m.Msgs = append(m.Msgs, MsgExecuteContract{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExecutionStage", wireType) + } + m.ExecutionStage = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExecutionStage |= ExecutionStage(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAddScheduleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAddScheduleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAddScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveSchedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveSchedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveSchedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRemoveScheduleResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRemoveScheduleResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRemoveScheduleResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil } func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { l := len(dAtA) diff --git a/x/cron/types/v1/schedule.pb.go b/x/cron/types/v1/schedule.pb.go new file mode 100644 index 000000000..3a35f34e6 --- /dev/null +++ b/x/cron/types/v1/schedule.pb.go @@ -0,0 +1,842 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: neutron/cron/v1/schedule.proto + +package v1 + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Defines the schedule for execution +type Schedule struct { + // Name of schedule + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // Period in blocks + Period uint64 `protobuf:"varint,2,opt,name=period,proto3" json:"period,omitempty"` + // Msgs that will be executed every certain number of blocks, specified in the `period` field + Msgs []MsgExecuteContract `protobuf:"bytes,3,rep,name=msgs,proto3" json:"msgs"` + // Last execution's block height + LastExecuteHeight uint64 `protobuf:"varint,4,opt,name=last_execute_height,json=lastExecuteHeight,proto3" json:"last_execute_height,omitempty"` +} + +func (m *Schedule) Reset() { *m = Schedule{} } +func (m *Schedule) String() string { return proto.CompactTextString(m) } +func (*Schedule) ProtoMessage() {} +func (*Schedule) Descriptor() ([]byte, []int) { + return fileDescriptor_cd4938034d592826, []int{0} +} +func (m *Schedule) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Schedule) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Schedule.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Schedule) XXX_Merge(src proto.Message) { + xxx_messageInfo_Schedule.Merge(m, src) +} +func (m *Schedule) XXX_Size() int { + return m.Size() +} +func (m *Schedule) XXX_DiscardUnknown() { + xxx_messageInfo_Schedule.DiscardUnknown(m) +} + +var xxx_messageInfo_Schedule proto.InternalMessageInfo + +func (m *Schedule) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *Schedule) GetPeriod() uint64 { + if m != nil { + return m.Period + } + return 0 +} + +func (m *Schedule) GetMsgs() []MsgExecuteContract { + if m != nil { + return m.Msgs + } + return nil +} + +func (m *Schedule) GetLastExecuteHeight() uint64 { + if m != nil { + return m.LastExecuteHeight + } + return 0 +} + +// Defines the contract and the message to pass +type MsgExecuteContract struct { + // The address of the smart contract + Contract string `protobuf:"bytes,1,opt,name=contract,proto3" json:"contract,omitempty"` + // JSON encoded message to be passed to the contract + Msg string `protobuf:"bytes,2,opt,name=msg,proto3" json:"msg,omitempty"` +} + +func (m *MsgExecuteContract) Reset() { *m = MsgExecuteContract{} } +func (m *MsgExecuteContract) String() string { return proto.CompactTextString(m) } +func (*MsgExecuteContract) ProtoMessage() {} +func (*MsgExecuteContract) Descriptor() ([]byte, []int) { + return fileDescriptor_cd4938034d592826, []int{1} +} +func (m *MsgExecuteContract) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgExecuteContract) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgExecuteContract.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgExecuteContract) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgExecuteContract.Merge(m, src) +} +func (m *MsgExecuteContract) XXX_Size() int { + return m.Size() +} +func (m *MsgExecuteContract) XXX_DiscardUnknown() { + xxx_messageInfo_MsgExecuteContract.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgExecuteContract proto.InternalMessageInfo + +func (m *MsgExecuteContract) GetContract() string { + if m != nil { + return m.Contract + } + return "" +} + +func (m *MsgExecuteContract) GetMsg() string { + if m != nil { + return m.Msg + } + return "" +} + +// Defines the number of current schedules +type ScheduleCount struct { + // The number of current schedules + Count int32 `protobuf:"varint,1,opt,name=count,proto3" json:"count,omitempty"` +} + +func (m *ScheduleCount) Reset() { *m = ScheduleCount{} } +func (m *ScheduleCount) String() string { return proto.CompactTextString(m) } +func (*ScheduleCount) ProtoMessage() {} +func (*ScheduleCount) Descriptor() ([]byte, []int) { + return fileDescriptor_cd4938034d592826, []int{2} +} +func (m *ScheduleCount) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ScheduleCount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ScheduleCount.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ScheduleCount) XXX_Merge(src proto.Message) { + xxx_messageInfo_ScheduleCount.Merge(m, src) +} +func (m *ScheduleCount) XXX_Size() int { + return m.Size() +} +func (m *ScheduleCount) XXX_DiscardUnknown() { + xxx_messageInfo_ScheduleCount.DiscardUnknown(m) +} + +var xxx_messageInfo_ScheduleCount proto.InternalMessageInfo + +func (m *ScheduleCount) GetCount() int32 { + if m != nil { + return m.Count + } + return 0 +} + +func init() { + proto.RegisterType((*Schedule)(nil), "neutron.cron.v1.Schedule") + proto.RegisterType((*MsgExecuteContract)(nil), "neutron.cron.v1.MsgExecuteContract") + proto.RegisterType((*ScheduleCount)(nil), "neutron.cron.v1.ScheduleCount") +} + +func init() { proto.RegisterFile("neutron/cron/v1/schedule.proto", fileDescriptor_cd4938034d592826) } + +var fileDescriptor_cd4938034d592826 = []byte{ + // 316 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0xc1, 0x4a, 0xc3, 0x30, + 0x18, 0xc7, 0x1b, 0xd7, 0x8d, 0x2d, 0x22, 0x6a, 0x1c, 0x52, 0x76, 0x88, 0x63, 0x22, 0xec, 0x62, + 0x42, 0xd5, 0xab, 0x97, 0x0d, 0x41, 0x10, 0x2f, 0xf5, 0xe6, 0x65, 0x6c, 0x59, 0x48, 0x07, 0x6b, + 0x53, 0x9a, 0xb4, 0xcc, 0xb7, 0xf0, 0x25, 0x7c, 0x97, 0x1d, 0x77, 0xf4, 0x24, 0xd2, 0xbe, 0x88, + 0x24, 0xcd, 0x3c, 0xe8, 0x25, 0xfc, 0xfe, 0xfc, 0xbf, 0x7f, 0xbe, 0xef, 0x4b, 0x20, 0x4e, 0x79, + 0xa1, 0x73, 0x99, 0x52, 0x66, 0x8e, 0x32, 0xa4, 0x8a, 0xc5, 0x7c, 0x59, 0xac, 0x39, 0xc9, 0x72, + 0xa9, 0x25, 0x3a, 0x76, 0x3e, 0x31, 0x3e, 0x29, 0xc3, 0x41, 0x5f, 0x48, 0x21, 0xad, 0x47, 0x0d, + 0x35, 0x65, 0xa3, 0x0f, 0x00, 0xbb, 0x2f, 0x2e, 0x89, 0x10, 0xf4, 0xd3, 0x79, 0xc2, 0x03, 0x30, + 0x04, 0xe3, 0x5e, 0x64, 0x19, 0x9d, 0xc3, 0x4e, 0xc6, 0xf3, 0x95, 0x5c, 0x06, 0x07, 0x43, 0x30, + 0xf6, 0x23, 0xa7, 0xd0, 0x3d, 0xf4, 0x13, 0x25, 0x54, 0xd0, 0x1a, 0xb6, 0xc6, 0x87, 0x37, 0x97, + 0xe4, 0x4f, 0x3b, 0xf2, 0xac, 0xc4, 0xc3, 0x86, 0xb3, 0x42, 0xf3, 0xa9, 0x4c, 0x75, 0x3e, 0x67, + 0x7a, 0xe2, 0x6f, 0xbf, 0x2e, 0xbc, 0xc8, 0xc6, 0x10, 0x81, 0x67, 0xeb, 0xb9, 0xd2, 0x33, 0xde, + 0xd4, 0xcc, 0x62, 0xbe, 0x12, 0xb1, 0x0e, 0x7c, 0xdb, 0xe3, 0xd4, 0x58, 0x2e, 0xfd, 0x68, 0x8d, + 0xd1, 0x04, 0xa2, 0xff, 0x37, 0xa2, 0x01, 0xec, 0x32, 0xc7, 0x6e, 0xe8, 0x5f, 0x8d, 0x4e, 0x60, + 0x2b, 0x51, 0xc2, 0x4e, 0xdd, 0x8b, 0x0c, 0x8e, 0xae, 0xe0, 0xd1, 0x7e, 0xd5, 0xa9, 0x2c, 0x52, + 0x8d, 0xfa, 0xb0, 0xcd, 0x0c, 0xd8, 0x6c, 0x3b, 0x6a, 0xc4, 0xe4, 0x69, 0x5b, 0x61, 0xb0, 0xab, + 0x30, 0xf8, 0xae, 0x30, 0x78, 0xaf, 0xb1, 0xb7, 0xab, 0xb1, 0xf7, 0x59, 0x63, 0xef, 0x35, 0x14, + 0x2b, 0x1d, 0x17, 0x0b, 0xc2, 0x64, 0x42, 0xdd, 0xbe, 0xd7, 0x32, 0x17, 0x7b, 0xa6, 0xe5, 0x1d, + 0xdd, 0x34, 0xff, 0xa1, 0xdf, 0x32, 0xae, 0x68, 0x19, 0x2e, 0x3a, 0xf6, 0x99, 0x6f, 0x7f, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x4d, 0x2d, 0x47, 0x23, 0xaf, 0x01, 0x00, 0x00, +} + +func (m *Schedule) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Schedule) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Schedule) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.LastExecuteHeight != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.LastExecuteHeight)) + i-- + dAtA[i] = 0x20 + } + if len(m.Msgs) > 0 { + for iNdEx := len(m.Msgs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Msgs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintSchedule(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if m.Period != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.Period)) + i-- + dAtA[i] = 0x10 + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgExecuteContract) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgExecuteContract) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgExecuteContract) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Msg) > 0 { + i -= len(m.Msg) + copy(dAtA[i:], m.Msg) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Msg))) + i-- + dAtA[i] = 0x12 + } + if len(m.Contract) > 0 { + i -= len(m.Contract) + copy(dAtA[i:], m.Contract) + i = encodeVarintSchedule(dAtA, i, uint64(len(m.Contract))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ScheduleCount) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ScheduleCount) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ScheduleCount) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Count != 0 { + i = encodeVarintSchedule(dAtA, i, uint64(m.Count)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintSchedule(dAtA []byte, offset int, v uint64) int { + offset -= sovSchedule(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Schedule) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Name) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + if m.Period != 0 { + n += 1 + sovSchedule(uint64(m.Period)) + } + if len(m.Msgs) > 0 { + for _, e := range m.Msgs { + l = e.Size() + n += 1 + l + sovSchedule(uint64(l)) + } + } + if m.LastExecuteHeight != 0 { + n += 1 + sovSchedule(uint64(m.LastExecuteHeight)) + } + return n +} + +func (m *MsgExecuteContract) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Contract) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + l = len(m.Msg) + if l > 0 { + n += 1 + l + sovSchedule(uint64(l)) + } + return n +} + +func (m *ScheduleCount) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Count != 0 { + n += 1 + sovSchedule(uint64(m.Count)) + } + return n +} + +func sovSchedule(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozSchedule(x uint64) (n int) { + return sovSchedule(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Schedule) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Schedule: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Schedule: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) + } + m.Period = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Period |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msgs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msgs = append(m.Msgs, MsgExecuteContract{}) + if err := m.Msgs[len(m.Msgs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LastExecuteHeight", wireType) + } + m.LastExecuteHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LastExecuteHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgExecuteContract) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgExecuteContract: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgExecuteContract: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Contract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Contract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Msg", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthSchedule + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthSchedule + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Msg = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ScheduleCount) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ScheduleCount: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ScheduleCount: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) + } + m.Count = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSchedule + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Count |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipSchedule(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthSchedule + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipSchedule(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowSchedule + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthSchedule + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupSchedule + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthSchedule + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthSchedule = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowSchedule = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupSchedule = fmt.Errorf("proto: unexpected end of group") +) From 6434865dda319b563f0e0e8ea26ed8435c32556e Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Thu, 5 Sep 2024 07:00:17 -0300 Subject: [PATCH 38/60] switch wasmd53 to release --- go.mod | 3 ++- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6ba6e9702..25a72961a 100644 --- a/go.mod +++ b/go.mod @@ -219,7 +219,7 @@ require ( replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 - github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7 + github.com/CosmWasm/wasmd => github.com/neutron-org/wasmd v0.53.0-neutron github.com/cosmos/admin-module/v2 => github.com/neutron-org/admin-module/v2 v2.0.2 github.com/cosmos/cosmos-sdk => github.com/neutron-org/cosmos-sdk v0.50.8-neutron // explicitely replace iavl to v1.2.0 cause sometimes go mod tidy uses not right version @@ -229,3 +229,4 @@ replace ( github.com/prometheus/procfs => github.com/prometheus/procfs v0.12.0 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) + diff --git a/go.sum b/go.sum index b0fea74d6..64d3617a1 100644 --- a/go.sum +++ b/go.sum @@ -849,8 +849,8 @@ github.com/neutron-org/admin-module/v2 v2.0.2 h1:XDDFWjvkVBKRf3lBFCazT1zAXZ3dHX8 github.com/neutron-org/admin-module/v2 v2.0.2/go.mod h1:RfOyabXsdJ5btcOKyKPZDYiZhtuKFubbJMOb8EJZtvA= github.com/neutron-org/cosmos-sdk v0.50.8-neutron h1:L+4obYi/KkkmS05gBlXNF+FhipHYTl0iO3EkmpMBXkE= github.com/neutron-org/cosmos-sdk v0.50.8-neutron/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= -github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7 h1:p80auAc2CgdsawR73JMV8SYi9U/5sAir+MAd6IEmgR4= -github.com/neutron-org/wasmd v0.51.1-0.20240829092952-0bbbba2428f7/go.mod h1:FJl/aWjdpGof3usAMFQpDe07Rkx77PUzp0cygFMOvtw= +github.com/neutron-org/wasmd v0.53.0-neutron h1:Dv1VP1+QjYeb6RMo03sxw0Pe42JU0MPxefwNaG22KVs= +github.com/neutron-org/wasmd v0.53.0-neutron/go.mod h1:FJl/aWjdpGof3usAMFQpDe07Rkx77PUzp0cygFMOvtw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= From 1bf83371924e7f3f5a756c8a9ea35e2d607a984e Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Thu, 5 Sep 2024 13:19:07 +0300 Subject: [PATCH 39/60] change BeginBlock & EndBlock signatures --- x/cron/module.go | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/x/cron/module.go b/x/cron/module.go index 3471b0379..f9957651e 100644 --- a/x/cron/module.go +++ b/x/cron/module.go @@ -26,8 +26,10 @@ import ( ) var ( - _ appmodule.AppModule = AppModule{} - _ module.AppModuleBasic = AppModuleBasic{} + _ appmodule.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} + _ appmodule.HasBeginBlocker = AppModule{} + _ appmodule.HasEndBlocker = AppModule{} ) // ---------------------------------------------------------------------------- @@ -155,12 +157,13 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return types.ConsensusVersion } // BeginBlock contains the logic that is automatically triggered at the beginning of each block -func (am AppModule) BeginBlock(ctx sdk.Context) { - am.keeper.ExecuteReadySchedules(ctx, types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) +func (am AppModule) BeginBlock(ctx context.Context) error { + am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_EXECUTION_STAGE_BEGIN_BLOCKER) + return nil } // EndBlock contains the logic that is automatically triggered at the end of each block -func (am AppModule) EndBlock(ctx context.Context) ([]abci.ValidatorUpdate, error) { +func (am AppModule) EndBlock(ctx context.Context) error { am.keeper.ExecuteReadySchedules(sdk.UnwrapSDKContext(ctx), types.ExecutionStage_EXECUTION_STAGE_END_BLOCKER) - return []abci.ValidatorUpdate{}, nil + return nil } From 5ba0ba4a5750b95591f863c207a775c914022291 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 08:58:32 +0000 Subject: [PATCH 40/60] Bump github.com/prometheus/client_golang from 1.20.2 to 1.20.3 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.2 to 1.20.3. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/v1.20.3/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.20.2...v1.20.3) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 837db6d47..ad2278fa6 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/hashicorp/go-metrics v0.5.3 github.com/iancoleman/orderedmap v0.3.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.2 + github.com/prometheus/client_golang v1.20.3 github.com/rs/zerolog v1.33.0 github.com/skip-mev/block-sdk/v2 v2.1.5 github.com/skip-mev/feemarket v1.1.1 diff --git a/go.sum b/go.sum index 4e52f6f9f..3a2d9fab4 100644 --- a/go.sum +++ b/go.sum @@ -922,8 +922,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= +github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From 9b2953d55b1a8938f023751f7fc7042ccfee9897 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:16:51 +0000 Subject: [PATCH 41/60] Bump google.golang.org/grpc from 1.66.0 to 1.66.1 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.66.0 to 1.66.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.66.0...v1.66.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 3 +-- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 45e02d20c..76712cf3d 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 - google.golang.org/grpc v1.66.0 + google.golang.org/grpc v1.66.1 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -229,4 +229,3 @@ replace ( github.com/prometheus/procfs => github.com/prometheus/procfs v0.12.0 github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 ) - diff --git a/go.sum b/go.sum index 5247f2ab2..50cbe94ce 100644 --- a/go.sum +++ b/go.sum @@ -1676,8 +1676,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= +google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 6df5f6b15c1f34c1ee4f72e2a2fee19ad4b9b656 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Tue, 10 Sep 2024 15:01:47 +0300 Subject: [PATCH 42/60] missing proto files --- .../proto/ibc/core/client/v1/genesis.proto | 44 +++++++++++++++++++ .../ibc/core/commitment/v1/commitment.proto | 39 ++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 third_party/proto/ibc/core/client/v1/genesis.proto create mode 100644 third_party/proto/ibc/core/commitment/v1/commitment.proto diff --git a/third_party/proto/ibc/core/client/v1/genesis.proto b/third_party/proto/ibc/core/client/v1/genesis.proto new file mode 100644 index 000000000..a16d5a709 --- /dev/null +++ b/third_party/proto/ibc/core/client/v1/genesis.proto @@ -0,0 +1,44 @@ +syntax = "proto3"; + +package ibc.core.client.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"; + +import "ibc/core/client/v1/client.proto"; +import "gogoproto/gogo.proto"; + +// GenesisState defines the ibc client submodule's genesis state. +message GenesisState { + // client states with their corresponding identifiers + repeated IdentifiedClientState clients = 1 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "IdentifiedClientStates"]; + // consensus states from each client + repeated ClientConsensusStates clients_consensus = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "ClientsConsensusStates"]; + // metadata from each client + repeated IdentifiedGenesisMetadata clients_metadata = 3 [(gogoproto.nullable) = false]; + Params params = 4 [(gogoproto.nullable) = false]; + // Deprecated: create_localhost has been deprecated. + // The localhost client is automatically created at genesis. + bool create_localhost = 5 [deprecated = true]; + // the sequence for the next generated client identifier + uint64 next_client_sequence = 6; +} + +// GenesisMetadata defines the genesis type for metadata that clients may return +// with ExportMetadata +message GenesisMetadata { + option (gogoproto.goproto_getters) = false; + + // store key of metadata without clientID-prefix + bytes key = 1; + // metadata value + bytes value = 2; +} + +// IdentifiedGenesisMetadata has the client metadata with the corresponding +// client id. +message IdentifiedGenesisMetadata { + string client_id = 1; + repeated GenesisMetadata client_metadata = 2 [(gogoproto.nullable) = false]; +} diff --git a/third_party/proto/ibc/core/commitment/v1/commitment.proto b/third_party/proto/ibc/core/commitment/v1/commitment.proto new file mode 100644 index 000000000..b4753be2d --- /dev/null +++ b/third_party/proto/ibc/core/commitment/v1/commitment.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package ibc.core.commitment.v1; + +option go_package = "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"; + +import "gogoproto/gogo.proto"; +import "cosmos/ics23/v1/proofs.proto"; + +// MerkleRoot defines a merkle root hash. +// In the Cosmos SDK, the AppHash of a block header becomes the root. +message MerkleRoot { + option (gogoproto.goproto_getters) = false; + + bytes hash = 1; +} + +// MerklePrefix is merkle path prefixed to the key. +// The constructed key from the Path and the key will be append(Path.KeyPath, +// append(Path.KeyPrefix, key...)) +message MerklePrefix { + bytes key_prefix = 1; +} + +// MerklePath is the path used to verify commitment proofs, which can be an +// arbitrary structured object (defined by a commitment type). +// MerklePath is represented from root-to-leaf +message MerklePath { + repeated string key_path = 1; +} + +// MerkleProof is a wrapper type over a chain of CommitmentProofs. +// It demonstrates membership or non-membership for an element or set of +// elements, verifiable in conjunction with a known commitment root. Proofs +// should be succinct. +// MerkleProofs are ordered from leaf-to-root +message MerkleProof { + repeated cosmos.ics23.v1.CommitmentProof proofs = 1; +} From 73e4cab9d9918fb72b3da47718bfef1db319d1de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Sep 2024 08:45:14 +0000 Subject: [PATCH 43/60] Bump google.golang.org/grpc from 1.66.1 to 1.66.2 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.66.1 to 1.66.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.66.1...v1.66.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 76712cf3d..544dff19b 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 - google.golang.org/grpc v1.66.1 + google.golang.org/grpc v1.66.2 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index 50cbe94ce..20eb616d2 100644 --- a/go.sum +++ b/go.sum @@ -1676,8 +1676,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM= -google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 7edef5d7b4bbade4815949204da35707d93dd138 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Sep 2024 08:33:53 +0000 Subject: [PATCH 44/60] Bump github.com/skip-mev/slinky from 1.0.10 to 1.0.12 Bumps [github.com/skip-mev/slinky](https://github.com/skip-mev/slinky) from 1.0.10 to 1.0.12. - [Release notes](https://github.com/skip-mev/slinky/releases) - [Changelog](https://github.com/skip-mev/connect/blob/main/.goreleaser.yml) - [Commits](https://github.com/skip-mev/slinky/compare/v1.0.10...v1.0.12) --- updated-dependencies: - dependency-name: github.com/skip-mev/slinky dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 76712cf3d..5b6339cd1 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/rs/zerolog v1.33.0 github.com/skip-mev/block-sdk/v2 v2.1.5 github.com/skip-mev/feemarket v1.1.1 - github.com/skip-mev/slinky v1.0.10 + github.com/skip-mev/slinky v1.0.12 github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 diff --git a/go.sum b/go.sum index 50cbe94ce..4d42294c0 100644 --- a/go.sum +++ b/go.sum @@ -987,8 +987,8 @@ github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610 h1:4JlsiRVt github.com/skip-mev/chaintestutil v0.0.0-20240514161515-056d7ba45610/go.mod h1:kB8gFZX07CyJnw8q9iEZijI3qJTIe1K/Y++P5VGkrcg= github.com/skip-mev/feemarket v1.1.1 h1:L34K7N2J6o635kzNYRAvQ93+hAFtSiJ2t03jmaNx0zw= github.com/skip-mev/feemarket v1.1.1/go.mod h1:DUa6djUsTeMOrbrcIZqWSVxU9IZNCXp96ruaojyBNpc= -github.com/skip-mev/slinky v1.0.10 h1:QBd/jBxUcV2dq3VERhf5h42cAA0s2awPZGWpHgh0t20= -github.com/skip-mev/slinky v1.0.10/go.mod h1:8mxMdQ8MY8QAxgxLvUKTfDwX6XCAUeqZwkU/r+ZsELU= +github.com/skip-mev/slinky v1.0.12 h1:qmZHB6c5fgDhO/pv67YcZc2M25t3gZcceVmJtA9zjOo= +github.com/skip-mev/slinky v1.0.12/go.mod h1:8mxMdQ8MY8QAxgxLvUKTfDwX6XCAUeqZwkU/r+ZsELU= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= From ef0aa14a5f700fd2a6b7dd4fe2472ef75686daf0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 08:47:34 +0000 Subject: [PATCH 45/60] Bump github.com/cosmos/ibc-go/v8 from 8.5.0 to 8.5.1 Bumps [github.com/cosmos/ibc-go/v8](https://github.com/cosmos/ibc-go) from 8.5.0 to 8.5.1. - [Release notes](https://github.com/cosmos/ibc-go/releases) - [Changelog](https://github.com/cosmos/ibc-go/blob/v8.5.1/CHANGELOG.md) - [Commits](https://github.com/cosmos/ibc-go/compare/v8.5.0...v8.5.1) --- updated-dependencies: - dependency-name: github.com/cosmos/ibc-go/v8 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d203836f9..04de501c4 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8 v8.0.2 github.com/cosmos/ibc-go/modules/capability v1.0.1 - github.com/cosmos/ibc-go/v8 v8.5.0 + github.com/cosmos/ibc-go/v8 v8.5.1 github.com/cosmos/ics23/go v0.11.0 github.com/cosmos/interchain-security/v5 v5.1.1 github.com/gogo/protobuf v1.3.3 diff --git a/go.sum b/go.sum index 3c96e84c9..ffc762436 100644 --- a/go.sum +++ b/go.sum @@ -377,8 +377,8 @@ github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0 github.com/cosmos/ibc-go/modules/apps/callbacks v0.2.1-0.20231113120333-342c00b0f8bd/go.mod h1:JWfpWVKJKiKtd53/KbRoKfxWl8FsT2GPcNezTOk0o5Q= github.com/cosmos/ibc-go/modules/capability v1.0.1 h1:ibwhrpJ3SftEEZRxCRkH0fQZ9svjthrX2+oXdZvzgGI= github.com/cosmos/ibc-go/modules/capability v1.0.1/go.mod h1:rquyOV262nGJplkumH+/LeYs04P3eV8oB7ZM4Ygqk4E= -github.com/cosmos/ibc-go/v8 v8.5.0 h1:OjaSXz480JT8ZuMrASxGgS7XzloZ2NuuJPwZB/fKDgE= -github.com/cosmos/ibc-go/v8 v8.5.0/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= +github.com/cosmos/ibc-go/v8 v8.5.1 h1:3JleEMKBjRKa3FeTKt4fjg22za/qygLBo7mDkoYTNBs= +github.com/cosmos/ibc-go/v8 v8.5.1/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/interchain-security/v5 v5.0.0-20240802125602-fa1e09444aae h1:/EWV9qryltapge0v4ctvl2jV3Nne5nsbd+GYblj/jWA= From 5bea9efd91d63c98e37b8d273bba0f8f4cc49cb7 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Fri, 13 Sep 2024 11:54:18 +0300 Subject: [PATCH 46/60] refactoring --- Makefile | 2 +- app/app.go | 21 -- contracts/neutron_chain_manager.wasm | Bin 558660 -> 585200 bytes tests/feemarket/go.sum | 1 + tests/ibc/gmp_swap_forward_test.go | 88 ------ tests/ibc/ibc_setup_test.go | 38 --- tests/ibc/swap_forward_test.go | 96 ------ tests/ibc/swap_test.go | 173 ----------- x/dex/keeper/msg_server.go | 10 +- x/ibcswap/ibc_middleware.go | 428 --------------------------- x/ibcswap/keeper/keeper.go | 207 ------------- x/ibcswap/module.go | 144 --------- x/ibcswap/types/errors.go | 9 - x/ibcswap/types/expected_keepers.go | 14 - x/ibcswap/types/keys.go | 8 - x/ibcswap/types/swap.go | 114 ------- x/ibcswap/types/swap_test.go | 248 ---------------- 17 files changed, 4 insertions(+), 1597 deletions(-) delete mode 100644 tests/ibc/gmp_swap_forward_test.go delete mode 100644 tests/ibc/swap_forward_test.go delete mode 100644 tests/ibc/swap_test.go delete mode 100644 x/ibcswap/ibc_middleware.go delete mode 100644 x/ibcswap/keeper/keeper.go delete mode 100644 x/ibcswap/module.go delete mode 100644 x/ibcswap/types/errors.go delete mode 100644 x/ibcswap/types/expected_keepers.go delete mode 100644 x/ibcswap/types/keys.go delete mode 100644 x/ibcswap/types/swap.go delete mode 100644 x/ibcswap/types/swap_test.go diff --git a/Makefile b/Makefile index 9c8a00e2d..a2a54ab7c 100644 --- a/Makefile +++ b/Makefile @@ -178,7 +178,7 @@ test: test-unit test-all: check test-race test-cover test-unit: - @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' ./... + @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' `go list ./... | grep -v dex` test-race: @VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' ./... diff --git a/app/app.go b/app/app.go index d25bc5583..af04a7b11 100644 --- a/app/app.go +++ b/app/app.go @@ -193,10 +193,6 @@ import ( dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - "github.com/neutron-org/neutron/v4/x/ibcswap" - ibcswapkeeper "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - ibcswaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" - globalfeekeeper "github.com/neutron-org/neutron/v4/x/globalfee/keeper" gmpmiddleware "github.com/neutron-org/neutron/v4/x/gmp" @@ -276,7 +272,6 @@ var ( globalfee.AppModule{}, feemarket.AppModuleBasic{}, dex.AppModuleBasic{}, - ibcswap.AppModuleBasic{}, oracle.AppModuleBasic{}, marketmap.AppModuleBasic{}, dynamicfees.AppModuleBasic{}, @@ -298,7 +293,6 @@ var ( tokenfactorytypes.ModuleName: {authtypes.Minter, authtypes.Burner}, crontypes.ModuleName: nil, dextypes.ModuleName: {authtypes.Minter, authtypes.Burner}, - ibcswaptypes.ModuleName: {authtypes.Burner}, oracletypes.ModuleName: nil, marketmaptypes.ModuleName: nil, feemarkettypes.FeeCollectorName: nil, @@ -370,7 +364,6 @@ type App struct { CronKeeper cronkeeper.Keeper PFMKeeper *pfmkeeper.Keeper DexKeeper dexkeeper.Keeper - SwapKeeper ibcswapkeeper.Keeper GlobalFeeKeeper globalfeekeeper.Keeper PFMModule packetforward.AppModule @@ -748,15 +741,6 @@ func New( dexModule := dex.NewAppModule(appCodec, app.DexKeeper, app.BankKeeper) - app.SwapKeeper = ibcswapkeeper.NewKeeper( - appCodec, - app.MsgServiceRouter(), - app.IBCKeeper.ChannelKeeper, - app.BankKeeper, - ) - - swapModule := ibcswap.NewAppModule(app.SwapKeeper) - wasmDir := filepath.Join(homePath, "wasm") wasmConfig, err := wasm.ReadWasmConfig(appOpts) if err != nil { @@ -921,7 +905,6 @@ func New( pfmkeeper.DefaultRefundTransferPacketTimeoutTimestamp, ) - ibcStack = ibcswap.NewIBCMiddleware(ibcStack, app.SwapKeeper) ibcStack = gmpmiddleware.NewIBCMiddleware(ibcStack) ibcRouter.AddRoute(icacontrollertypes.SubModuleName, icaControllerStack). @@ -972,7 +955,6 @@ func New( globalfee.NewAppModule(app.GlobalFeeKeeper, app.GetSubspace(globalfee.ModuleName), app.AppCodec(), app.keys[globalfee.ModuleName]), feemarket.NewAppModule(appCodec, *app.FeeMarkerKeeper), dynamicfees.NewAppModule(appCodec, *app.DynamicFeesKeeper), - swapModule, dexModule, marketmapModule, oracleModule, @@ -1022,7 +1004,6 @@ func New( oracletypes.ModuleName, globalfee.ModuleName, feemarkettypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, ) @@ -1059,7 +1040,6 @@ func New( oracletypes.ModuleName, globalfee.ModuleName, feemarkettypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, consensusparamtypes.ModuleName, ) @@ -1101,7 +1081,6 @@ func New( feemarkettypes.ModuleName, oracletypes.ModuleName, marketmaptypes.ModuleName, - ibcswaptypes.ModuleName, dextypes.ModuleName, dynamicfeestypes.ModuleName, consensusparamtypes.ModuleName, diff --git a/contracts/neutron_chain_manager.wasm b/contracts/neutron_chain_manager.wasm index 9127898467342809c29c3696c3b1c5502c883abd..83945edcf24213cb198f871fa1c5c9c0fcc0f8e1 100644 GIT binary patch literal 585200 zcmeFa4Y*xZdG9;tm~(yYwbstc2N+0{xt8hePRlN_$0iuKp3Gc63*KT6&v|IC&xI&C zl^sL~kYU62G1kJ+?(fiwcUCw(&?kYEkis7Aqd^@BfZ5 z=2~m-olnwRdu`A?=bCeTzTe}0-!W#g;mVh!Ns^>Dxxqzl>()en(ybR|TXnC${7AV? zb(8a(`vrX);cvK0{M&1*Qq*dOw>+c4YbnITScO~b2k)w3sbxwg7qw&ms3#zsy5so zxdqwA%dVCOjFd=|Mkb&P2wCccohDpGWJh}c$mAi`j-#?9m7M4@i)uV zMN&`dG^q}`@Q*ugvP{L&V{6Go!szNM!HCEHX=HhtxKz)n(@4ZbYK-1_(5U70hHEjw zZmZjM^|TfnuxbKrKoEpqG?J!W5)ib%Oe|e?^wLte-d1%hSK&zgm_i3+u;a zThnsew!KMvYf^6e@yCbP#>dlc{UsY;^3u(}s__8gVUwT>c{j|B^(o0|ZBE5f) zo49ym_3O{v!m2dvOA9aEO!47E`rZ6ns`veL@gL%Q9{MWxC-fZg=|r^qbj5A4q@f-sL{( zF4&Xam3}z=xnKB;^qzF(C(^%6Px_eK<=*f9kJH}k-sg6^54b;fce_3AgYHA_!|o&Q zz3Kn<-vHc4($A!yO8-2)E8mmen|?C=bo#z@SNfjx&(a^HkEOrx!}Oohm%HoTjc&sq zyZ5KBbQiqBZFjG7H#k*%v%AUdNmcQU?oB*-D0`i|Iopx#Nk8sB;a=lj>uzyxaQ`d) z19!7~wY$#kaDU-m@AgvX_uYSU+uW1shQD;*%Kkaq@PYK3?(1&DoAS5kcjiyHTk~!1 zo%s*khCS&&yC1p7-4ESAxyRfqvJHQLfVkjI^l)$b%4~afU3Pu;^6U?@kEH*L_ixE= z&2G%zoc$5+pQQZ{WPi@xN3suPAI{##IQQ`D9r<7L_krvS+5PtH^VI#D>~FIVq(8}? z%)Xnw1wcH>2;Y-$%WuqIk-s;8WxhRsRlX~KB>S^`;twAx-kE7~xw%rX{y5wi*MbYZ@{OcAki&mM=3>vFlQ_qs3HB+9r zHc8q=S|)3g+^Q7~U$GG@Hmud8Xv~xY3e!rXY9$L*Hl1UgHHxga(04biRXCpR&X1>J zMk7`CdC}NZrqA;gOE%{(&dARHCeAncv0BXq?lOa@-nTJN!v=5#mtJNeGg2()dSY8NZdNXRI^J@?L#n*5@E%a z+%46$$#4LJE0@glKARS9%60m7X`W6KNs+B~ITsDNo?(1@t(%ATg$ z`(l=~dtc%YPi!WiLYRe_WN{`c&s@$K&V|u!8RR@qi+p4*`N&)x17U=kOXla2jm{+t zbIJT%atismWPUDO!dw8yf#;IVnM>y9@+bnlBKRDF&nXEN?Q??ll)q_*c!Dm zfA9v%)ZpLFOz)ZgwaA8+5iHY5r}u#CSzo zS_&W+=V#@V-i&ZQ0~hB5kis`7UZ;itBB*BN$@{IbYEBIXXTn1D)@?!|ezq2E4M6xa zOs?1zt7afosT}<$S+Giar3rkccATC(+pMsfl#XOHw9?O{Ig)+@;s0cMg=)w;8>D6_ zdDAM5rWNR_Lp@$em_?RGP2{^TWKkiC)OpvTjGPpglo2wj>|82+ltX>}Ov)&X0F|r} zU?{2M#z@CwHl3Mql_`jICsQy?8!IcX`i0`?LKe`OQcjGbVZ3V-^h(MkW!H5wxLPJx zvpiM6Fhfh`*s}w1Hbu_iWw6#%+(_8$wr9(3D`;NUni@Mi>#mR4iKS}&dV2oSsA6kG z+qnipgY8@cNd3AvM|Xp!E@m;*iY9on*G*nB7VN^h0LC)_6)_cTXH_feLa;24m<#VXew`#*m?rs(X40wzFE4?QG*5R*bf@y*5LqVQOuu zz{BvdoEw5|1Mu_Hy!20f8T>2d+S?2dhZ*z_U@)7#$b;>|J8SW<=eM^@|8bK{Nwu)gx@^H*KM-Lvy0!8 zXe2Z@6|N`iDpFsW71v-WXXoE_%>W)do^R6j!-caH{tN8lo zZtsJk_3jmP`rPd|m{?vv{R&3Bc>4|OKl-+pzx}oE&bPH`FlVCscHRBQci;L0KZBL5 zT58wO{y#92w7e;u>D`cv_R2@@{&-R*ZmYD>O)0RY_6_HCljAA&qhzLBMX4p5dhchY zm6m8WL6i3BHdD8Qyy{qH@!WpVMsxa&T~&3@_x*i6^p}SIirVevs?BSYjjXO1nT>v? z{Q07}srQ|%uLnC)mRp6b44}Uraw~zjx$O*$B9}g`-QRl`#PnkpKHsm!MZ$f_rh#82Kox$KU?LkqT=SNTV!8F&y#oWNb?GbVO5vIOm(v zAjMF!Nr8;{C#CVDZcvz}ZlDvb*3hM4J;d@YXUWN*6Qdbr%Qg>qX~ujiS-Cn{SfQXJ zy_Cx?vN}=RSu3V`sItE}>$P-mixeoYcbcW8eu zrp}lbTFG9cB>5#pRFgX687w$UovB(;lRDFCC{z^aRhad%xq@VbjI_efP30nabo62| zTFJT_)*7VcPj1|stW1(MiKOm=newJr>`j6(EWJ?P$nWsp8X1n!S~q`@UP$N7YCY;a zdu=+eF71&IZ8!`fv*GH&hBMpf*#^E$Hk^}MlF|y6n>s)ya0wtBgM>}K0$}As@SS2j z{Ed_8ueuklq>2!Fjz467} z;jOW>tTDE&_mG308$YHU@KD3InhB2|Rx&Q60Wyz{$d@LypFcHoLCbA` zdjhbPf@G0=xC$+Xm+Bb5m}}dJ8b5_VhFJy(7b$`xT%Yt<5n=g3FIX|X*#QkR6nS^=tMfCnXjMO-q7EH}M+>q?~mk`Rpl?eC91=7O;30 zf~OPYo0W{lz{9!PO+i8ODqE)~a*OiHFbvBZZ(^z1R1g!>8B@8pKs8pe3?7zwjmqE* zWuedd)RsN581z*&b+d{Q%hVFr!8pktkhj zHynrZg=#R2eL6W&3ub;ayIGm|x74=wf*W38f@+FdaAs4hHU4oeAHHl|L*LBL9`^A#Uv9^03?&WMpRf#U}iwLJ@8^!iu(8w3$k&F_54zw zy&$WzAoE@iPy1D{3Qv9&ta>&}*AT1<@*n}m5Tu2kG`u1VFpmR-8F`MZ3O)n*y6_pq z(NbYkS(60Ri#ig}rZucJsFmLaW?>9c@#XjU9VDVvn$?>52=qcef?2IaAA!C02>?P( z3NDvcNJN^IiDGxd0Gx$0g6OFLSd8(b0LaR0Je>AKwVYkG$-Lx0vu10#LavxQ@cBwK z*Tk4BaPo0EQLbOEQxHLF-d|(ero||bhK*5aXfcY8Vie=jaCVGhmCUarweP=2iaJqwFj9ST<9>V)$FipLD9|!sBNM3F*ZlxyQ2d5tLJ2g~!DJmj+w& zav~U6`B);Y4_>@kVjfS4A{^b7PfXEFdo7n@2;17cu>I_tMqrCr`8>Zz46E8xfvrQH;Y?J*LnhZPQ1(d= z%HNWg5tC?T*2LL3j)Wl!bO!{^GDQ+$bZ#hamPq-J3>f>X*?YQGGrLO|^>2Uh`@AJt zFT6Fp+E8eiR;QD5LwZ6quY{TCw#&+gXvi!Lvp+5$F|f|}a#01caul83)QMvq;`28Q zvzpEMo)Ek_cgX$8Dq<+-ah-DKX(FPx{X1r*Zh{Up6M2Lp;f*8kX*VMwwdN(HFMx;O zvo;_0-;5Jd>!}fvC#9uxNeN?iwR#ZsyEKBHJ%c(_!8x`kpaMHR}(=)mfM%f;+<( zxg~;hBHHE2QXX(w5;T=t>F{M^2C0dVok?Me0(x}Nj~cGyT>#QSB$@7~v(O!xr|NKh zLS|p+a50K>HUXw{HI0>KGEw9YZT9aK+xRa7+X&nEd>}}bs=BM0g9)#;W2u~e0 zDu4p&x~SMpLL^ICw1J&^!X)VPhgU*u0{#IZvz;kgqOn9WZ^GX#$9(j6tb>~V4iVPz zcZz)ZyD3J!GP}Sx)RST(R#tS&=9bOA020b3=K-dfT1LY#L&4GOtPF*>EOrfVe(rSM z{4{p}iVJ?~eH#8VLa6n=;6xurBk1MxO3NG5l*_!YR7u`!jqaJzlFuKw^2f=UMp6SV z0z3^do@K3rPjMda~KXpO4tTsJm-siZe$E+ zKvdaD$!Dal{yLRN5!D#S&v|NmJLT?65sB6&ybj*f@|3$jh3uPGbx7f2(i#o~Du}D- zSpm|5G6i^Ywuh$yr>XhZSc(r+Q+Z2DR#KK|Ix_!OJI?=!_r>|w{LJCtTJKZV(`kM* z>mc#WU0Z(RpFf^JNwQ_i$Nhc3T|VmXY?i3R-dnNEcx3c##aMY}ClA`9Qtno@l`QvQ zYW0eV_31VCqTu~L!3}|WKUY+VyH~&Oc<){w-J@H`y%AtA6=2|i0d7tvd4=~tth5!t zo7_ylCER7uC*mE%6U9GKG)FK$IYWXnK%<4HqQos>Ki%>4VEBg_V_$tWIh_>r!IlJb zH^df=d>8jopw{l0U3YwkEi0C58>{z5(4}|N$->g=iIjN|I=soL$Ilxz-QqmpZ+0S% zDYgV@2qaKB&khP8S)4U1pMXxuJ?YJO`0FRj8DxP;q1@ySU2Y34JmDEiG<8yP9i5fe zyGW;qMVyj1xc-EngCEi7;PPSL#sQ^&bB@}0qbpj0&Nb$hY-U0((&Nb3ZB93lxRe%B zNzyYD0OF+N^%}q%W(|Of)_^8$11aF%M`#-yExl@O@?C%1yy}$X+q#{2u6xX`>x=Er zb&u;-oK)12fsgXbM(Y_`O85~p%O*`}Isu$%Sv#XhHzTk;m?=NS6b5xsO5bHtd$}x0 zeoJi{JVAGSEl~w>iiuArEl*fYBdm7m+MbxR za<9q3hg0<;L2iqghfo-MQe$ncR*hf_2PumIY<|6a4ANd6nkw{FueOy zPgq_G`BEO{D5>qVCQWmL+)n7$A$d62%<7@5+Sk?lR!=Sj)ugoQ6u z@{oow22CQ#uBbC>^kP;tPpL{0Ywle&XxQ?)1P;^(CWF=pJb=X-_mHqn(yb&$k*`he z)0H7ha!Ajb*bueWdVg)O2^{3<|DfbYw+Q*(FWLCY-Hc;60!I5M^isZ^r+%Q4ZW`2` z>YPE{rYnQmsVjrJRaXXe3s+^FM0vgx{A)nd$#KXg$*8QnMctMn2)uJaFyCizxYKZN zS=*j8u%NJ|?uqCKRg-?x)UY`NZ4wpbm>#gSXsHMAfaoZnv;V{%T&{;~E=fo1BOOyBT5|Vq?@c+3B<{`xEE)%i+)`ceJvqoK!M-Nm2rcm$R^P zuKTBt%P(|1zti4#(*f!J(1JJOcIOC#T)<#qqJ>C@UrSl=a~a8eCY_`ANrz37D5tQq zh82%NDkK7G^0}53EIqY^Hn7U=Wl&Lm)N&6T;3hBu9DgSmDLt_Xe>g6$KO9oSh z9}<~7^vWv_IkmQJuuL&QzlgCGSLXTL4BNM+esd%s+W)#$!W@U7p62#y>^ zjj&#~vCkbr-bNfE7_=!Z}^de(9x5S1e8$8G)h9km2((4-AjgQh8}^oEciS_H&4Y zyhrWL6}LgMU&)FV788lv+>vw1z6g&m&j7Hl#Xe-yO4I1Kl)kx-lxPA3eCoE5&mcF` z$Al#UH^@w%EScGC7x*2(B{4K(<=3{{q+f6D4X!4mW^F~%_~0J>soYy`onV6(8WOe_ zEXq}=KS_oAlbOEe{Op;2GqZw3_C+(qYZxb&DKUrg>0#q3SI8~J#d%i$Tr9qf7-? zDZ`t%YQE@ngTf7Zeg}Gd+*h>Io>VFoQk&0Fv_qA5Sy7CD-Y;s#yEJ2#UcG)@2KkhF zO0^PkG8epO@eb@CNhVh7%lbL4K6WL`)hD1)nn3O#KS#?q?K#Q^9qlNe01cQl>?r42 z3RV+92+Ei!aX#*4S?#v;7tnyh+VF-6@+I&MNR$t-Lur(pR0pWwnXVAY0$LTrX|Ftb ztV4@j%qLrui-$3o>0p7W;a+*kd8;{lue|3QP5g#bE+kAJ>1vR(%a9}L0v3C)XFP){ zhe?EBxT(XqqW$@xs=W#xpnVn*4h3b#E>KEG_v%l%Z7&$xE7=z4dwaq9Zy*Sjf`Wvz>lraa(m^iJX@?O;j{@>3F2j?99k zTp%SjWO?1xD9{bcjKD{RkyuFGAdfQCDk}v05g2qikMX4q8C2RyidX1CQm9d+u@oMX zT3*|v=n?$pBLACa&k_R@>!TdRa&42eqQcHmux*k$6#>D)rDID&p;@NyT*iedG83|? zf)R~=0>$R0l<7%IIb~Q)WNe=?&0_jNDz%IvM)~%|qM%`@by*T^0({Vjc1#V_ibmC< zJtLUG1Rb`lL&#k3_^pB4;xiP|BSii1De{{`CbVXqu)cwxe5NABmQ{owuV>IB%UUVw zC6|`VX3DFt7!bAjZSCv?IGa?y{ik&-RI%Ou|0`sePIhD+)as39Yogr&{tR`=K+rLd z_dp|Gm?wsW)4QEcSAH!apsdSOOhR}aO&cmm38;dUg@(_yiS_GeFP`_1r_`*r+c+O% z+Zh~jG~1r&=v)MkDvu6t)iRNu4alcVjZd~E_sHQ^YHHn1J4>zE zu1y*RMvrGYWKO+UAUhaEN6f1$IgN6g__bW^H)xf8uV*1&NW~y^^sFm!h<3_iGy6BO z3`MiGvMY&cswM4xM|d4JW9`X|%twQaR`ewTzBMv8E1oNM+A zQzSQ_Xqw&v3TJfd#iXCfWSGh6-A3ijcmySGzWwOzzTxH3*&XI@5SaMYD`gQ4VQ&X0 zU?lvS7b8i(3q+em*C3h$QPX=Z#n)4$F^D2aLrO!@!QWttF0X(I(gRQ?dcPcWk-=!9 z_pCM~UwK}3#jyrg%qQ^3_`!zsnhllhiB5VN|3fCjV=vkmCe{s`fmb%2;gYwElG-^SxsrL~+ zwSt;ye2y+QKtrUVz6UI3g$NbI8wp|;^uDbGEa;DXt3-e1oh9Ofv!dV+x6T-#V`BRdMT<*&V)=G=WJ%IpVrS`B}7!z?i4Y0W#kmy+XwCPgqNKOi$Kvun+cuE z=;%twu5+|Nz|Zc8A8&nXZ!e){pq8yiXD^dIAf2R**#ctIK*5CUOdc(~1j0aD3>G6! zS~m=qHJgZD1eBMP!oF=pHPB!+3OFp0Y(Jiu6Kjd(vG9Ic68^=TZG~I*oJ`I;@h*gl z(Syj0vv?xXArLnzv(?`i3b4oaBLcwuJ~kg#Jj;q*xvbrTfE#|@d<&-9R(FkuH(rw>`w&){0o}=Z%IRiM zzmj7I5T_q-5EX>ch=52oAb;{Q`9DES&BIh21+78PLE3TWsSSY2+t4^|=RN;;ejc@Q(o@oq^eo{>~`mvB~{l3g*~tQSTggAn0;V|InWc*i>lHb+`Vnkcyk!eqg!7n z!VBX-ea#+9C3qQ1J0Mr$@sGyv89WLPG~LA3OgV%hJWXj8-(lrZ%@I z`nV;1+#S=$BfoxAl5bRIcO?WTi)PTs-C|OQTQId*g73DMN3E){z!!uqaZA)hGX()h z(U_4M2bDYzmCDv%cGjTQeIf0DGO_$J{h5+m|3Mq)S?SZ>cpVzQ}=>=&~sq&K{w1R5WJ z%clCQrrPUMEI}nbbp6kyzW~M4{XLSYlK+&iTkrY{Bwo88`sfHR-q@d1vy&DcDHf~Zvc`y2tGuz6@A2tQYaS4jpjH`C%itRtI%hOWqzK=VIsZZ zGh@JCg~SeCkvRkG?q`7ibG`vi&O1Oq7aO22Fg`$;@uLHrnkmKyI3+4O5i09wRWcib z{?S|res#_O0Z=Cn&@eC$1bqPUMIeCV1RE^apiH+a#)%3mvVUcxKI;jdg?`I)45g#`6 zf*l0sk2D+RO|w)vOKbOPxiWFKkFer^)Vwe-60II8nyvJsLC&a0(8SOmnF0c+f^nDv za+JO<@Ua+#ni^j<8(XVX=GnrQq>E&qilLatk%~Y>_p2C!sw##S9xv8YF{$BpUjy2w zZDd8#zIZe{)~%BulIIr1qUIFQV>ToH`$Xj=M04Ya@Wy zCMSAi@t1v=-~0W&a>sjUdl#lZt0Zdw%lKXr*IgwVi!a;MRn{|gG<`Oo&9@2ge zqdg>v?Ou>hGWUgC^)dt@C9&7VN)Lx#s}ptXy{{6sl!;0#T5q$mdQ-_I)fN!uZCgMP z6q>UJc|-~Pw!utj(grg>cbhqj5=D8mRbtAIh_KB}`6GUx{TQ(vG#Yh!9G!Ae(w+s$eapE|>7^E3 zk;K>Sl#6KrBhyTZSb3NWtV8fJdq0v7Y!yP61j^}?d|+U4jn7@UT3t^OlV-kbvm;OA zSeb;aKH|_iW1=mzZva-ktZkZfDehRt^zduZw)Nhhv!zPpW;(R|{7xR$^bjkLhoFk3 zyYLz!c$l+Q8?Es+WXQF~TcBczNk%}S3Lny!j8%Y(b9VEsB^1CbmY& zg6LcTFd>JI3{gMK0Q6bI^gTB{Mlnfkf=SVnX*x1@xhb6K;C7F_P*_{Il-MA_c-RFi z_L*`omKy-;t8ZsY#M1w}FKs}TbHfHoHy10T$4|x}jnEm6UjBuyj-D(gl+#Q(pceuC zT(uZLc(ouRNDe`$sPKV+g!`WYLm<^8O*&O40ZgG2o7mNUVq5xbXNoAL{KV;UIhnm- zdu2R277Wp0`(}Jk1(_{m7+}&HX0^HI1q_11Z1vFwoAbGVROR)6&~vSnHBFC~4x6k1 zrxwnIc^U$hEhHkZE4v#(5wg2s0z{&+H(dDzQH$lW3qm3oGRFi9K%!wlHyQ@I+VYCX zy*?#*J|tvZY9GvKLQNg4(0(Jsqg+M%r7>)^BH0g6=o^=#ywMtAu|RCuQ2~j7qI)`^ zBk^{#(%&caSb{@iJ`MMo=hY%JrqKXT6VNa4**53y*RlC(Af^j1F>{HM z5EdDc`cv)&CgH_`QUOZJ9%9n&ukpye+Oy;qIzSp5!pOwpu6sDMCX_0sc_pmXT&)5LYGD*Q~7})uKFz5NfoC^r&8B7KWkYOR=0#nqZK&x9uKSaUk zU@B6x#W=w&k7^Kq7E9E3ycMxr03pob-jo!trQI5FEAPQ)(&jkNJlK5=HWyxOA3b7eg}_-ERQ z!`fR>UzT#*OyRRpCY0O>TI{hDVpKh)<9mnUy`$g67^dT*ONVMYatY&u_F8CCpr3lh z%M{a~1j(0>qytHQvC#)bKJ~*>A*aim?(>OlY()^@PvNH6J{L(n!#pwD*{5MKQOgs(y%D22Iy~5evk-(v!RY}jP!`xI9;kiX zsRmW;3sZ7mAq*iL;A>DW(WF&7#HH@h#R2@-J!!DbmU}2KHDe1pII(c+$pKx#*g#TC zwi+gcx{XGTKJFu-h=GGBq`NE3%MYzcY-yO@0w5G%JF{x#-{Q7(#YA7m(L_DZPB^q;mobZ+lAtpT=$dZXbquWVU&db5Juv#iJd6EM0$`bZh4V45T` zzPzF!VMqS--2CZWaJX|Uvb2Zx2E(gBP2dxpki7=qYNFa#!^{%qOW>h~e=-G;DmWq3 z6%%KY2SJZheoQMEeOllV?Hq_8fmR^MdS#*CRBeU~)35_(l@Dw=Z6rwsF^5yZi@984 z&aewHS=>|OfR-92YT`J(&?UPn73GQO>YkY~r2<;g-e*k!uM(dNrnos~v)fR}Nf?Tg zU?G3-E0aMAj-=)%!KXt@NMaOFbs+(Wq}Q#NfXqk|kQxdgk|M#@0TH8#iV+D&Lt$J|0%qjK!d9sFrEoV5 zE~jlvG)8@TNla1O-3K2V(%@LXN`ywWZfpjj=VQRtTGR_Yc&UmB9;{iP;#Bi`QO=p7C6z}kN1TCgMx4PySi2&K7DFO%U<0}BQ+7SS z%iR-%m_fhD&+L-prdnvEDYs5`*qPmliZ+lAJT}@e>EOEuQy3j9-T9_I%@7J_f2dn8 z0~Ca_n1uLGxLaj(LDRvX!9qXM1>2+#Ko>L==wd2pMus%y3F1T%gdq`cOSSnZ5QUSC zxNg&+RjsT6rl#Y(dRhcf4~_~Hw(TNzVzo#t z3n5pU_8ccHNmbD5fEwLwHOo7ZsJ-`g8V@IZ zh0y&fb?z_(^}S%s1Zo6z^^qycRft7#GD7a}&FGTqz;<+4P~#<6Q;{J;4>5{qfRJwRVmm!hsV23eguxVAmBSAn@H;pSvX9EL1 zxTCz|!^DvojUXg#v!_{wnpd?4b@4(=K7bAvn4Uct77{`V)q@n8ijK~Yiotj_~={sONB+aqSH zg7N#&1B#7$>$f@A*qBer($#4rERBB$neSOzhV_9An^8-9j_Wb@HC&aN_&88s5+3^$ zVm#ah)4ul{{(|XyY$(~qJ{CA;6X$;Y z!=taJ^SEpuO9uX{hZUVl6-C;`NwN9nzP?9!pTB)N zwQM1$FKN$>hZMHt3_xBj{{?drkrjn}u-Ut&fN*8vHF_?TT_1q^?movEvCKvPecRyc)cU3}(kd@?e4Kar zI)u69%ID>Wck;09ox|)fk^zvfOcFv!AAI}m?|JaOkFkL#0r2vUml>C#hnOB`cd}r- z6ScNrybFW$JRQ((naR0o4&((vK`ihnf(->vGp3@GZVxj8Vq-l z2?$~)LTSy|rUl!O!`=(;aGEzg+pyZv@HDLFh<5#Q#v&%Z?Fkto7%XI8D_)WuUoLL< z7vn>m=)ja#26sW;Ukq6@XUu`vo>^~Zk7(u-_FjfuI8?Q6 zDGycB2>iYqKmGM@e`)u_frDC}gIePpG~UI;co%AGV!Q+K&%`{<2mT@ABEP4(bQ$6z zk1ISVn~@eW0wQv$YeBS#nNI)*i5)oOMxZ)@d{Y;?cc7?!if4~ zWf4#S=J7Gmf{APts$~uMp9<8O_m4NYAxgUbR#m5ym2^GLrg7G+KI3pCBNsFCcum^S ziYXuRY@flp)yd>*vOp#Mv9ERt-%s(3ei0b3KWNeRDl!t|!>oLczWp4E1Y*Hah4UE9RYZc$M;YWTW*5vUOrefM7(GO$=GOWTO za54A*C*Whd2SFJn#Si6Q3PgD?wr1D>d2?Ee(4MC?9|lun0p1n{LxLG_ASnY5qeAYR z1T(H>00rxkj|g?gtmZTJTnTB7pc0ecirf>5d_vba4k#4L>}XxU<0D^;Z44RH8jyWZ{k(rgR zq|Py6`><1+cL)qLc$==Ywo}*sn(P)`k6XQy28-gbY)HT zM9P(neg5yx+OxPyChHYmD(AbpB(x5hMx(ir8ks2CAPbhz*`ba_+ zDc7_?%fpWBY}ylSh~AEvH;|@A6D$~*paD~|A>W%g0rr)NQ%vGRlbd8{=SZT*{{kvR z!PW{p%^8)~?t5g@>gjay!O@jQqq1~#G73Jp@o+=1beiqXGb&4Gmo@8G7`w4U8OF0`mCyVO>88h|?F$l?wnYaSzj2bhOCa)Wu z4`RlQe>XH{b~1`c*neWDYfdLSt$*!riOmOl#ySZ0%+m^T*hTzSrq3dy|1>RK?IeY& z$y?%7c+2!MD>0qCIgKWb)d^Y()}dmxEHD=yY-54|wgG6yHsDHP*!KqvGI?+`bi5Dp z!gtEQz6JhkV8@VfWU$4xSPIZl<_sAg2Iwh--0XsF(U@fEL*nd3tI(>Xe=5!G+u_IykNiSe2Bce4(&5_gQC{RoX*eE!xGx{_}_C^@=&_D(~C{+euw6zh&OVR^snQ_6our1Xhac|TY#A{ejSK`&n za&fNKrctU^#9PVL?Ir-dT-`nt3OPcdhZKQikaDj|IU-oZKI$hZKfxBHk^m$SuJ|7r z%hu)MgxmXVKLW!3Cb#V|O>LXqhsa_&xo$*`Ti1sq%dI5xe0e3$IVqU#yga`~F;-;{ zX?#}?a=&zy`D}K=<&qV+hw1$a$h~VqoR^ETD99DX)7qu$#dtS3aw;(njlz-M@a9Vb zqDp&b4jns4GWRP}lF(Xyp#)*}?41V1D- z@##|A&;Zpw*_+DZlOWd-aPhT>q&4d`#4156VA97jY?IS|;#!1)qm|f%YrFtKa+&x=43CQ6 zyfTlh*Mo>(U)c`HT@+(t?_yu0gGTY0ZR^$30ND^sDRamUvoA| zsJ2DgoR|Pja9TtVs`m$)i$YY$^Up3oOX6gx~RXn${;!p6mGG{sZK|{2Yt1Sm^#D3LE?WE)b z&_j9m@VHnOK^jf}8DeGdw%BVv6pt-iFu(UuqgWhP+$2Qo*6#^ZQFr@W>7ozdiXbuW z^x_z_k;C&Aa^%|mi3)tSvM)$r&|w>vz%XHPDvq;s{l3um3BU627P|+ZH`xt*Cnf)& z(f^NGqh~2+qh~3{_mm_7<+U;T@bjHc?#4+*tkzb1yIlYHI9Vo-M}g{D|2PpyG{{Gj zMIblxmUxt|DaK1qL6kA0#M=rLA=9N{MVip)*@gr?FD#CO zTfJ?>PG^mIv21BM#!Y5uIR}K*{%63*6wYdI^oWn2j0f)e_J3jvs+Fu&{gj#N{Ou>! zK4U6+rzAfKEfE~@$8EXd1ir8!-T{lY-UWRex~#Oh@-<3aR6K`qaeO}^1BL34ZbTPg z@X$n}hFe9VmGmku@aKtK$ibzGd@KbQR^6N)DwCTpCTVT1)4S-p!-bxkT#$FHC4vZ8|<8$w<>+$*NJl;}O?iW00E#HA>0Bn<^Z&|4^~zP%5vrf^D+? zScH&Zl#LzJ5F*Mv4@nvR@D%$zIZ(hS>{yFx5Q!`psr%_f9I{F$h~?#4+YuYGh>Vc( zs?Y2$9ez+(4j{OwbJiUdeEX#5X`4B+mF!xL6GYH7DV&S$UAI?7j3Btqi{I?C6d1Cr8>ea#@Dk3xrba)Qtnoe5xm6i zPULQd-6>00XTI8Tqp#!iRNdOQOKLzFoE-F+;S`|5X*ulfq07+scg%3efNr5~AOmt1 zl0kL0u&5zsFe(8fo=Tb?{D9#recE)-e;Uspj|0~cX=7&f-uvAUVI<^t`Zx@>WcY3 zoO&dZr&S~S2A%Cw*Px~*v|=Aus8uQOtS5~b%3J{H;ytTj%ZHHF6= zx$~@AXg5~eJ-Z^*dn(<6`;)oULMFZLPKHNT(Hyrisb2Z3N~*6}u2B1512JzOLCo8s z*?%d-+>s&`B?$GOcJL=`VUyJ4R=O{oUOBMiw);*2z~0%2R2;=HT4qjWM6*c3LP64` z$_=%&C))>%=%cObAVJP^kxf;#+&gzzRpcD1hQ<&YjDv^m_HU=@$bm|3T}cx<4|K`z z4bt0-bbb9dmrd3ZJLJ-jruXhtqv%~_W3fXx{aBi6k6!KIOAVMl^r0>**PQ9yZuOW? z@Bc~L?Khx355$%ccz_ReH*T~%1qL;Iq-BdOg-J>bA}c?)dv8*<@H?E|ZE59|m0!`5 z35CWROvl?2CC6dQ{W4Y`9iNZZx6^p?k^0%J`eqbh0KwU_H&(FT4(zYQ#RIaxjCqqS z<=zkN#X9X>?v2whQtT|uxiRC*q|$*(JFm>&bd_6HA!QK~WfACtdi=(WVo^i{Na0@L z=z&%N8L1&M%#!ujaWvLWDOE|jMapAMdk?20xLkxPp_;k5X@ay)#mYHBRd!pk=%i$! z8Pzhh7nO_sc?&$JWZ%u z6#b68MI>87t-%s$F&_Jo_2EnJm6VkIWNJgx?oVQ??9F59+x8ql5c?Se1)_a>KIjFL zlkd1_2M?}W%Em}ScyHOC<@-2$1{YiTIy=zJFFsjuy(T{;-DNIE8sN(6jl3*fZ&rf@ zB2VJIpgJk2cBcL3%O}lhm(HFPnpmOe4s4UT%w5p~q-Bc3R@i23cy23wh}APt8*)H}^oHjmItP$d7~WV2I0pEF8ET0ec`}qe|4wa`+5Y*0*O8bCDA9!lI)`uEASo_=%_$4QUH-d z0og6(E=H`K2-`nuqUj7w04XNiaEdWB@%`lQ)@R@5;R+7~4BaR}$3I$;Yy=@kA*1 zsb(SuMk~VNJOt5#d@-h70#WT5Y4d|LpoaFuwxOybCzgpM%e{cLoh)6>3Wqq%F}rJ| z{w_~N*2a5BsEFZ(-eyseQ4KdustAySrsQR9Am+mJj?qfuuw*o{3Q1(8 zph@!~8g+PWAO#)B8?lDoQcFA$&5_QjT+YU@9gr;|YYZEjhYCdxB5Naa%uge8LYdH? zPv?OC8l#;WvLhuMp)yvjn|#o0gph1&NFXHhGlMlC;L4pGOA|O_tq(!XM`eZpzzLO! z!Xnr(&1(6QF5()2%y|lx54LpFPBml9rh3K^yzEd9X7-;)Cn7^X&FEjiGuzjmrG7OlVV! zhfD)rzlHTSATDU^%oT$ZH%IfrJND5Wf|8!gj^M4gErdIETiM6bKp>*R5GYYW1kd~R z%bn0>%qH3CMUWBOpM=zul4zX#P^QKw`HBt5_OP1d(>HK={Gkn2r9#6B_^*Tt)Z0nv zpXO}6QEzy!A-+T(>eA;O*ghg_Z&Jn#$NXEE-b@%MD3~zzA+t&PL-MN3md%(y8Vd<4 zVbtmnVFVdWC%0sb1u-WJrc4YIq^*pYE%p$>WrmBEY}#0k;WFHI>vr!N!P^)IZ=(rT6aGIb-F&FnzVZfMO3OxY|Q$3McBcK&<&0uNR1 z+qQa#zrA4*-r&;Y4Tv`Lz;Dj=pyjVV<2qcFGvwVlz+?fErAcPo>PK4{4_3b^)6mNn z87H2D8ohZ62@MA;sJ&M@p2qNX(89ieDzsIDNS^)xM1=(^q&{j`Fk`oFOf;Q*j~x~` z6>PuP&?u?%Kt>5WxS~0NhYx3+p~ZBvUa#%AN%<|HjGiDEm~N9}|Us(zjNmQ_42K?SUu zo!<(Gu$jru_^+zJi2Al&W4`*aeVb^7H%6b}lyGC$1BJ9P5{Pd1v)@|6#_lG%2LTgd{qhg)evhK@K;7Ss~+ZjxiQ!_i)?Q$@SyLSoxAUVI#EKFqwH?B2hrG^$A-;Gd4 zjX9(Y0rw0CSJ`p*j14f@ai0udX_xy6`^*meJ2X2EmJD{>UhB-;aUnm3q<6t=FFCvW zvE%l{(adYdeNbBh4$qF;MVC>%zSpvJ_@hJKBVFKXw zBb0Fz?YQsEvg15OJXJgHL-Ie$j#Bduk=t=UR{e!X z$Bx?`5E|{cR|TTjF692Z9XH~zI(l|opua<~We(Mj3lw<>Egq^J7ijcwTRf;87ijlz z+x>St4u{^+x8sznI%>yl8>)iJU_;ehcPMt8J`rtpT*E?i=B_(ZJI+jFrGCyAL44fy zbSTJ#XKA>R<1iwKSf{~!d(`^y=G$YoK}fl#GT$Ce$0CU8>>JjxIa6ju4x<-Aj*02y zo9X;9L`rqId(0T_tZm&3fS`B{Gmfm<>(L&ivLnN@07R50b!>xr;IxWUPeNQ+f|@< z2qDCsD(HG=;H8-_gg8&{wb9;vD6#5oRw!}UICKz0iDnY~3x*Q!8zG14WEq91<=*h8 z%4BoAb}^L5=eVNRZZwp5&q$k}96Q;?JlZ~#h|eYWM517H2u<2qQFgLRB+Y>e z)TxE#enN}pNs^;cp~b3mTdqe6KVWE)FiaJro)cOOV_NHXE_=SM+{+fgu3UEe2`z?s zuC6e;it{Fd*s>+CA)G;lX@R(evYjg`!j+_MP8jH5M#HCn#}1#C;f{SG4E9 zdWcaw>0^j-mlsV&$L~#tE~i5ZF)De_%oe$<<_|HlWB#d!7)>CM!#Qfwkeej_x?@CP zzjJ8N_?X+lB8zhFNSy_P#&6{J2F-1D-fnpdoubHgrh^IdN2$wOtV=of%I{~R5&Q2c z5(!Km)s>v!NBlk^70M*EG++qh~w%p17sOf!79{o^qTM*ho2?)~$^ zhY%NdC)WZHrbCg_vKNi4Ls*b&y@L5>e17z~(wmo2a8RH$X$rjWmN7sTU8Q`-ZG)P{Pub~FL?!xm))y6_y@2W!Jf zB%ddSDOrrfGVW}%D+1OIG{Y;;u1m7TX-FrTF|xWmv#s(+e~wL~4_L5CPE0JFVxN|f zt&{f7FbAbg#VRZqtzgup3JYj&+pq%7m=Xex%4@L$$22Oe8r%D+dUHb-EkVP_R3Cvl z!ob$*^jYsDo(RVo#K|a>p{>^u4ck0L8!E0#In_79%5X8EBtON(B|uubWTlo`Mk z{bkgzQ$UAm9O8eTE{Bd<&ZdQimq8Lqf0@K;1Ik#|E|v_pWNRcEf$hb%f{TqlDaF%E z`UF3GIEA)&y_g2rsmTcpOxb1;c9LJjkbO#m=yI`oq5g&{l`=ksRF(+RLZm*X45Zm8 z!jYXa6=Ad`M%Rnk&fZyB4OH8Dmjw8}K)mF?qQQ3&1`7pAb_LR@#j?-SIJ#XA!YaS> z`GXpyW$x>?L^0+X7Odyo1u|n6dWh)IH?^p-pRKs{baECA+TurDQFOFg6@kdtI&MNX12 zF08U31VWU8a3=(&G!x56Vk7Qt8mNr!Y9YiI6e1Nd+HBKg-4;Sx0=3H5y#Z#$DYh{wG|NggL^_Ew1DB(ZoNHyMC&Jb73NJ<&26Anf;)XIlG64yZ_BJ;u6 zu~f=gooAz+OJ&&kZNtuq{USZ_gf^cZ~LIzbft7;R3V= zMhG}jha>uoXdw-aS;vj*Tx@QiGkP3x#1;%=%P2Y({i2B$@IZt{AcB}an~($DtQykp zvpnstQrpx)%1~~kCCi5xX+H>6X-{D(%Temj3a4+o<#5I-k| zFZ#2^l$KGmF#hW>CuaEwVX)CbEHs-2u%p#rY_7(?1bgY&acX^j*Zk$jj?kH~5XsjQ zIn@M9DHy=p1$t1@B1>tQ!(P;c;Eky@qGRblQl%%D*tBs54NJ!z3lA^{i)@N`Z%d>fd@vwVV9=3~Y-drQJ&x38yQ1e(vsa($>6K!64wUn07qfbZ zggmPUdyL#Ne%UX57efl_donB_Bzf%-aniC%0}NinGrOeDO}TAB$~~cUQS>hgK?-DP z@wCyy5T8c2KO2(>s{%Yfiq-BGNj^;E+fc7NbdU7A3AF<3I9TS0T0oxOl>0@RiDk}B z^kI2&N8h2`QQ`h1rAiz>o%p;_9z-i$ScQ}b#zIljOg`ro2uGN+9OFozAR!R!hBE}a zKUy~CM@X+|8e-d)NnAA%2qZRPXr>7hS|hrFAh|!Wi2d9KAo`;zxYZP|nY~Nm zX#(C@7SkFYZS6dQN5T!f^Hyz_yJL*^L&FM_ir@<~m-)mP$&U5j|D}gFSQad&A!L1w z6P;>~646GJrI#{0sdwh3PY?CDfFqrA4*Z*3$cf@$OYP-P41lbh1rkzqWO}m0&1^M^ zoa4Niq%-hgNuave=u@p*RuwqkBN||r|1Mo=ayO9DU|M8CnE}`pP5KQL@?Hc>+-MRw zn}8UDGjsE4Kb|HT)#Hd@jr}oQ8N3#D8UhPD6ReL5D%#=W%E!2+B)74kWH$w2?|3}C z7F1FZwuNX;|B^e$fMPHy{3^$Gv2tu>og1_{Tg28Owu3#ZKDMHr%K>#g37&!EbjIeR z;q#^X))b&-PY}=ysI8DcN7!))icfX1#a32ylt2;}Fa9$uVevv6el}+008KL^pjzmG zcT5Gp>j8$Ula&uVRCu5G74!3X#_Sx{IthX>GkT#+75^0jk%@9ZwZ6sa5I!$9Tmvx) z={+e;QgWG-)``O2yhw(wz@2pASfafi=yMjf(r59HQ92?gj7-o9MkdyR^fR3vJy;|L z3lVm7BLx*Dc`{5;dff7nryyKUJ&z*fg{em}OZ!BiXfsR(5Nm9R!3koEW-Y;+L3)7T zm^^Ic8WD^E>o>P(Swd|-TS6*${P0gR(p-~maNKK9Bb3;L#mPR;Y~gB@DEQbJCf+7t zpPU?1W-o!)(e0@+C1Jj!&?y;Ju#hGpt6owAdhYQY1#W8;a_oIBK2?x(p$c0!LKXbG7#FsgP_k!l&LIF&WCuOW zr23G=2-RSpYh}xBP&-~B>;PTFm*j#~gYBSQqxKDFI#x%4yKb#M2*nI+gQ@NE+-v7X z=u{UoNwi~CXIczB6IH#}rfF?!k>=|%S;!D~ne#QQY&uCWB@k>66wv2(3?~W`@TmcAL>nXDLLv-&cS%m=eIbz48hobHG8o1Ib46#OI(#2IVKFM z>~4}=#w_HZR0de)XD@@6IkbeWwleqV&!2ta{Gl0`%X{`>3Zi@UF{CM^2ft3_;!1x4 zhVJ4C7#g|`(|{S%@@6WQztnrJWeuj~$Mv(LpAc4BepWyG`U!o_)9v;T#%>`r>lT4t1j6iaMP#LXhSfy0 z5u9I)#NSmDxjan7&)^6~N~;C|iRAEY_=5pY--aIro|fo3{AJc?t1)s?lmxGhJW);K ztU36j6{rCDaF~?-6Hz*HTt_T2hE*EK+%L<6^r<=HV0XN?9WyzCInU+OoydCo_>$w% zV7)hr^|BGxbL%wEr^0-+z#&q}diQ&S`t4pI*4Ml9O&}sh5r=`6ANxc4ZuSCG9w{x; zno$T#z=JdO6YA2K`Yd>sk8nWSfw8TBd1@;<*)My}rZ9C~$%LWY;A_0$qhd$7i^!N9 z|I+Ilx{lJ|ITdBa(QL1L@+RPI>y(QC2EtG9Ugjx`FF_nBOUpaqRmToV>Gsj0A+@W) z9Z)O|X=oL5I{E03P@IvemA7b8QYxp;^q%=t@iE#mO>!KJM=>cHM-2a=KKf$~wF~@% z+&EG$HsN>}pvU3tR}z7>bpFlZQj>_tLApgKyB2-M-|ayW8OcakJi|q zsNl{*62o?AOUW;Pq@;u+G?3DDw}aQC#@TB3prrIK!r5^~MoQZ?DY*}`;;EC;Sj%%s z>GY>yV&QZSXn2E0+&NkTR_*@lpdrr4&@hx4Y(c?0GfKOR?+C?UTnMD)9~+wgzp{(= zPqt6VE;7^c@K(-NWtO!gztx=Ov^iPl_(=Y3Sx}#Dq`AC;kFpr&Fkbv%b?+T8cUbU) z)uJB^quF+i5B*@Z=m*O!A1N)r@eWvRbTwXZV(mqhop|WY$`OXoO<7K9`7X)nTnwz% zaDEXunQ|A)`K2vDtjdD(%U8(d{d$k;Af}K}aR^*b#?hDK&O(FKtLixsmbbXQ)or^M?6?&>dc$M4R(?mKDeL{ceUBkN{GJ{+x-UfWn zAy7Q-MyNv%)vN_n2_1;yc}6du;^m!J9LK5^CLD;g$BGh>DhxRoS=pYyVJpmLQ`rz9 z=tUDkuee7$0_}wqv{heeDbY!JwRW~})3(?W6>XDA@^(;ElHvz8D!Yd=1 zf%i^so4>jPBB%!%(u2?FK`qda9(-O8BJJqGmtzU@YBE>O1goKW`C}`nf$=}*7q4{r zps^Lorl!#qYS3_ zI=h{B1=uXvD;2_3%3wy=vXbm$QqTlnCD$t|kG+1?82dc0Zl;q9)+XnA@p}GhcUBmi zX@HOvq~&xKY0)_G==ipLsXtK0m#y*?H1pw>#Txy2N(4|^BKI^rot)cy!1_L!Tvp8x zFOSdM;45R7&e%bJg#YU36`LS=nbicdDCSX5B3d7`;yop|SbZJvRW{u_>Z==bvJol1m|zg75PYsbs>$qhwbhNsV!nGkae$a5Tvz zL_X!^C#=th(7I6{;&$*;Kmake-2jMt+Y7nWtoL0Nj5YLgrgiKiH9C zLjF`tI3{HDW++|$)4vJn5+-(F>4K0jC0mJ=Ft>jfEAG^P9kKGp%G@NU{PEBIeqCoxNr`b#dNg+t!kfy&v^0$=&E7D7K=1Ety-~wC&H9s%EbEIF^n(^& zF<=GFr;CVJ>pFG1!ts{lh)oDnn@NepuZ>E4GbuYVDaR%LY?IQyT11Xn_)LOFOIfYy z4>z|(`Zrj`N^H^il4>P?=#AM*p0-F0l4IaVn;EW_(7gI?2!G}^yNfwyw=IPa%TTY@ zRyFiBORN8`uXE`06iJ^vCmG^OuXE)m`1(eQ8K#vM4^U2JmUm3%a#|v={P>2R1!u@{jWNk8{`Z3(B3WPMWMv&@M`^ln&~*;!0gVn|vn< zAQ)8uoK5HC>u@U-_BjK;mKXiQW#_PO%hS#P<8%uP8W^rv&rn=#J9-2VAGe}m`&3cyOIkEKTd`@9eA37$$`W8}e1YXsoJtyo z9~OCeP(;0GF#)3+ zL_E?L^@0N%G&9}qO_hdc#o3P^Yl^}I6fQs+70Hg`LEX%0Kg*^DZ1dF@6z)hj;T2+@ zxe8K~Dx36_|6gXyiqUV&jN}+9soB1uS|GKm97S^pd zVw`xXvJE@gLzGwZ$Y9r_+2c4r8Q6f&R@sM!#bmZO0OT%_XN2!E+k$Gz$ozR1w+H}8 zZ4s~wPI*xowwS1lV81S)y?}zneB+bWH*m&*G#iMsfea8E9%92Ucp+Y))KY23x_Kb= z&fO6%WCQMuzWXB{loW#5;6Xk>CE|bwxf%~@o!OU2`Qp1C_=U4ew?*sgu=kf)i3M|t zcn*}*n2!Tt3Mh8TOvQo5h{l1iil6}%0S$2=AA5@&sNq>nlXY`Au>Fsz|Af_jK7mZk zs-!$Y~3KU&t{4z4b$M76)&KZXf&``UVTVpPN4KsfF+Sx zS_Q z&ZboTm~a%6)clA9i{TgiYJL>B)8ugx#O0HK%vac%sEh}&pIGGDRlmZk`jh|?@`P6_ z_{@N$3oNq*#|}ahy{@bDdtDlRf*&yaw$y}+j_#IzNBBs%h=sB(5-w&e(~+rnyw9fI zr7VgLJ9#v52^WcA@8=E*9(^W}fd4D!^ z9ID1oer+rKPg*^fr;h-7X#)E?nXoYzo~Gwzg%veBbZma3wUyW zHAa5y)6?^~K~wqZqjj~`?!6OautP(SSBZMH&Iegd*}5hyfSY~u1EQ44hG}h|w-mmn z)+AT*ptdr(d`*&45NT5@{|VSzm;-bm>Ornww%5vCX0Bf1x7YA-RDCg2wiSdSBJay= zXZu;&dm}WY{XkF_^Ocv5$I8AdACr2yPPz0J8wvZU*q~Iyw4~88#w>$l#xe%o~~zhV21oqM-!y}sWCzuogh9`-#A zamFS|Nk3j`@d0n<)EjiqGkn*I?(g1SW>=M$vgNo_F4;7lBow!;)q)q>5Swg8=3?>3kO{NvXwv|#xs`v#EwgpIDzYT-zBSM(=9H-Gtv1|3!6Q&EShB>PS z&hiOi^J%>oDSN^{dBcZ!@^qdcn*Ebqdh&BT!MyiR9?+BJJVB=UC*RYP1-%!w2a@du zVM#9|k08N3*o_4DU=?Z8DP+J&D?$#~+|5;%<(>Ksy&jiUgNeM^^jYFq6V-xm9t92^7@EJx1@~CFaRZ07yvxD7YzqMgR7B|(W}<{p3ZD& zoCMh0#Gc8E{REZ2-jFWfFODQCiZ;>xE5XW|Yx#`}xkf)^GpzdDIJxl%Bo!@3GcgbIm!|e66{>G49kGdyh3Hl(VXMkKFcf zRl9r^{twNxchc#oe@=c4P|)TFbL=gk5T9a?Kggwyj{IIYrkA(h;)+y2~}H zljUl2>S;b*V$g+-+bvTdwKW}RSy}k&_>q$q43$p+vwwAD3Fh0ujey?g^rm6O*Xn4^ z4hj)4HGg@gh6puUAtF1dHa`~IlwiXN1v5zZYHO)AI^&%>ruQk;hrx^g`FOP{D&CvK zON1le>rG=M#MRsAW3W`T7n7~1oqanTwP?R2+4gd+K@5|1$ubJqn$1IJxHf^6(U#R1 zm5D;XcgNol(hf+6w^3@f;v_3tJ$z%(4H;8I&zMSCG=4@#5z_yxBq=}nhF9~8`v-pl0YHt<;P|L-jmwlx9c%u;W98!5Xs%8h3U=@TY?4j~-Ksk8`?Ek-d{JRrz z;`wn>)YiZX>JsPEvg8*XB}69F}Fw)XWG$A`A&M%PW?bx9&J)NFt zJEMTIr38W#4$;y#=vQM9>tTTcwcV~cSmU>^p2IW zw<-5MX~9sRwsqKF^^}xc)?@@v!kU&AlHX0MUCi(0)t-t!afGZTG9iH$6KzC4MI6PA z=vpW#x#@bC??iWeNpC#GHrK{G_;<|95|mfdk-sOojPL3`mq`|i>0)-Xb6oRIar63Z zuZfEh5pGN2lS`F96PPdGLyNW`*Cv5?3Q&JrD$K<_+!L>jC+v!%o`1J$!lWw!A0t^z zE|c=Yk0WW{3H%gj)ODD|EDNV10X|6!(ksX4su9Dx8GFPjgHr7sQ7>|{;yGnl>Y|r* zi3%lGYUWB{kuvDqYtH`3w|T}P1kdE+jOv+A{TV+pf@kdT*!aw85)%a|G(iM@Qr#+I(l)?~nEdRyRm3!1f5y*| zdx40Fx>%=8Og81~5ECAw=Rr(V>CH`~o}Of43uauXn!ZqB3gVeKMUW;Jt6=`GNnt0? zGba>RhfT;FbV{0b6|KdsD|TCM0B|hvlvev5T#uF>AC*WfK(~Q{^Fx71Y?VDLS#xs3BpL}n z(5V;gV3<;beJ!aCvqAX9o?J0fZO91HeC0^B=Yd@iI1M~)OM86f>xs_QFPeSAh7g)i zCIB1H++^vXUZ3J3JfUQoyjw@fbfm0rt{8Kkx~zmPNvo-?19FUlNLkup)_ zibiXKfKeedZR;8KXpHn?g&MmfvOZwSk`R;+%m2ciiiM0gfPVj|Pg(;bBf4eo#S4)R zioC(f(?h&}WrsruaBt%5n?}l^SWdzCcADC>QuxTv{LXzUQ@Fk0ROXN!gE+PT&^%5} z037f^9IFQ$ykj{t0!$!u$e(Du2G&9Run9J#cUz26wqa_=G>L#ax}A`c5CQu4y!->R95aF5f58X!Pq;enQ7_btU!s<&G^ zGvXtKh(Y4E*5j^vj|!z$@31M0zE8481nXKo?!qUI1CX$N3tSJUJZY!vNjrgI19e&@ zJfqAS2L;NctS{^gt$}|MQ3rUX1EDu)k^F$9-ePFiP>Uy)EH%ZMyzZ*%{o-eBtl$7t z6>)%PW)W*ct)U-7WV}{K*_hSF9Z9*39nBP` z5%&B8mv}K_DMZYw_zkyrbMTKQ#3)2;vdpSJD?-xamS|tBujkNp#5xK4WksHS1w<_= z&(;-(btb@yOwa&4t@gnR-ybvAH1k~^{XLylf**pp4a9H2*kTXjYePfv! z1@8?_Sx9k0PjgmRJzMJKlE;TG>6f|^*Alb2Q(top>YEaq)u=BIGFa4?ub{qwW-Wsp5g5cp~Z6{d&4M_7+$P+lZ12p!7<-WVmsrZTKRj%p?{cYwOU>3$0t8nudc znIzG!N&_pmfR!OoEHFZ`=5m+{RFD`}p@JIC0)d!=m>4t!B&>2!fud%JIp|Lx=!2Rm zE{a|gQ2`1fr;+G`qN{-lq+1Sw5b<8oTdk*n2v%$bE+Zy58pP?%KGYNS+Z6%oE zC1fQQQE!l#`W_;4=|+ij;^x32JQr9*Tgt^EGc@7p2ouZ_Fk*=!jxb8ot65fL^1*CH z^_=ImnTA1t>}n8@;)+2~^PWLGfB1W%T@3&-h|83x7J`{E?FMqjN-Mg|!U!!xD>r}U z@ul*y0|H0o8O%-Dtp<5rTus0xA6tRbl^=fe_+bfym0T<5UA1A*1b1C^un)2BK;*$p zNHU>SY1pmu7F#6wChDO>RtdN)uSVbtExE7r#&cCqTIL!<;!grCiz=1tcwR6!k(Nor z4s<&#i3Cwltdxk%BIixUFL!0+nfam-|C%W)_RUkPZeX%aZt=n8Fr*+RsxWy`+AtT< zC0RH!uoXB;A-Xah+U_+hj0w&PsY4{uz*#bxY$FR8o5e+zspb7;@3<=Rn z=~Oy0SsA7gdtG;CRrS#GVH>f>)T&u>voXa&Znjix9tgSF7O!txh8G!#2-W$6`}I6R z5ll*nHw|97u>24Kdkt?19y?}(K16gPi7>P(pY``p+7#rzBaa*Zs?i!)UUWWEi#~O* zK)nF{h~v0u^+8qa#;KQvqp!$)wIk`cY8BEMb0{|l|K2}*@W@A=N?zNyqi3ABz_ZZc;0OaMwt+ZptZc(h5TfKm z)keOe4ar~?YDd5;FCtqHwGkq|S~o*VjGi!24u;F8)KfON zLQ7x;t%{#8K*@->*8$|g3x z<*CD9h!k`sxLsbKLM9O%j^aZ4xO9|W2%+$8pV>W-nBr!nq))LNm)m|C0}6V*s(d?k zkk!TD;`t=GFpWy|waq3D(%_IhFc-`66Rn^QAi%v9a7|@@X5cC# zmP`AxDvG%$K92zD!8} z7^iu7Q&*0%K32B0tnme;g3XtxbD$^MrA^!T39|QHEsRf~(R7Cvnz+iSL=LM0T9NaR z!`~s^8u}aS(`mch^3zahJ5uSD&?k&hr#u+jC@)~uyf6ae8#T(?rT$*#SZQ>X^AolO z-1`SXPO_kL0HKjip#DIE3lYop_7>FMSz{XXnQ^eR_rqC8HroluDQ;}}C|l!EdXiL) zzrrXNvV+dkmz!1)g-~H4Q``_~1W_s)!Kz(NBNoy+*Pu5FnP}2lz_BY?bBW6sH3UXc zvW%gs{aLmzj)mdBXPVcL{%D>vmM)1~^MGBX^heO}YVuPPZFx%y?(8Jp5go_%1b3q98NmgD!-b!Yairi zhYdOySXUQD%nj5*9>9HDw0>Hfn>uoI`R1k!YDejj3W@&EDrYXlq5TGawf{Z*_;0V~ zMHG!@Hvq8JHz}QuWd%4pxJ8DVvcCa08Mc8NldEhi*Om_5-=B(*Tjf8ovnxMjN7j%j zjlrpn49RGVveVl)FU9=y^!j4U(sTdxgYSLk@BZeK&m}ipD}RkL*-z;OZF&Q$PMNVO z+;kd3!5pC|Wrn_C+mr3v47}Gc0$g`^yIA$9Bc(jNwiW~~4nE9rbmbe6CLp4#+&L6s z#>=KY&|?qIAK;L#K3W$CNb->kIW11H0nmkOWJErrY*ENfUet}eOJ@C0KEoF2j?%-V z{Xw_W#r9$wr*z$y9vk%zjiwZ404ixBwfz3k7IJ%WG138}HOGz|QJ{n9L@|A6gi~tO z8-}BHvBfg`c}dTCu4(eGHF%(|_hFAI+lRb={Ac|6McyboLX=^c1Co@B-65ZR+tnko z48c4K7!N7PLHl+|S=C{LzJWle3^kQvW(F`{_9Pggi%CXXSj2qUlh_kEskU~3?K#+| z>P>mIJmGe{+DD(z8E=waoE?s(TFeLz9_HjEf0%RSpu@$a7278*l3HAgNjtXB799Mb z__$;H99k}^Py2MI_QhAU&sfwxCOcbpWBc3&@Wo_0wm-cmA$N5#>BjcEd(c?8fF183 z(J*c@wU42#_NV!vec_t+0ems($M(r)#u8pkW@7t1K|71dY;1paPlCbE@prL(n(BG` zeQ$rp+n@FJLF-~N7u%oPL%l{WY>4e|*pqC~g^jWOjeC-fx-f|C5B4MjZ(o%jfq#Ry zPdzTdKR|+!vF~&NE^)?A(1k8(_3pDsueuwq*_Kur;~}~!@-`Xa+(}35j1r&9T`BW1E<&4VaeJxNB+tI;2o>^D&rj%Q5NX*Bl~Xr$$FziJkU^+##Hb0OM;K zWnpK#n4NNj8Kw}TWo(NfuH@lq>9xVGT*eRbm{N@zM zi3ygIx|-l_oM0r{t4z`}&+rZNph?EBNtoPsjv_#`%ukzRZ{h2@Q7A7;pwnqh#t*mHqP?kP$uRR}%l|Vx zgO=C_v*miuw{I3_Xp0u9^7LpMweb9Cqn7glnhq17OW4o2LNPfl`jViCP-h5lclc>x z5|AhD)ngf0pjb;=mXg%)Aa(kRcz*s(PnuVI9JoSzFBM#!9vf0 zWY;8|(FV&k#$M3##kOPERFInpsLf$!odc18?9yzxQCek18mTa^^*22vHfL)2t+PMf zx4J>duyIQ-lX@m+z&Roso+)PK8sTzUve?f;fKayohBjx*Es-E8lE~X#F3IK5J^EwO zukjEZt=*M&nwa)5p4vYn8#ja+<|%U@hFk#yxvAAGhP`Fm&TIYU2GV@Iw-JR|VujIC zaoRi-zK=H1e z%PZX4-P^2}ac=Mzw0%JU_Ts3lH#Oo7C$?obQvh*1Kx=#<`6bnMj3_wQK+?EQ8z1NO zHJ$fEp(in@DS@vXxwTg`eKuvy}0D;=)eyY3`hw9rQUI><`4)(EW)&4%Q+G(=H@tET4n(XHD zrrwAF^2^GP&+WM%WDQ^j$xBs?wTc zWvny|D{9ceQOMG*77+>*Vhj8DwNFE-f$o>t1@Ogp(ye*oR%%nmU8bf?Dnvj<7j=DT zH~pgyO>|!CBAl5g9k8MfIlxb=ZNdPjzHT{IcKZqNYYB|iV~X-(N6%J;Q+-JS-Xb?E zWyk8CE(qAuvGcArsYZjS);SA^Jn1=9qtRgIXV>fODTMB5Yu62ct zuJg9hRq8r4;AyjQ+v_}T#@vbXaZ_9C38Wc0ceUw1SL(2obxnV%ye#NBrL1Yma*(}VbrBEv3 zV4(>MJcN4tFr@rnnKF1aM>4j?T)IQkw7`2+MuR3y4f!(=2rdv!kJ7Ky%tMyZdsh{C z-;23#$LN@-pb)BQ&%O&;3b)K>S%3{P(GCT_{uM-aC>I6sU{!F%(Onq zwkLfAwPwS7KBS18q4nWR)d4OyG~pM@%13NpIpZKCN5sM+y+R?jK28AnCi7U_hsXvYnUrb1#G6|U$oDndDo%5Jlw@=F8^7uXZz7S{>*u<_$0 z0Y3(+$Fj#M_`4bwB>b=?zi^2V3P8R6bKT9MFdhCecf3nng{b=@BF}u|I zc{@S9nKrXroPqTkL3uW<=fd-@_@j>cE$hjt1rV1w8C z5-&1qlr?){J%R>j)HezeY8o^U($6c2rI}tvOo`I(waiF_{GLR~a=LUspMm)A2c=(? zoj@4TU8x2VljdHRhcbG~$|r#<SZ+XBl-64iRc1 zdn=CVLq(_9tZ)r6e#{4C69I#2FpCUL>ZK-9O#3lku4)YaQE@GiSI0TQfjk+o;Av$u zNGkqj__tYkmci@%wle3CZzsu!?-z<|jCh3igdPwYl(srgv2Da~c=PxzW5uH<+1u^o z_ly-$?F6)ho1{?CT^?d%qZD`wP4%QWk9rDymI-TWSJ5cdL1U{PFW$}WMF#80(6%(z zG0X_x(KGlrtMC;bA#DXR7R_879-*~*E1LM9^;_C65v{yQxhA*tN?CK1kqDjVn$;VO zbA($Bo%b^4+H0w3ayh(qPY`Wx;+?p=!&P@S4X)Ck_%$;#3`(1Y2}91+$K4_#X-{-; z>L!~VsL0}36VR2F{xC=D-D9dLRu-7$p&D`~ae9v-=Zb(*vC~OdfuK`XAj6Xt)sW4i z1f&8PaQZe2jZWGuG=Dss<>^dOwOi68+Z+D@J^8z>G|v-E8HMYPybB)hDqB|>-nDF9 zrHvERTYC118=v{eXCM90-;?1R^2L8k@AUN!d0+7z0)Y+QNeX7G{D7Xw2UqAqe1Ijd z(Y+z{TD;g#Y)~OKi5jRJ6o^s6bVn%9-lR}_EK$o7^W6IWe_qDQV^^QV*;%}TOg@(n zL@4!cxxB#YwAH?;mhCS4*5MmC<1W6IhY3)-Vep}rC+U(u-8d8U6jUVB|M_ON2c|zO z^QfsLM!pf;&Osp)+S0nC^uD~@#u8j&-h~7|1R~d7rR^20>o9-$0p%gSObeVaf&^h8 z9olGm4n;$GwezNKVzZGis+Vl_)gMcSO+lWeZ-7);X1VCdn-XBc9idtEW%jQ%kaD57 zfABR6nyRJwGPC-3(x$6Os%~Hem$L_Ew&WfEuc?nL3BS?~>29WmhC)-y=Vs|HO;wEb zhq$PNRmm{{9>5q?)RKOk$GtmG=Y0y46Wp3hN;mJ@(jMp(i(SOK2 zB5jq1LSko?9!Q2C^pik8%&g~j8!Ff>8R#de=qC{wQTMl^A9@x2;JX+7B<10IMOV9N zib`@uLi*+;q;Ez-nNqsh(wD1G={v!mRZ7|9KZ&YF*y`IPn~mLU3@+_(%GNxvb> z1<{jhOH#(^0jA(c`tYK%DD?hFOL2VFm7K{v8W4eUV`xeZqCu!8A&C;8QTVVA3>e!3 z=Y0*HBt@HEt+udIed9(7>{a#@a1W$nG#B7L9sC6IQ>Mx-QDTcl=Woq@hXuQVQ+P(a zqV01dUKGT+c!h74k_VMru_h>Nom5!*sj-AMJ}a$Ab8;phXhw-xA~nO4UTjSzyH&X0 zSXj&IP3(60ps^Xx{{%My%G(t%&L0f=H85xBkPgsbBYfqz6M6=LJf#0CuT#l$dN_+p zvgg=SKU;ZD$#@d@eq|CfvTR%VuuBgEg(+p&h=)3kuFm@bdqUvOw zO&MZk-;|;C_PCoew6+?l{V2xvTeY$M)(>%PUuk4*=511Fl#m>$%}d$qN1bCuM+VeP zlL>A#;lG5_Mc^xEuLaK$C-dDn);)CX#$Mb3;_e>Bq!I1Pnc{=uh`iMtrrcFZlDDD- z&05hyF;ogO**0X^!GOGDd;jdVTb<#sPN3Kw-j6k4-D}IPNU{B1Ua`gAg3k`Cm-ClY zt-wFi!ACk*mv)6qdk<8X&JCBSU|wCjAY3DnrMl)j%M(=zuC84go+D(+H6`u?-9aw? zGeRf6pjUxsy*j2GDMFOylwB+p%&!jDNXW0QT@tQgE!a3r%w85+WST<#2+gGWuq%l^ zb*0<=__T?KNitjS7fC^oUn25r9OI;q4UpfQ$ZybWwL4SO-CloYc3`AP$^HM!#$@hX zA5tfPYDq-TEeShN`Pr!+?r;45K?oEUi^@&tH)S%75kfx(+nLy?tq zm;h7B{!F9~>4kzR4n4vYVFaciEu3}F>-R(-f^$|2CEsm!pc-e<7Yd*-VJxDK61LUo zC@N9CO@_W|+peO(oVZgX`r|QqB{IB`fbI2J-w`j)S1%s2^=sFJYd7GF3{wSJzkW>C z3TlHL(e?PEzdJ$e=b;hfjg;D1@$H1rWAFTl9%%Zu#r4<;0VaRh`dv6!6LK|(9|_j= zz$Y)^muS>x%3CM`Qf!9&(plk>Ei!&-cer$aZPH#Du6b>7f9|4i4O4k6z4meOpPexz zCo92WSXN{&%x+iUU?K&;v`Y_ic_=mYc2ZiRo8$*(rkZKHk+s_Gq>a^rh`8mKm)(4Z z7Pj;I&2J08`z))P+7x$V`Q`gQb0??trR=d&W#aOkda5l0nxa3NUwi7C_kCDTVHudw zSpJ5dYME(X%An%K-_fO9m(sE&%ONe_$0bI{C7MJ9E<3KwyD6{y+(!5J+F8eyMUPuD z7>g8st}+PYU}b*n8s+6?Ii;nJ!Kr_N8)h*nZ0irmTug@LU!e@6jItqOWLjVp+1eGs z?oB_Fos%vVhJ{1ImSYs+bnt++#-=BAwRMO^EbH~GBC`Xg_=W!4q0dssnbO%n{bCJi zt2X%L${f}r*2$salr9SLod0{jWJRClJEi^_b)20OFa!3N9m3V|jn5btYF{l$LADGQ zZ8ibH271Yx^tTaf%`#HJRA=yV>8`tngkPk3ap0uT)Y7hLb`P1i6KPvC9c!cnGzY&1 zs&rx!#)VFr!t#{^TnZZX)7dET3alEwy+RQHrPwox+{aCT82~ma7|jS@gox5ZEQoAx zP%1pz%mEJ?Z1W+KVkY!%Lw6~7udJM%EPw{@ncxebgyts9`)4TxXZfz`L)hg+GLT z?%B*+>WZvww)qF=Mg`=%(zJ~;3ILck$*Ga6_oDe7P!H<6baXx(Lca7MvfytH8h^%U zvT8Jd?9a+;fdW#~_(LK(4SF2{WxbEsd*%i?-K#G zVETT!W*&Z-*<5A%P8G@08xJ2oylkbhSQA1~0@=TI<8cmW@gPqyf+gsf8Hy7~1B1E9 zhv1vJ`nZ6X3U<$abQbX)wIScJ){wCpR+eBm9c%yIW+EBB{y$@enQ60!%^nGs2viMm zibjnW!@|KP2z$Dw3LM*F$K2{2tbO%_lI0V+WHOW!^=#eWNrdL_ zAGr0-cYfxtiO{?bebVfOwESAFK`W|~mfzK-IW?G}JZkk?NRsj!4}AE0rkl21pZw)p zdCF8w@G1#BrK%5=1Xfjo?j8MX_6@oA=c~+#Csvt4Sua5&1#1^t3vA+xkKBsxx?Kv}PUg|pOJ|!2CfJ(l|W~t0mAXdpY zb8-$$p>l`ux3$h^Ns4T5))sbRGsCvUGipma%N7@LZ)beqj*mF3wJ|l>hKO!zvIP+x z&Ti6$WU5&eH2NabM~FrPzS7lP9rl~ZK}rIg4f1m~$V*I-#X7M}WB$5}K&vd*c4qs| z$*vOEI^taEiV>VWo(;XKDWQfw>_wFXW1+6K+0(ua%k6H-MqnqAx<4OR3*WD0yD=Zv z3@Km1_9W_@qTS9NvtYiqbhHLCz{YRU(@fC~+eT;9le%M-0CM-JWpt5+^jJb8fI zZny#H@=J#sm(t;!L*D(0GUhdQ*Wz%3*3D5!M)#FuIiwz$56Y2_#>*nB!zz@f{#%Ekx|odrBw^P+o(TAYsO?9h02AxMIw!xk8GIzW+&$%2V!W6s57 zCjm#pk_&V#bmgbtw5(O~A;ZEhub-Bp>7)I#rb8IwL#MyF3eJPVu3ud_=27%7I49sk#U5T6!+MUKtQ{XC9n~8FaOZ>Fc%;m9j5nJ^#s{ zz7h*KczeV=OUcso;G>|F=$6WKY3L#Zeyf~2uX*#=Qdg(_^Dve@pg~XwjT7Z=Vv0A&{v)+0(cYAR1tTo?d7Wk1ywC)sw=il4r9ec%+oA;~eTrX0kq*x3;dH*Y zT0xClAr|v)Nl&nKN%UcwNJqP6C`N=PLY*%84=qd0w2_X)e7n*{V#nK@C@XEmd&tMy zNbcH5#}6l=ry=!th8@){%S3&#p|Lh1(r?-Qnl@rDgzhy9?VycZ?rO+o0)x_a?uObI zwGmu2G?d|JsWcIOG|Tn@BBM!e*-LrQe*fS*fBNW$zJm6f(Z4CXd3ozC%fZEJIT#|k zyu3{pE!l~*5S~Q1fkG7QdKYS|G1-B%n8sxD(qi&1V?>rgoU++~E=&@K z0*)<(@i(P%T!~u|TwDA%X_c=*N2aT4cKcXD0)e=V%RXn8cY9BORU4 zDJOOj#HCcku2GM`kh47$kV-v&_^JxPLGZy-?yyMGUWL)Zg?R}$7LOMQdl*%T^o@XFR zyQFRnIknOyYg!%sU%n;Lq#iH8? zLMz3ode2N4=rNnt7W96m)CVX^RmS`SZD0zzIKJooJWf~ ztD$91pkBZ4+a!%>M0*v$V~SFd?Fe*5_hz>o_buk`+)@R>!W@~{XHk!0AM;nMR?vtg z*nEk|SRznig7dwm7TfxW8x#^lkxzo^;j5-s%Bl1Zi>kUBWAZ3yJ5NS=q_;IvTlGCI z?9r(9_KfCOZ#nS6cdjc4ki8 z4r}g#(ZJ|pquQAX>kEhdl9^uQR;ABM$)C8bS+zB5ZEa9nR(&3rj%O&GE8?UyVG0(% z3l`a}+gN|u1D{E#`L)mDf-^6%fWT27&^)pk#~7Bw@gNgu)t!Z$o!Po&!?MZ1{{UJ-AgG4 zicB)CY~z2DW0zEV_|FmEJ{eb~MYoZPLDMIri?6QgU+gQ?Me=rtTrMjtyba}>nCi(W zl6M^m(}t^1MlZU7l`p{TSa{Sd5L}_u&ax+G)>uUX(Aa6c zfa{kDk2vn7h3p#jg<6&%8bBclmb?v}8py%;#H9Ci`4ESHkQ}fYg_hpzj^8Swz)h~% zU~Zuh=VorHPBH|Eti|zbW?0|xir5k`0%9n=Wiim#&einHUh2O*xb?CYcGT@5j*th&ffP}{=`CdJL{BCb6Zf-k8o&)E4Xsr$)4+L z0h+DMELJ!I7g?GJP(=uyzVCB?WD$axz#i(GIPWPD!5qG=njKYdV|KC)L)K&qGL>-n zQZiJ_&um!AC@SX;UrZvmOFhb=rK=XrQF02s)iT^qN zxV+bjpcOkKYdhBb80=ZEDcMHrH)Wn4tzv!m03WvQ&nKY)tYep$J%TY{rV@6^6xKNi zZ&%%WwHOSv>3$bf0F;mBEvZ^y9?hs?9$_+@M{C*VQ8_MnEYHra;R7A@Dn3wgwbG*E z9&|^KX>JZ-G(H?b-C`3iWG_>=Nf;8E!is2G&_RhL7#Db_f~^5;p-9TWRCD075dxpt z1JIe78xg()P&PVz=u?6Z6(GVV?xPE#gPFI1N79ImuQzxb0pWr3ke2IU05y(XpPYv8bc`Y<8>2 z3Y9BWd$wmH(CNTC3|hH*6LdCyO}QMfS5Wzp67V>3g)^`u2zg2nqJtjPQ>J_#vS}sn z2=6WqxA3dd0MR9<&cknFUSA8JgmpneSNR>rO@-|{M*Lb{kfIdeQBevrUaxSWaS$Qe zLdk1Fd+-`DBI=tO24ddISik4xYek|)y}jTdh6-}=VkBj=6>B1C+W5eY8NAIQ+#~

&A7ZcHB#wSay}#5n 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

_3C8*ng}FycPceG4wG{it=vhliz0ZujXI=6H73 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 zNxibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - // Compose the IBC transfer memo metadata to be used in the swap and forward - swapAmount := math.NewInt(100000) - expectedOut := math.NewInt(99990) - - swapMetadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - }, - } - swapMetadataBz, err := json.Marshal(swapMetadata) - - s.Require().NoError(err) - - gmpMetadata := gmp.Message{ - SourceChain: "axelar", - SourceAddress: "alice", - Payload: swapMetadataBz, - Type: gmp.TypeGeneralMessageWithToken, - } - - gmpMetadataBz, err := json.Marshal(gmpMetadata) - s.Require().NoError(err) - - // Send an IBC transfer from chainA to chainB with GMP payload containing the swap metadata - - s.IBCTransferProviderToNeutron(s.providerAddr, s.neutronAddr, nativeDenom, ibcTransferAmount, string(gmpMetadataBz)) - - // Check that the funds are moved out of the acc on providerChain - s.assertProviderBalance( - s.providerAddr, - nativeDenom, - newProviderBalNative.Sub(ibcTransferAmount), - ) - - // Check that the swap funds are now present in the acc on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative.Add(expectedOut)) - - // Check that the overrideReceiver did not keep anything - overrideAddr := s.ReceiverOverrideAddr(s.neutronTransferPath.EndpointA.ChannelID, s.providerAddr.String()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that nothing is credited to the original creator - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) -} diff --git a/tests/ibc/ibc_setup_test.go b/tests/ibc/ibc_setup_test.go index 54264e685..51477e833 100644 --- a/tests/ibc/ibc_setup_test.go +++ b/tests/ibc/ibc_setup_test.go @@ -5,7 +5,6 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -20,12 +19,10 @@ import ( appparams "github.com/neutron-org/neutron/v4/app/params" "github.com/neutron-org/neutron/v4/testutil" - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" ) var ( nativeDenom = appparams.DefaultDenom - ibcTransferAmount = math.NewInt(100_000) genesisWalletAmount, _ = math.NewIntFromString("10000000000000000000") ) @@ -338,38 +335,3 @@ func (s *IBCTestSuite) assertChainBBalance(addr sdk.AccAddress, denom string, ex func (s *IBCTestSuite) assertChainCBalance(addr sdk.AccAddress, denom string, expectedAmt math.Int) { s.assertBalance(s.bundleC.App.GetTestBankKeeper(), s.bundleC.Chain, addr, denom, expectedAmt) } - -func (s *IBCTestSuite) ReceiverOverrideAddr(channel, sender string) sdk.AccAddress { - addr, err := packetforward.GetReceiver(channel, sender) - if err != nil { - panic("Cannot calc receiver override: " + err.Error()) - } - return sdk.MustAccAddressFromBech32(addr) -} - -func (s *IBCTestSuite) neutronDeposit( - token0 string, - token1 string, - depositAmount0 math.Int, - depositAmount1 math.Int, - tickIndex int64, - fee uint64, - creator sdk.AccAddress, -) { - // create deposit msg - msgDeposit := dextypes.NewMsgDeposit( - creator.String(), - creator.String(), - token0, - token1, - []math.Int{depositAmount0}, - []math.Int{depositAmount1}, - []int64{tickIndex}, - []uint64{fee}, - []*dextypes.DepositOptions{{DisableAutoswap: false}}, - ) - - // execute deposit msg - _, err := s.neutronChain.SendMsgs(msgDeposit) - s.Assert().NoError(err, "Deposit Failed") -} diff --git a/tests/ibc/swap_forward_test.go b/tests/ibc/swap_forward_test.go deleted file mode 100644 index 2385da68d..000000000 --- a/tests/ibc/swap_forward_test.go +++ /dev/null @@ -1,96 +0,0 @@ -package ibc_test - -import ( - "encoding/json" - "time" - - "cosmossdk.io/math" - pfmtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward/types" - - "github.com/neutron-org/neutron/v4/x/dex/types" - swaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// TestSwapAndForward_Fails asserts that the IBC swap middleware fails gracefully when provided with a package-forward memo -func (s *IBCTestSuite) TestSwapAndForward_Fails() { - // Send an IBC transfer from provider chain to neutron, so we can initialize a pool with the IBC denom token + native Neutron token - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - "", - ) - newProviderBalNative := genesisWalletAmount.Sub(ibcTransferAmount) - - // deposit stake<>ibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - - // Compose the IBC transfer memo metadata to be used in the swap and forward - swapAmount := math.NewInt(100000) - chainBAddr := s.bundleB.Chain.SenderAccount.GetAddress() - - retries := uint8(0) - - forwardMetadata := pfmtypes.PacketMetadata{ - Forward: &pfmtypes.ForwardMetadata{ - Receiver: chainBAddr.String(), - Port: s.neutronChainBPath.EndpointA.ChannelConfig.PortID, - Channel: s.neutronChainBPath.EndpointA.ChannelID, - Timeout: pfmtypes.Duration(5 * time.Minute), - Retries: &retries, - Next: nil, - }, - } - - bz, err := json.Marshal(forwardMetadata) - s.Assert().NoError(err) - - nextJSON := new(swaptypes.JSONObject) - err = json.Unmarshal(bz, nextJSON) - s.Assert().NoError(err) - - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nextJSON, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with PFM data - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are not present in the account on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative) - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that the refund takes place and the funds are moved back to the account on Gaia - s.assertProviderBalance(s.providerAddr, nativeDenom, newProviderBalNative) -} diff --git a/tests/ibc/swap_test.go b/tests/ibc/swap_test.go deleted file mode 100644 index bd8f47ca7..000000000 --- a/tests/ibc/swap_test.go +++ /dev/null @@ -1,173 +0,0 @@ -package ibc_test - -import ( - "encoding/json" - - "cosmossdk.io/math" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - swaptypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// TestIBCSwapMiddleware_Success asserts that the IBC swap middleware works as intended with Neutron running as a -// consumer chain connected to the Cosmos Hub. -func (s *IBCTestSuite) TestIBCSwapMiddleware_Success() { - // Send an IBC transfer from provider to Neutron, so we can initialize a pool with the IBC denom token + native Neutron token - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - "", - ) - - // Assert that the funds are gone from the acc on provider and present in the acc on Neutron - newProviderBalNative := genesisWalletAmount.Sub(ibcTransferAmount) - s.assertProviderBalance(s.providerAddr, nativeDenom, newProviderBalNative) - - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, ibcTransferAmount) - - // deposit stake<>ibcTransferToken to initialize the pool on Neutron - depositAmount := math.NewInt(100_000) - s.neutronDeposit( - nativeDenom, - s.providerToNeutronDenom, - depositAmount, - depositAmount, - 0, - 1, - s.neutronAddr) - - // Assert that the deposit was successful and the funds are moved out of the Neutron user acc - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - postDepositNeutronBalNative := genesisWalletAmount.Sub(depositAmount) - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative) - - // Send an IBC transfer from providerChain to Neutron with packet memo containing the swap metadata - swapAmount := math.NewInt(100000) - expectedOut := math.NewInt(99_990) - - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 2, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are moved out of the acc on providerChain - s.assertProviderBalance( - s.providerAddr, - nativeDenom, - newProviderBalNative.Sub(ibcTransferAmount), - ) - - // Check that the swap funds are now present in the acc on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, postDepositNeutronBalNative.Add(expectedOut)) - - // Check that the overrideReceiver did not keep anything - overrideAddr := s.ReceiverOverrideAddr(s.neutronTransferPath.EndpointA.ChannelID, s.providerAddr.String()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - s.assertNeutronBalance(overrideAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that nothing credited to the original creator - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) -} - -// TestIBCSwapMiddleware_FailRefund asserts that the IBC swap middleware works as intended with Neutron running as a -// consumer chain connected to the Cosmos Hub. The swap should fail and a refund to the src chain should take place. -func (s *IBCTestSuite) TestIBCSwapMiddleware_FailRefund() { - // Compose the swap metadata, this swap will fail because there is no pool initialized for this pair - swapAmount := math.NewInt(100000) - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 1, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with swap metadata - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds are not present in the account on Neutron - s.assertNeutronBalance(s.neutronAddr, nativeDenom, genesisWalletAmount) - s.assertNeutronBalance(s.neutronAddr, s.providerToNeutronDenom, math.ZeroInt()) - - // Check that the refund takes place and the funds are moved back to the account on Gaia - s.assertProviderBalance(s.providerAddr, nativeDenom, genesisWalletAmount) -} - -func (s *IBCTestSuite) TestIBCSwapMiddleware_FailWithRefundAddr() { - // Compose the swap metadata, this swap will fail because there is no pool initialized for this pair - refundAddr := s.neutronChain.SenderAccounts[1].SenderAccount.GetAddress() - swapAmount := math.NewInt(100000) - metadata := swaptypes.PacketMetadata{ - Swap: &swaptypes.SwapMetadata{ - MsgPlaceLimitOrder: &dextypes.MsgPlaceLimitOrder{ - Creator: s.neutronAddr.String(), - Receiver: s.neutronAddr.String(), - TokenIn: s.providerToNeutronDenom, - TokenOut: nativeDenom, - AmountIn: swapAmount, - TickIndexInToOut: 1, - OrderType: dextypes.LimitOrderType_FILL_OR_KILL, - }, - NeutronRefundAddress: refundAddr.String(), - Next: nil, - }, - } - - metadataBz, err := json.Marshal(metadata) - s.Require().NoError(err) - - // Send (failing) IBC transfer with swap metadata - s.IBCTransferProviderToNeutron( - s.providerAddr, - s.neutronAddr, - nativeDenom, - ibcTransferAmount, - string(metadataBz), - ) - - // Check that the funds have been moved to the refund address - s.assertNeutronBalance(refundAddr, nativeDenom, genesisWalletAmount) - s.assertNeutronBalance(refundAddr, s.providerToNeutronDenom, ibcTransferAmount) - - // Check that no refund takes place and the funds are not in the account on provider - s.assertProviderBalance(s.providerAddr, nativeDenom, genesisWalletAmount.Sub(ibcTransferAmount)) -} diff --git a/x/dex/keeper/msg_server.go b/x/dex/keeper/msg_server.go index 1211cc57b..2b3bca666 100644 --- a/x/dex/keeper/msg_server.go +++ b/x/dex/keeper/msg_server.go @@ -259,12 +259,6 @@ func (k MsgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParam return &types.MsgUpdateParamsResponse{}, nil } -func (k MsgServer) AssertNotPaused(goCtx context.Context) error { - ctx := sdk.UnwrapSDKContext(goCtx) - paused := k.GetParams(ctx).Paused - - if paused { - return types.ErrDexPaused - } - return nil +func (k MsgServer) AssertNotPaused(_ context.Context) error { + return types.ErrDexPaused } diff --git a/x/ibcswap/ibc_middleware.go b/x/ibcswap/ibc_middleware.go deleted file mode 100644 index 9f5b5edab..000000000 --- a/x/ibcswap/ibc_middleware.go +++ /dev/null @@ -1,428 +0,0 @@ -package ibcswap - -import ( - "encoding/json" - "errors" - "strings" - - sdkerrors "cosmossdk.io/errors" - "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - - "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -var _ porttypes.Middleware = &IBCMiddleware{} - -// IBCMiddleware implements the ICS26 callbacks for the swap middleware given the -// swap keeper and the underlying application. -type IBCMiddleware struct { - app porttypes.IBCModule - keeper keeper.Keeper -} - -// NewIBCMiddleware creates a new IBCMiddleware given the keeper and underlying application. -func NewIBCMiddleware(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware { - return IBCMiddleware{ - app: app, - keeper: k, - } -} - -// OnChanOpenInit implements the IBCModule interface. -func (im IBCMiddleware) OnChanOpenInit( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID string, - channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - version string, -) (string, error) { - return im.app.OnChanOpenInit( - ctx, - order, - connectionHops, - portID, - channelID, - chanCap, - counterparty, - version, - ) -} - -// OnChanOpenTry implements the IBCModule interface. -func (im IBCMiddleware) OnChanOpenTry( - ctx sdk.Context, - order channeltypes.Order, - connectionHops []string, - portID, channelID string, - chanCap *capabilitytypes.Capability, - counterparty channeltypes.Counterparty, - counterpartyVersion string, -) (version string, err error) { - return im.app.OnChanOpenTry( - ctx, - order, - connectionHops, - portID, - channelID, - chanCap, - counterparty, - counterpartyVersion, - ) -} - -// OnChanOpenAck implements the IBCModule interface. -func (im IBCMiddleware) OnChanOpenAck( - ctx sdk.Context, - portID, channelID string, - counterpartyChannelID string, - counterpartyVersion string, -) error { - return im.app.OnChanOpenAck(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion) -} - -// OnChanOpenConfirm implements the IBCModule interface. -func (im IBCMiddleware) OnChanOpenConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanOpenConfirm(ctx, portID, channelID) -} - -// OnChanCloseInit implements the IBCModule interface. -func (im IBCMiddleware) OnChanCloseInit(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseInit(ctx, portID, channelID) -} - -// OnChanCloseConfirm implements the IBCModule interface. -func (im IBCMiddleware) OnChanCloseConfirm(ctx sdk.Context, portID, channelID string) error { - return im.app.OnChanCloseConfirm(ctx, portID, channelID) -} - -// OnRecvPacket checks the memo field on this packet and if the metadata inside's root key indicates this packet -// should be handled by the swap middleware it attempts to perform a swap. If the swap is successful -// the underlying application's OnRecvPacket callback is invoked. - -// For clarity, here is a breakdown of the steps -// 1. Check if this is a swap packet; if not pass it to next middleware -// 2. validate swapMetadata; ErrAck if invalid -// 3. Pass through the middleware stack to ibc-go/transfer#OnRecvPacket; transfer coins are sent to receiver -// 4. Do swap; handle failures - -func (im IBCMiddleware) OnRecvPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) ibcexported.Acknowledgement { - var data transfertypes.FungibleTokenPacketData - if err := transfertypes.ModuleCdc.UnmarshalJSON(packet.GetData(), &data); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - m := &types.PacketMetadata{} - err := json.Unmarshal([]byte(data.Memo), m) - if err != nil || m.Swap == nil { - // Not a packet that should be handled by the swap middleware - return im.app.OnRecvPacket(ctx, packet, relayer) - } - - metadata := m.Swap - - if err := metadata.Validate(); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - if err := validateSwapPacket(packet, data, *metadata); err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - - // Use overrideReceiver so that users cannot ibcswap through arbitrary addresses. - // Instead generate a unique address for each user based on their channel and origin-address - originalCreator := m.Swap.Creator - overrideReceiver, err := packetforward.GetReceiver(packet.DestinationChannel, data.Sender) - if err != nil { - return channeltypes.NewErrorAcknowledgement(err) - } - metadata.Creator = overrideReceiver - // Update packet data to match the new receiver so that transfer middleware adds tokens to the expected address - packet = newPacketWithOverrideReceiver(packet, data, overrideReceiver) - - ack := im.app.OnRecvPacket(ctx, packet, relayer) - if ack == nil || !ack.Success() { - return ack - } - - // Attempt to perform a swap using a cacheCtx - cacheCtx, writeCache := ctx.CacheContext() - res, err := im.keeper.Swap(cacheCtx, originalCreator, metadata.MsgPlaceLimitOrder) - if err != nil { - return im.handleFailedSwap(ctx, packet, data, metadata, err) - } - - // If there is no next field set in the metadata return ack - if metadata.Next == nil { - writeCache() - return ack - } - - // We need to reset the packets memo field so that the root key in the metadata is the - // next field from the current metadata. - memoBz, err := json.Marshal(metadata.Next) - if err != nil { - return ack - } - - postSwapData := data - postSwapData.Memo = string(memoBz) - - // Override the packet data to include the token denom and amount that was received from the swap. - postSwapData.Denom = res.TakerCoinOut.Denom - postSwapData.Amount = res.TakerCoinOut.Amount.String() - - // After a successful swap funds are now in the receiver account from the MsgPlaceLimitOrder so, - // we need to override the packets receiver field before invoking the forward middlewares OnRecvPacket. - postSwapData.Receiver = m.Swap.Receiver - - dataBz, err := transfertypes.ModuleCdc.MarshalJSON(&postSwapData) - if err != nil { - return ack - } - - packet.Data = dataBz - - // The forward middleware should return a nil ack if the forward is initiated properly. - // If not an error occurred, and we return the original ack. - newAck := im.app.OnRecvPacket(cacheCtx, packet, relayer) - if newAck != nil { - return im.handleFailedSwap(ctx, packet, data, metadata, errors.New(string(newAck.Acknowledgement()))) - } - - writeCache() - return nil -} - -// OnAcknowledgementPacket implements the IBCModule interface. -func (im IBCMiddleware) OnAcknowledgementPacket( - ctx sdk.Context, - packet channeltypes.Packet, - acknowledgement []byte, - relayer sdk.AccAddress, -) error { - return im.app.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer) -} - -// OnTimeoutPacket implements the IBCModule interface. -func (im IBCMiddleware) OnTimeoutPacket( - ctx sdk.Context, - packet channeltypes.Packet, - relayer sdk.AccAddress, -) error { - return im.app.OnTimeoutPacket(ctx, packet, relayer) -} - -func (im IBCMiddleware) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (sequence uint64, err error) { - return im.keeper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} - -// WriteAcknowledgement implements the ICS4 Wrapper interface. -func (im IBCMiddleware) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - ack ibcexported.Acknowledgement, -) error { - return im.keeper.WriteAcknowledgement(ctx, chanCap, packet, ack) -} - -func (im IBCMiddleware) GetAppVersion( - ctx sdk.Context, - portID string, - channelID string, -) (string, bool) { - return im.keeper.GetAppVersion(ctx, portID, channelID) -} - -// handleFailedSwap will invoke the appropriate failover logic depending on if this swap was marked refundable -// or non-refundable in the SwapMetadata. -func (im IBCMiddleware) handleFailedSwap( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - err error, -) ibcexported.Acknowledgement { - swapErr := sdkerrors.Wrap(types.ErrSwapFailed, err.Error()) - im.keeper.Logger(ctx).Error( - "ibc swap failed", - "err", swapErr, - "creator", metadata.Creator, - "receiver", metadata.Receiver, - "tokenIn", metadata.TokenIn, - "tokenOut", metadata.TokenOut, - "AmountIn", metadata.AmountIn, - "TickIndexInToOut", metadata.TickIndexInToOut, - "OrderType", metadata.OrderType, - "refund address", metadata.NeutronRefundAddress, - ) - - // The current denom is from the sender chains perspective, we need to compose the appropriate denom for this side - denomOnThisChain := getDenomForThisChain(packet, data.Denom) - - if len(metadata.NeutronRefundAddress) != 0 { - return im.handleOnChainRefund(ctx, data, metadata, denomOnThisChain, err) - } - - return im.handleIBCRefund(ctx, packet, data, metadata, denomOnThisChain, err) -} - -// handleOnChainRefund will compose a successful ack to send back to the counterparty chain containing any error messages. -// Returning a successful ack ensures that a refund is not issued on the counterparty chain. -// See: https://github.com/cosmos/ibc-go/blob/3ecc7dd3aef5790ec5d906936a297b34adf1ee41/modules/apps/transfer/keeper/relay.go#L320 -func (im IBCMiddleware) handleOnChainRefund( - ctx sdk.Context, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - newDenom string, - swapErr error, -) ibcexported.Acknowledgement { - amount, ok := math.NewIntFromString(data.Amount) - if !ok { - wrappedErr := sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - data.Amount, - ) - wrappedErr = sdkerrors.Wrap(swapErr, wrappedErr.Error()) - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - token := sdk.NewCoin(newDenom, amount) - err := im.keeper.SendCoins(ctx, metadata.Creator, metadata.NeutronRefundAddress, sdk.NewCoins(token)) - if err != nil { - wrappedErr := sdkerrors.Wrap(err, "failed to move funds to refund address") - wrappedErr = sdkerrors.Wrap(swapErr, wrappedErr.Error()) - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - return channeltypes.NewResultAcknowledgement([]byte(swapErr.Error())) -} - -// handleIBCRefund will either burn or transfer the funds back to the appropriate escrow account. -// When a packet comes in the transfer module's OnRecvPacket callback is invoked which either -// mints or unescrows funds on this side so if the swap fails an explicit refund is required. -func (im IBCMiddleware) handleIBCRefund( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, - newDenom string, - swapErr error, -) ibcexported.Acknowledgement { - data.Denom = newDenom - - err := im.keeper.RefundPacketToken(ctx, packet, data, metadata) - if err != nil { - wrappedErr := sdkerrors.Wrap(swapErr, err.Error()) - - // If the refund fails on this side we want to make sure that the refund does not happen on the counterparty, - // so we return a successful ack containing the error - return channeltypes.NewResultAcknowledgement([]byte(wrappedErr.Error())) - } - - return channeltypes.NewErrorAcknowledgement(swapErr) -} - -// getDenomForThisChain composes a new token denom by either unwinding or prefixing the specified token denom appropriately. -// This is necessary because the token denom in the packet data is from the perspective of the counterparty chain. -func getDenomForThisChain(packet channeltypes.Packet, denom string) string { - counterpartyPrefix := transfertypes.GetDenomPrefix(packet.SourcePort, packet.SourceChannel) - if strings.HasPrefix(denom, counterpartyPrefix) { - // unwind denom - unwoundDenom := denom[len(counterpartyPrefix):] - denomTrace := transfertypes.ParseDenomTrace(unwoundDenom) - if denomTrace.Path == "" { - // denom is now unwound back to native denom - return unwoundDenom - } - // denom is still IBC denom - return denomTrace.IBCDenom() - } - - // append port and channel from this chain to denom - prefixedDenom := transfertypes.GetDenomPrefix(packet.DestinationPort, packet.DestinationChannel) + denom - return transfertypes.ParseDenomTrace(prefixedDenom).IBCDenom() -} - -// Update the packet data to reflect the new receiver address that is used by the PFM -func newPacketWithOverrideReceiver(oldPacket channeltypes.Packet, data transfertypes.FungibleTokenPacketData, overrideReceiver string) channeltypes.Packet { - overrideData := transfertypes.FungibleTokenPacketData{ - Denom: data.Denom, - Amount: data.Amount, - Sender: data.Sender, - Receiver: overrideReceiver, // override receiver - } - overrideDataBz := transfertypes.ModuleCdc.MustMarshalJSON(&overrideData) - - return channeltypes.Packet{ - Sequence: oldPacket.Sequence, - SourcePort: oldPacket.SourcePort, - SourceChannel: oldPacket.SourceChannel, - DestinationPort: oldPacket.DestinationPort, - DestinationChannel: oldPacket.DestinationChannel, - Data: overrideDataBz, // override data - TimeoutHeight: oldPacket.TimeoutHeight, - TimeoutTimestamp: oldPacket.TimeoutTimestamp, - } -} - -func validateSwapPacket(packet channeltypes.Packet, transferData transfertypes.FungibleTokenPacketData, sm types.SwapMetadata) error { - denomOnNeutron := getDenomForThisChain(packet, transferData.Denom) - if denomOnNeutron != sm.TokenIn { - return sdkerrors.Wrap(types.ErrInvalidSwapMetadata, "Transfer Denom must match TokenIn") - } - - transferAmount, ok := math.NewIntFromString(transferData.Amount) - if !ok { - return sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - transferData.Amount, - ) - } - - if transferAmount.LT(sm.AmountIn) { - return sdkerrors.Wrap(types.ErrInvalidSwapMetadata, "Transfer amount must be >= AmountIn") - } - - if sm.ContainsPFM() { - return sdkerrors.Wrap( - types.ErrInvalidSwapMetadata, - "ibcswap middleware cannot be used in conjunction with packet-forward-middleware", - ) - } - return nil -} diff --git a/x/ibcswap/keeper/keeper.go b/x/ibcswap/keeper/keeper.go deleted file mode 100644 index 33d5f1493..000000000 --- a/x/ibcswap/keeper/keeper.go +++ /dev/null @@ -1,207 +0,0 @@ -package keeper - -import ( - "fmt" - - sdkerrors "cosmossdk.io/errors" - "cosmossdk.io/log" - "cosmossdk.io/math" - "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/gogoproto/proto" - capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" - transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" - ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -// Keeper defines the swap middleware keeper. -type Keeper struct { - cdc codec.BinaryCodec - msgServiceRouter *baseapp.MsgServiceRouter - - ics4Wrapper porttypes.ICS4Wrapper - bankKeeper types.BankKeeper -} - -// NewKeeper creates a new swap Keeper instance. -func NewKeeper( - cdc codec.BinaryCodec, - msgServiceRouter *baseapp.MsgServiceRouter, - ics4Wrapper porttypes.ICS4Wrapper, - bankKeeper types.BankKeeper, -) Keeper { - return Keeper{ - cdc: cdc, - msgServiceRouter: msgServiceRouter, - - ics4Wrapper: ics4Wrapper, - bankKeeper: bankKeeper, - } -} - -// Logger returns a module-specific logger. -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", "x/"+ibcexported.ModuleName+"-"+types.ModuleName) -} - -// Swap calls into the base app's msg service router so that the appropriate handler is called when sending the swap msg. -func (k Keeper) Swap( - ctx sdk.Context, - originalCreator string, - msg *dextypes.MsgPlaceLimitOrder, -) (*dextypes.MsgPlaceLimitOrderResponse, error) { - swapHandler := k.msgServiceRouter.Handler(msg) - if swapHandler == nil { - return nil, sdkerrors.Wrap( - types.ErrMsgHandlerInvalid, - fmt.Sprintf("could not find the handler for %T", msg), - ) - } - - res, err := swapHandler(ctx, msg) - if err != nil { - return nil, err - } - - msgSwapRes := &dextypes.MsgPlaceLimitOrderResponse{} - // TODO: replace the Data field with MsgResponses? - if err := proto.Unmarshal(res.Data, msgSwapRes); err != nil { - return nil, err - } - - amountUnused := msg.AmountIn.Sub(msgSwapRes.CoinIn.Amount) - // If not all tokenIn is swapped and a temporary creator address has been used - // return the unused portion to the original creator address - if amountUnused.IsPositive() && originalCreator != msg.Creator { - overrrideCreatorAddr := sdk.MustAccAddressFromBech32(msg.Creator) - originalCreatorAddr := sdk.MustAccAddressFromBech32(originalCreator) - unusedCoin := sdk.NewCoin(msg.TokenIn, amountUnused) - - err := k.bankKeeper.SendCoins(ctx, overrrideCreatorAddr, originalCreatorAddr, sdk.Coins{unusedCoin}) - if err != nil { - return nil, err - } - } - - return msgSwapRes, nil -} - -// SendPacket wraps IBC ChannelKeeper's SendPacket function. -func (k Keeper) SendPacket( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - sourcePort string, - sourceChannel string, - timeoutHeight clienttypes.Height, - timeoutTimestamp uint64, - data []byte, -) (sequence uint64, err error) { - return k.ics4Wrapper.SendPacket( - ctx, - chanCap, - sourcePort, - sourceChannel, - timeoutHeight, - timeoutTimestamp, - data, - ) -} - -// WriteAcknowledgement wraps IBC ChannelKeeper's WriteAcknowledgement function. -func (k Keeper) WriteAcknowledgement( - ctx sdk.Context, - chanCap *capabilitytypes.Capability, - packet ibcexported.PacketI, - acknowledgement ibcexported.Acknowledgement, -) error { - return k.ics4Wrapper.WriteAcknowledgement(ctx, chanCap, packet, acknowledgement) -} - -// RefundPacketToken handles the burning or escrow lock up of vouchers when an asset should be refunded. -// This is only used in the case where we call into the transfer modules OnRecvPacket callback but then the swap fails. -func (k Keeper) RefundPacketToken( - ctx sdk.Context, - packet channeltypes.Packet, - data transfertypes.FungibleTokenPacketData, - metadata *types.SwapMetadata, -) error { - // parse the denomination from the full denom path - trace := transfertypes.ParseDenomTrace(data.Denom) - - // parse the transfer amount - transferAmount, ok := math.NewIntFromString(data.Amount) - if !ok { - return sdkerrors.Wrapf( - transfertypes.ErrInvalidAmount, - "unable to parse transfer amount (%s) into math.Int", - data.Amount, - ) - } - token := sdk.NewCoin(trace.IBCDenom(), transferAmount) - - // decode the creator address - receiver, err := sdk.AccAddressFromBech32(metadata.Creator) - if err != nil { - return err - } - - // if the sender chain is source that means a voucher was minted on Neutron when the ics20 transfer took place - if transfertypes.SenderChainIsSource(packet.SourcePort, packet.SourceChannel, data.Denom) { - // transfer coins from user account to transfer module - err = k.bankKeeper.SendCoinsFromAccountToModule( - ctx, - receiver, - types.ModuleName, - sdk.NewCoins(token), - ) - if err != nil { - return err - } - - // burn the coins - err = k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(token)) - if err != nil { - return err - } - - return nil - } - - // transfer coins from user account to escrow address - escrowAddress := transfertypes.GetEscrowAddress( - packet.GetSourcePort(), - packet.GetSourceChannel(), - ) - err = k.bankKeeper.SendCoins(ctx, receiver, escrowAddress, sdk.NewCoins(token)) - if err != nil { - return err - } - - return nil -} - -// SendCoins wraps the BankKeepers SendCoins function so it can be invoked from the middleware. -func (k Keeper) SendCoins(ctx sdk.Context, fromAddr, toAddr string, amt sdk.Coins) error { - from, err := sdk.AccAddressFromBech32(fromAddr) - if err != nil { - return err - } - - to, err := sdk.AccAddressFromBech32(toAddr) - if err != nil { - return err - } - - return k.bankKeeper.SendCoins(ctx, from, to, amt) -} - -func (k Keeper) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) { - return k.ics4Wrapper.GetAppVersion(ctx, portID, channelID) -} diff --git a/x/ibcswap/module.go b/x/ibcswap/module.go deleted file mode 100644 index 428ac1274..000000000 --- a/x/ibcswap/module.go +++ /dev/null @@ -1,144 +0,0 @@ -package ibcswap - -import ( - "encoding/json" - - "cosmossdk.io/core/appmodule" - - abci "github.com/cometbft/cometbft/abci/types" - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/gorilla/mux" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/spf13/cobra" - - "github.com/neutron-org/neutron/v4/x/ibcswap/keeper" - "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -var ( - _ module.AppModuleBasic = AppModuleBasic{} - _ appmodule.AppModule = AppModule{} - _ module.AppModuleSimulation = AppModule{} -) - -// AppModuleBasic is the swap middleware AppModuleBasic. -type AppModuleBasic struct{} - -// Name implements AppModuleBasic interface. -func (AppModuleBasic) Name() string { - return types.ModuleName -} - -// RegisterLegacyAminoCodec implements AppModuleBasic interface. -func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) {} - -// RegisterInterfaces registers module concrete types into protobuf Any. -func (AppModuleBasic) RegisterInterfaces(_ codectypes.InterfaceRegistry) {} - -// DefaultGenesis returns default genesis state as raw bytes for the swap module. -func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { - return nil -} - -// ValidateGenesis performs genesis state validation for the swap module. -func (AppModuleBasic) ValidateGenesis( - _ codec.JSONCodec, - _ client.TxEncodingConfig, - _ json.RawMessage, -) error { - return nil -} - -// RegisterRESTRoutes implements AppModuleBasic interface. -func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} - -// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the swap module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} - -// GetTxCmd implements AppModuleBasic interface. -func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil -} - -// GetQueryCmd implements AppModuleBasic interface. -func (AppModuleBasic) GetQueryCmd() *cobra.Command { - return nil -} - -// AppModule implements the module.AppModule -type AppModule struct { - AppModuleBasic - keeper keeper.Keeper -} - -func NewAppModule(keeper keeper.Keeper) *AppModule { - return &AppModule{ - keeper: keeper, - } -} - -// RegisterInvariants implements the AppModule interface. -func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} - -// QuerierRoute implements the AppModule interface. -func (AppModule) QuerierRoute() string { - return "" -} - -// RegisterServices registers module services. -func (am AppModule) RegisterServices(_ module.Configurator) {} - -// InitGenesis performs genesis initialization for the ibc-router module. It returns -// no validator updates. -func (am AppModule) InitGenesis( - _ sdk.Context, - _ codec.JSONCodec, - _ json.RawMessage, -) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} - -// ExportGenesis returns the exported genesis state as raw bytes for the swap module. -func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONCodec) json.RawMessage { - return nil -} - -// ConsensusVersion returns the consensus state breaking version for the swap module. -func (AppModule) ConsensusVersion() uint64 { return 1 } - -// BeginBlock implements the AppModule interface. -func (am AppModule) BeginBlock(_ sdk.Context) {} - -// EndBlock implements the AppModule interface. -func (am AppModule) EndBlock(_ sdk.Context) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} -} - -// GenerateGenesisState implements the AppModuleSimulation interface. -func (AppModule) GenerateGenesisState(_ *module.SimulationState) {} - -// ProposalContents implements the AppModuleSimulation interface. -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalMsg { - return nil -} - -// RegisterStoreDecoder implements the AppModuleSimulation interface. -func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} - -// WeightedOperations implements the AppModuleSimulation interface. -func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { - return nil -} - -// IsOnePerModuleType implements the depinject.OnePerModuleType interface. -func (am AppModule) IsOnePerModuleType() { // marker -} - -// IsAppModule implements the appmodule.AppModule interface. -func (am AppModule) IsAppModule() { // marker -} diff --git a/x/ibcswap/types/errors.go b/x/ibcswap/types/errors.go deleted file mode 100644 index 819589ae8..000000000 --- a/x/ibcswap/types/errors.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -import sdkerrors "cosmossdk.io/errors" - -var ( - ErrInvalidSwapMetadata = sdkerrors.Register(ModuleName, 2, "invalid swap metadata") - ErrSwapFailed = sdkerrors.Register(ModuleName, 3, "ibc swap failed") - ErrMsgHandlerInvalid = sdkerrors.Register(ModuleName, 4, "msg service handler not found") -) diff --git a/x/ibcswap/types/expected_keepers.go b/x/ibcswap/types/expected_keepers.go deleted file mode 100644 index 705463d97..000000000 --- a/x/ibcswap/types/expected_keepers.go +++ /dev/null @@ -1,14 +0,0 @@ -package types - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// BankKeeper defines the expected interface that the swap middleware needs in order to facilitate refunds. -type BankKeeper interface { - SendCoins(ctx context.Context, fromAddr, toAddr sdk.AccAddress, amt sdk.Coins) error - BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error - SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error -} diff --git a/x/ibcswap/types/keys.go b/x/ibcswap/types/keys.go deleted file mode 100644 index 9a88fc669..000000000 --- a/x/ibcswap/types/keys.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -// ModuleName defines the name for the swap middleware. -const ModuleName = "swap-middleware" - -// ProcessedKey is used to signal to the swap middleware that a packet has already been processed by some other -// middleware and so invoking the transfer modules OnRecvPacket callback should be avoided. -type ProcessedKey struct{} diff --git a/x/ibcswap/types/swap.go b/x/ibcswap/types/swap.go deleted file mode 100644 index 9f5013a49..000000000 --- a/x/ibcswap/types/swap.go +++ /dev/null @@ -1,114 +0,0 @@ -package types - -import ( - "encoding/json" - - sdkerrors "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/iancoleman/orderedmap" - - dextypes "github.com/neutron-org/neutron/v4/x/dex/types" -) - -// PacketMetadata wraps the SwapMetadata. The root key in the incoming ICS20 transfer packet's memo needs to be set to the same -// value as the json tag in order for the swap middleware to process the swap. -type PacketMetadata struct { - Swap *SwapMetadata `json:"swap"` -} - -// SwapMetadata defines the parameters necessary to perform a swap utilizing the memo field from an incoming ICS20 -// transfer packet. The next field is a string so that you can nest any arbitrary metadata to be handled -// further in the middleware stack or on the counterparty. -type SwapMetadata struct { - *dextypes.MsgPlaceLimitOrder - // If a value is provided for NeutronRefundAddress and the swap fails the Transfer.Amount will be moved to this address for later recovery. - // If no NeutronRefundAddress is provided and a swap fails we will fail the ibc transfer and tokens will be refunded on the source chain. - NeutronRefundAddress string `json:"refund-address,omitempty"` - - // Using JSONObject so that objects for next property will not be mutated by golang's lexicographic key sort on map keys during Marshal. - // Supports primitives for Unmarshal/Marshal so that an escaped JSON-marshaled string is also valid. - Next *JSONObject `json:"next,omitempty"` -} - -// Validate ensures that all the required fields are present in the SwapMetadata and contain valid values. -func (sm SwapMetadata) Validate() error { - if err := sm.MsgPlaceLimitOrder.Validate(); err != nil { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, err.Error()) - } - if sm.TokenIn == "" { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "limit order tokenIn cannot be an empty string") - } - if sm.TokenOut == "" { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "limit order tokenOut cannot be an empty string") - } - if sm.NeutronRefundAddress != "" { - _, err := sdk.AccAddressFromBech32(sm.NeutronRefundAddress) - if err != nil { - return sdkerrors.Wrapf(dextypes.ErrInvalidAddress, "%s is not a valid Neutron address", sm.NeutronRefundAddress) - } - } - - if !sm.OrderType.IsFoK() { - return sdkerrors.Wrap(ErrInvalidSwapMetadata, "Limit Order type must be FILL_OR_KILL") - } - - return nil -} - -// ContainsPFM checks if the Swapetadata is wrapping packet-forward-middleware -func (sm SwapMetadata) ContainsPFM() bool { - if sm.Next == nil { - return false - } - forward, _ := sm.Next.orderedMap.Get("forward") - - return forward != nil -} - -// JSONObject is a wrapper type to allow either a primitive type or a JSON object. -// In the case the value is a JSON object, OrderedMap type is used so that key order -// is retained across Unmarshal/Marshal. -type JSONObject struct { - obj bool - primitive []byte - orderedMap orderedmap.OrderedMap -} - -// NewJSONObject is a constructor used for tests. -// The usage of JSONObject in the middleware is only json Marshal/Unmarshal -func NewJSONObject(object bool, primitive []byte, orderedMap orderedmap.OrderedMap) *JSONObject { - return &JSONObject{ - obj: object, - primitive: primitive, - orderedMap: orderedMap, - } -} - -// UnmarshalJSON overrides the default json.Unmarshal behavior -func (o *JSONObject) UnmarshalJSON(b []byte) error { - if err := o.orderedMap.UnmarshalJSON(b); err != nil { - // If ordered map unmarshal fails, this is a primitive value - o.obj = false - // Attempt to unmarshal as string, this removes extra JSON escaping - var primitiveStr string - if err := json.Unmarshal(b, &primitiveStr); err != nil { - o.primitive = b - return nil - } - o.primitive = []byte(primitiveStr) - return nil - } - // This is a JSON object, now stored as an ordered map to retain key order. - o.obj = true - return nil -} - -// MarshalJSON overrides the default json.Marshal behavior -func (o *JSONObject) MarshalJSON() ([]byte, error) { - if o.obj { - // non-primitive, return marshaled ordered map. - return o.orderedMap.MarshalJSON() - } - // primitive, return raw bytes. - return o.primitive, nil -} diff --git a/x/ibcswap/types/swap_test.go b/x/ibcswap/types/swap_test.go deleted file mode 100644 index 50bc06772..000000000 --- a/x/ibcswap/types/swap_test.go +++ /dev/null @@ -1,248 +0,0 @@ -package types_test - -import ( - "encoding/json" - "testing" - - "github.com/neutron-org/neutron/v4/app/config" - - "cosmossdk.io/math" - pfmtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v8/packetforward/types" - "github.com/iancoleman/orderedmap" - "github.com/stretchr/testify/require" - - "github.com/neutron-org/neutron/v4/testutil/common/sample" - "github.com/neutron-org/neutron/v4/x/dex/types" - dextypes "github.com/neutron-org/neutron/v4/x/ibcswap/types" -) - -func init() { - _ = config.GetDefaultConfig() -} - -// TestPacketMetadata_Marshal asserts that the marshaling of the swap metadata works as intended. -func TestPacketMetadata_Marshal(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "test-1", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) -} - -// TestPacketMetadata_MarshalWithNext asserts that the marshaling of the swap metadata works as intended with next field initialized. -func TestPacketMetadata_MarshalWithNext(t *testing.T) { - forwardMedata := &pfmtypes.PacketMetadata{ - Forward: &pfmtypes.ForwardMetadata{ - Receiver: "cosmos14zde8usc4ur04y3aqnufzzmv2uqdpwwttr5uwv", - Port: "transfer", - Channel: "channel-0", - Timeout: 0, - Retries: nil, - Next: nil, - }, - } - nextBz, err := json.Marshal(forwardMedata) - require.NoError(t, err) - - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "test-1", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - TickIndexInToOut: 0, - AmountIn: math.NewInt(123), - OrderType: types.LimitOrderType_FILL_OR_KILL, - // MaxAmountOut: math.NewInt(456), - }, - Next: dextypes.NewJSONObject(false, nextBz, orderedmap.OrderedMap{}), - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) -} - -// TestPacketMetadata_Unmarshal asserts that unmarshaling works as intended. -func TestPacketMetadata_Unmarshal(t *testing.T) { - metadata := "{\n \"swap\": {\n \"creator\": \"test-1\",\n \"TickIndexInToOut\": 0,\n \"orderType\": 1,\n \"receiver\": \"test-1\",\n \"tokenIn\": \"token-a\",\n \"tokenOut\": \"token-b\",\n \"AmountIn\": \"123\",\n \"next\": \"\"\n }\n}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -// TestPacketMetadata_UnmarshalStringNext asserts that unmarshaling works as intended when next is escaped json string. -func TestPacketMetadata_UnmarshalStringNext(t *testing.T) { - metadata := "{\n \"swap\": {\n \"creator\": \"test-1\",\n \"receiver\": \"test-1\",\n \"tokenIn\": \"token-a\",\n \"tokenOut\": \"token-b\",\n \"AmountIn\": \"123\",\n \"TickIndexInToOut\": 0,\n \"orderType\": 1,\n \"next\": \" {\\\"forward\\\":{\\\"receiver\\\":\\\"cosmos1f4cur2krsua2th9kkp7n0zje4stea4p9tu70u8\\\",\\\"port\\\":\\\"transfer\\\",\\\"channel\\\":\\\"channel-0\\\",\\\"timeout\\\":0,\\\"next\\\":{\\\"forward\\\":{\\\"receiver\\\":\\\"cosmos1l505zhahp24v5jsmps9vs5asah759fdce06sfp\\\",\\\"port\\\":\\\"transfer\\\",\\\"channel\\\":\\\"channel-0\\\",\\\"timeout\\\":0}}}}\"\n }\n}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -// TestPacketMetadata_UnmarshalJSONNext asserts that unmarshaling works as intended when next is a raw json object. -func TestPacketMetadata_UnmarshalJSONNext(t *testing.T) { - metadata := "{\"swap\":{\"creator\":\"test-1\",\"receiver\":\"test-1\",\"tokenIn\":\"token-a\",\"tokenOut\":\"token-b\",\"AmountIn\":\"123\",\"TickIndexInToOut\":0, \"orderType\": 1, \"tokenIn\":\"token-in\",\"next\":{\"forward\":{\"receiver\":\"cosmos14zde8usc4ur04y3aqnufzzmv2uqdpwwttr5uwv\",\"port\":\"transfer\",\"channel\":\"channel-0\"}}}}" - pm := &dextypes.PacketMetadata{} - err := json.Unmarshal([]byte(metadata), pm) - require.NoError(t, err) -} - -func TestSwapMetadata_ValidatePass(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: sample.AccAddress(), - Receiver: sample.AccAddress(), - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) - - require.NoError(t, pm.Swap.Validate()) -} - -func TestSwapMetadata_ValidateFail(t *testing.T) { - pm := dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "", - Receiver: "test-1", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err := json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "test-1", - TokenIn: "", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(0), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(-1), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_FILL_OR_KILL, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) - - pm = dextypes.PacketMetadata{ - &dextypes.SwapMetadata{ - MsgPlaceLimitOrder: &types.MsgPlaceLimitOrder{ - Creator: "creator", - Receiver: "receiver", - TokenIn: "token-a", - TokenOut: "token-b", - AmountIn: math.NewInt(123), - TickIndexInToOut: 0, - OrderType: types.LimitOrderType_GOOD_TIL_CANCELLED, - }, - Next: nil, - }, - } - _, err = json.Marshal(pm) - require.NoError(t, err) - require.Error(t, pm.Swap.Validate()) -} From e24627588e00317abbbd12eb330b3b938109f901 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Mon, 16 Sep 2024 15:22:45 +0300 Subject: [PATCH 47/60] enable burn rights for wasmd + tests --- app/app.go | 2 +- wasmbinding/test/custom_message_test.go | 110 +++++++++++++++++++++++- 2 files changed, 109 insertions(+), 3 deletions(-) diff --git a/app/app.go b/app/app.go index af04a7b11..0d105a861 100644 --- a/app/app.go +++ b/app/app.go @@ -284,7 +284,7 @@ var ( auctiontypes.ModuleName: nil, ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner}, icatypes.ModuleName: nil, - wasmtypes.ModuleName: {}, + wasmtypes.ModuleName: {authtypes.Burner}, interchainqueriesmoduletypes.ModuleName: nil, feetypes.ModuleName: nil, feeburnertypes.ModuleName: nil, diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 446c7159f..8d7366831 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -3,8 +3,13 @@ package test import ( "encoding/json" "fmt" + "strings" "testing" + transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + contractmanagertypes "github.com/neutron-org/neutron/v4/x/contractmanager/types" "cosmossdk.io/math" @@ -75,7 +80,7 @@ func (suite *CustomMessengerTestSuite) SetupTest() { suite.contractKeeper = keeper.NewDefaultPermissionKeeper(&suite.neutron.WasmKeeper) err := suite.messenger.TokenFactory.SetParams(suite.ctx, tokenfactorytypes.NewParams( - sdk.NewCoins(sdk.NewInt64Coin(params.DefaultDenom, 10_000_000)), + sdk.NewCoins(sdk.NewInt64Coin(params.DefaultDenom, 100)), 0, FeeCollectorAddress, tokenfactorytypes.DefaultWhitelistedHooks, @@ -723,6 +728,103 @@ func (suite *CustomMessengerTestSuite) TestAddRemoveSchedule() { suite.NoError(err) } +func (suite *CustomMessengerTestSuite) TestBurnTokens() { + // add NTRN to the contract + senderAddress := suite.ChainA.SenderAccounts[0].SenderAccount.GetAddress() + coinsAmnt := sdk.NewCoins(sdk.NewCoin(params.DefaultDenom, math.NewInt(int64(10_000_000)))) + bankKeeper := suite.neutron.BankKeeper + err := bankKeeper.SendCoins(suite.ctx, senderAddress, suite.contractAddress, coinsAmnt) + suite.NoError(err) + + suite.ConfigureTransferChannel() + + // add IBC denom to the contract + timeoutHeight := clienttypes.NewHeight(1, 110) + + // Create Transfer Msg + transferMsg := transfertypes.NewMsgTransfer(suite.TransferPath.EndpointB.ChannelConfig.PortID, + suite.TransferPath.EndpointB.ChannelID, + sdk.NewCoin(params.DefaultDenom, math.NewInt(100)), + suite.ChainB.SenderAccounts[0].SenderAccount.GetAddress().String(), + strings.TrimSpace(suite.contractAddress.String()), + timeoutHeight, + 0, + "", + ) + + // Send message from chainB to chainA + res, err := suite.TransferPath.EndpointB.Chain.SendMsgs(transferMsg) + suite.Require().NoError(err) + + // Relay transfer msg to Neutron chain + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + + //nolint:errcheck // this will return an error for multi-hop routes; that's expected + suite.Require().NoError(suite.TransferPath.RelayPacket(packet)) + // ----------------------------------- + + // Add tf token to the contract + // Create denom for minting + fullMsg := bindings.NeutronMsg{ + CreateDenom: &bindings.CreateDenom{ + Subdenom: "tfdenom", + }, + } + + _, err = suite.executeNeutronMsg(suite.contractAddress, fullMsg) + suite.NoError(err) + + tfDenom := fmt.Sprintf("factory/%s/%s", suite.contractAddress.String(), fullMsg.CreateDenom.Subdenom) + + amount, ok := math.NewIntFromString("808010808") + require.True(suite.T(), ok) + + fullMsg = bindings.NeutronMsg{ + MintTokens: &bindings.MintTokens{ + Denom: tfDenom, + Amount: amount, + MintToAddress: suite.contractAddress.String(), + }, + } + + _, err = suite.executeNeutronMsg(suite.contractAddress, fullMsg) + suite.NoError(err) + + type testCase struct { + Name string + CoinToBurn sdk.Coin + } + + ibcTokenDenomHash, err := suite.neutron.TransferKeeper.DenomHash( + suite.ctx, + &transfertypes.QueryDenomHashRequest{Trace: ibctesting.TransferPort + "/" + suite.TransferPath.EndpointA.ChannelID + "/" + params.DefaultDenom}) + suite.Require().NoError(err) + + testcases := []testCase{ + {Name: "burn NTRN", CoinToBurn: sdk.NewCoin(params.DefaultDenom, math.NewInt(1000))}, + {Name: "burn tf denom", CoinToBurn: sdk.NewCoin(tfDenom, math.NewInt(1000))}, + {Name: "burn ibc denom", CoinToBurn: sdk.NewCoin("ibc/"+ibcTokenDenomHash.Hash, math.NewInt(50))}, + } + + for _, tc := range testcases { + suite.Run(tc.Name, func() { + balanceBeforeBurn := bankKeeper.GetBalance(suite.ctx, suite.contractAddress, tc.CoinToBurn.Denom) + + // Craft Burn message + msg := &types.CosmosMsg{ + Bank: &types.BankMsg{Burn: &types.BurnMsg{Amount: types.Array[types.Coin]{types.Coin{Amount: tc.CoinToBurn.Amount.String(), Denom: tc.CoinToBurn.Denom}}}}, + } + + // Dispatch Burn message + _, err = suite.executeMsg(suite.contractAddress, *msg) + suite.NoError(err) + + suite.Require().Equal(balanceBeforeBurn.Sub(tc.CoinToBurn), bankKeeper.GetBalance(suite.ctx, suite.contractAddress, tc.CoinToBurn.Denom)) + }) + } +} + func (suite *CustomMessengerTestSuite) TestResubmitFailureAck() { // Add failure packet := ibcchanneltypes.Packet{} @@ -804,6 +906,10 @@ func (suite *CustomMessengerTestSuite) executeCustomMsg(contractAddress sdk.AccA Custom: fullMsg, } + return suite.executeMsg(contractAddress, customMsg) +} + +func (suite *CustomMessengerTestSuite) executeMsg(contractAddress sdk.AccAddress, fullMsg types.CosmosMsg) (data []byte, err error) { type ExecuteMsg struct { ReflectMsg struct { Msgs []types.CosmosMsg `json:"msgs"` @@ -812,7 +918,7 @@ func (suite *CustomMessengerTestSuite) executeCustomMsg(contractAddress sdk.AccA execMsg := ExecuteMsg{ReflectMsg: struct { Msgs []types.CosmosMsg `json:"msgs"` - }(struct{ Msgs []types.CosmosMsg }{Msgs: []types.CosmosMsg{customMsg}})} + }(struct{ Msgs []types.CosmosMsg }{Msgs: []types.CosmosMsg{fullMsg}})} msg, err := json.Marshal(execMsg) suite.NoError(err) From ecc0ebde410ef7452fbd7660df4405ec97eca11d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Sep 2024 09:01:18 +0000 Subject: [PATCH 48/60] Bump github.com/prometheus/client_golang from 1.20.3 to 1.20.4 Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.20.3 to 1.20.4. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.20.3...v1.20.4) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index d203836f9..08e3f32fe 100644 --- a/go.mod +++ b/go.mod @@ -33,9 +33,8 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 github.com/hashicorp/go-metrics v0.5.3 - github.com/iancoleman/orderedmap v0.3.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.20.3 + github.com/prometheus/client_golang v1.20.4 github.com/rs/zerolog v1.33.0 github.com/skip-mev/block-sdk/v2 v2.1.5 github.com/skip-mev/feemarket v1.1.1 @@ -142,6 +141,7 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/hdevalence/ed25519consensus v0.1.0 // indirect github.com/huandu/skiplist v1.2.0 // indirect + github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 3c96e84c9..18ea3e6b0 100644 --- a/go.sum +++ b/go.sum @@ -924,8 +924,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= -github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= +github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= From cdf4aab44511e86e03544a2a39f06ba4af43d27a Mon Sep 17 00:00:00 2001 From: Aleksandr Pismenskiy Date: Tue, 17 Sep 2024 15:21:50 +0300 Subject: [PATCH 49/60] whitelist EscrowAddress for Stargate and gRPC --- wasmbinding/stargate_allowlist.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wasmbinding/stargate_allowlist.go b/wasmbinding/stargate_allowlist.go index 13d8ab761..1e591374a 100644 --- a/wasmbinding/stargate_allowlist.go +++ b/wasmbinding/stargate_allowlist.go @@ -41,7 +41,8 @@ func AcceptedStargateQueries() wasmkeeper.AcceptedQueries { "/ibc.applications.interchain_accounts.controller.v1.Query/InterchainAccount": &icacontrollertypes.QueryInterchainAccountResponse{}, // transfer - "/ibc.applications.transfer.v1.Query/DenomTrace": &ibctransfertypes.QueryDenomTraceResponse{}, + "/ibc.applications.transfer.v1.Query/DenomTrace": &ibctransfertypes.QueryDenomTraceResponse{}, + "/ibc.applications.transfer.v1.Query/EscrowAddress": &ibctransfertypes.QueryEscrowAddressResponse{}, // auth "/cosmos.auth.v1beta1.Query/Account": &authtypes.QueryAccountResponse{}, From 22e49a4975de6835b5fdc8b0ff92774b1dc7a7d5 Mon Sep 17 00:00:00 2001 From: sotnikov-s Date: Tue, 17 Sep 2024 20:35:12 +0300 Subject: [PATCH 50/60] update chain manager binary with the version with software upgrade strategies --- contracts/neutron_chain_manager.wasm | Bin 585200 -> 589098 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/contracts/neutron_chain_manager.wasm b/contracts/neutron_chain_manager.wasm index 83945edcf24213cb198f871fa1c5c9c0fcc0f8e1..5b1fd4f492b7d0047a92595dec5ad1f4e6bcb641 100644 GIT binary patch delta 230816 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 @3icI(xBbwjif1(F@0 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 delta 227525 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

-W%8EHQWhxyGSXa^d+4Tk?I?ZyrCugA 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 From f3d54351e2c09d7845505cb07bcec15e33afa0d0 Mon Sep 17 00:00:00 2001 From: pr0n00gler Date: Wed, 18 Sep 2024 16:27:02 +0300 Subject: [PATCH 51/60] small refactoring --- wasmbinding/test/custom_message_test.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/wasmbinding/test/custom_message_test.go b/wasmbinding/test/custom_message_test.go index 8d7366831..50e0f5559 100644 --- a/wasmbinding/test/custom_message_test.go +++ b/wasmbinding/test/custom_message_test.go @@ -739,15 +739,13 @@ func (suite *CustomMessengerTestSuite) TestBurnTokens() { suite.ConfigureTransferChannel() // add IBC denom to the contract - timeoutHeight := clienttypes.NewHeight(1, 110) - // Create Transfer Msg transferMsg := transfertypes.NewMsgTransfer(suite.TransferPath.EndpointB.ChannelConfig.PortID, suite.TransferPath.EndpointB.ChannelID, sdk.NewCoin(params.DefaultDenom, math.NewInt(100)), suite.ChainB.SenderAccounts[0].SenderAccount.GetAddress().String(), strings.TrimSpace(suite.contractAddress.String()), - timeoutHeight, + clienttypes.NewHeight(1, 110), 0, "", ) @@ -760,7 +758,6 @@ func (suite *CustomMessengerTestSuite) TestBurnTokens() { packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) suite.Require().NoError(err) - //nolint:errcheck // this will return an error for multi-hop routes; that's expected suite.Require().NoError(suite.TransferPath.RelayPacket(packet)) // ----------------------------------- @@ -812,12 +809,12 @@ func (suite *CustomMessengerTestSuite) TestBurnTokens() { balanceBeforeBurn := bankKeeper.GetBalance(suite.ctx, suite.contractAddress, tc.CoinToBurn.Denom) // Craft Burn message - msg := &types.CosmosMsg{ + msg := types.CosmosMsg{ Bank: &types.BankMsg{Burn: &types.BurnMsg{Amount: types.Array[types.Coin]{types.Coin{Amount: tc.CoinToBurn.Amount.String(), Denom: tc.CoinToBurn.Denom}}}}, } // Dispatch Burn message - _, err = suite.executeMsg(suite.contractAddress, *msg) + _, err = suite.executeMsg(suite.contractAddress, msg) suite.NoError(err) suite.Require().Equal(balanceBeforeBurn.Sub(tc.CoinToBurn), bankKeeper.GetBalance(suite.ctx, suite.contractAddress, tc.CoinToBurn.Denom)) From c3b28edb53e9d16b45a1ee25c6117eb11ff6697a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:36:09 +0000 Subject: [PATCH 52/60] Bump cosmossdk.io/x/tx from 0.13.4 to 0.13.5 Bumps [cosmossdk.io/x/tx](https://github.com/cosmos/cosmos-sdk) from 0.13.4 to 0.13.5. - [Release notes](https://github.com/cosmos/cosmos-sdk/releases) - [Changelog](https://github.com/cosmos/cosmos-sdk/blob/main/CHANGELOG.md) - [Commits](https://github.com/cosmos/cosmos-sdk/compare/x/tx/v0.13.4...x/tx/v0.13.5) --- updated-dependencies: - dependency-name: cosmossdk.io/x/tx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ad6a2b8a..d4407fad5 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( cosmossdk.io/store v1.1.0 cosmossdk.io/x/evidence v0.1.1 cosmossdk.io/x/feegrant v0.1.1 - cosmossdk.io/x/tx v0.13.4 + cosmossdk.io/x/tx v0.13.5 cosmossdk.io/x/upgrade v0.1.4 github.com/CosmWasm/wasmd v0.51.0 github.com/CosmWasm/wasmvm/v2 v2.1.2 diff --git a/go.sum b/go.sum index 6537b6485..47b7d96af 100644 --- a/go.sum +++ b/go.sum @@ -212,8 +212,8 @@ cosmossdk.io/x/feegrant v0.1.1 h1:EKFWOeo/pup0yF0svDisWWKAA9Zags6Zd0P3nRvVvw8= cosmossdk.io/x/feegrant v0.1.1/go.mod h1:2GjVVxX6G2fta8LWj7pC/ytHjryA6MHAJroBWHFNiEQ= cosmossdk.io/x/nft v0.1.1 h1:pslAVS8P5NkW080+LWOamInjDcq+v2GSCo+BjN9sxZ8= cosmossdk.io/x/nft v0.1.1/go.mod h1:Kac6F6y2gsKvoxU+fy8uvxRTi4BIhLOor2zgCNQwVgY= -cosmossdk.io/x/tx v0.13.4 h1:Eg0PbJgeO0gM8p5wx6xa0fKR7hIV6+8lC56UrsvSo0Y= -cosmossdk.io/x/tx v0.13.4/go.mod h1:BkFqrnGGgW50Y6cwTy+JvgAhiffbGEKW6KF9ufcDpvk= +cosmossdk.io/x/tx v0.13.5 h1:FdnU+MdmFWn1pTsbfU0OCf2u6mJ8cqc1H4OMG418MLw= +cosmossdk.io/x/tx v0.13.5/go.mod h1:V6DImnwJMTq5qFjeGWpXNiT/fjgE4HtmclRmTqRVM3w= cosmossdk.io/x/upgrade v0.1.4 h1:/BWJim24QHoXde8Bc64/2BSEB6W4eTydq0X/2f8+g38= cosmossdk.io/x/upgrade v0.1.4/go.mod h1:9v0Aj+fs97O+Ztw+tG3/tp5JSlrmT7IcFhAebQHmOPo= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= From 43b16f24e1969409d493736ce7a6266e29a845d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:03:34 +0000 Subject: [PATCH 53/60] Bump google.golang.org/grpc from 1.66.2 to 1.67.0 Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.66.2 to 1.67.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.66.2...v1.67.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d4407fad5..eb845f99e 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/stretchr/testify v1.9.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 - google.golang.org/grpc v1.66.2 + google.golang.org/grpc v1.67.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v2 v2.4.0 ) @@ -55,7 +55,7 @@ require ( cloud.google.com/go v0.115.0 // indirect cloud.google.com/go/auth v0.6.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/iam v1.1.9 // indirect cloud.google.com/go/storage v1.41.0 // indirect cosmossdk.io/api v0.7.5 // indirect @@ -112,7 +112,7 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect - github.com/golang/glog v1.2.1 // indirect + github.com/golang/glog v1.2.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/google/btree v1.1.2 // indirect diff --git a/go.sum b/go.sum index 47b7d96af..0fae92b6a 100644 --- a/go.sum +++ b/go.sum @@ -72,8 +72,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -520,8 +520,8 @@ github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2 github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1676,8 +1676,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= -google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= +google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 8e3f5df1be4adcbdd6b266861c4219b7fda46cb8 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 17:17:30 -0400 Subject: [PATCH 54/60] Remove hardcoded dex pause logic --- Makefile | 2 +- x/dex/keeper/msg_server.go | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a2a54ab7c..9c8a00e2d 100644 --- a/Makefile +++ b/Makefile @@ -178,7 +178,7 @@ test: test-unit test-all: check test-race test-cover test-unit: - @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' `go list ./... | grep -v dex` + @VERSION=$(VERSION) go test -mod=readonly -tags='ledger test_ledger_mock' ./... test-race: @VERSION=$(VERSION) go test -mod=readonly -race -tags='ledger test_ledger_mock' ./... diff --git a/x/dex/keeper/msg_server.go b/x/dex/keeper/msg_server.go index 2b3bca666..1211cc57b 100644 --- a/x/dex/keeper/msg_server.go +++ b/x/dex/keeper/msg_server.go @@ -259,6 +259,12 @@ func (k MsgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParam return &types.MsgUpdateParamsResponse{}, nil } -func (k MsgServer) AssertNotPaused(_ context.Context) error { - return types.ErrDexPaused +func (k MsgServer) AssertNotPaused(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + paused := k.GetParams(ctx).Paused + + if paused { + return types.ErrDexPaused + } + return nil } From 0c6e58ad6d27b2b210a74ffeb3f17f61b55c3f13 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 17:41:21 -0400 Subject: [PATCH 55/60] Add dex pause migration --- app/app.go | 4 +- app/upgrades/types.go | 2 + app/upgrades/v5.0.0/constants.go | 20 +++++++++ app/upgrades/v5.0.0/upgrades.go | 54 +++++++++++++++++++++++ app/upgrades/v5.0.0/upgrades_test.go | 64 ++++++++++++++++++++++++++++ 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 app/upgrades/v5.0.0/constants.go create mode 100644 app/upgrades/v5.0.0/upgrades.go create mode 100644 app/upgrades/v5.0.0/upgrades_test.go diff --git a/app/app.go b/app/app.go index 0d105a861..e5f286eab 100644 --- a/app/app.go +++ b/app/app.go @@ -37,6 +37,7 @@ import ( servicemetrics "github.com/skip-mev/slinky/service/metrics" v401 "github.com/neutron-org/neutron/v4/app/upgrades/v4.0.1" + v500 "github.com/neutron-org/neutron/v4/app/upgrades/v5.0.0" "github.com/neutron-org/neutron/v4/x/globalfee" globalfeetypes "github.com/neutron-org/neutron/v4/x/globalfee/types" @@ -221,7 +222,7 @@ const ( ) var ( - Upgrades = []upgrades.Upgrade{v401.Upgrade} + Upgrades = []upgrades.Upgrade{v401.Upgrade, v500.Upgrade} // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string @@ -1396,6 +1397,7 @@ func (app *App) setupUpgradeHandlers() { MarketmapKeeper: app.MarketMapKeeper, FeeMarketKeeper: app.FeeMarkerKeeper, DynamicfeesKeeper: app.DynamicFeesKeeper, + DexKeeper: &app.DexKeeper, GlobalFeeSubspace: app.GetSubspace(globalfee.ModuleName), CcvConsumerSubspace: app.GetSubspace(ccvconsumertypes.ModuleName), }, diff --git a/app/upgrades/types.go b/app/upgrades/types.go index d94491025..dfbce160c 100644 --- a/app/upgrades/types.go +++ b/app/upgrades/types.go @@ -21,6 +21,7 @@ import ( contractmanagerkeeper "github.com/neutron-org/neutron/v4/x/contractmanager/keeper" cronkeeper "github.com/neutron-org/neutron/v4/x/cron/keeper" + dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" feeburnerkeeper "github.com/neutron-org/neutron/v4/x/feeburner/keeper" icqkeeper "github.com/neutron-org/neutron/v4/x/interchainqueries/keeper" tokenfactorykeeper "github.com/neutron-org/neutron/v4/x/tokenfactory/keeper" @@ -64,6 +65,7 @@ type UpgradeKeepers struct { MarketmapKeeper *marketmapkeeper.Keeper FeeMarketKeeper *feemarketkeeper.Keeper DynamicfeesKeeper *dynamicfeeskeeper.Keeper + DexKeeper *dexkeeper.Keeper // subspaces GlobalFeeSubspace paramtypes.Subspace CcvConsumerSubspace paramtypes.Subspace diff --git a/app/upgrades/v5.0.0/constants.go b/app/upgrades/v5.0.0/constants.go new file mode 100644 index 000000000..1eeb344c5 --- /dev/null +++ b/app/upgrades/v5.0.0/constants.go @@ -0,0 +1,20 @@ +package v400 + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/neutron-org/neutron/v4/app/upgrades" +) + +const ( + // UpgradeName defines the on-chain upgrade name. + UpgradeName = "v5.0.0" +) + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: storetypes.StoreUpgrades{ + Added: []string{}, + }, +} diff --git a/app/upgrades/v5.0.0/upgrades.go b/app/upgrades/v5.0.0/upgrades.go new file mode 100644 index 000000000..648145982 --- /dev/null +++ b/app/upgrades/v5.0.0/upgrades.go @@ -0,0 +1,54 @@ +package v400 + +import ( + "context" + "fmt" + + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/neutron-org/neutron/v4/app/upgrades" + dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + keepers *upgrades.UpgradeKeepers, + _ upgrades.StoreKeys, + _ codec.Codec, +) upgradetypes.UpgradeHandler { + return func(c context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx := sdk.UnwrapSDKContext(c) + + ctx.Logger().Info("Starting module migrations...") + vm, err := mm.RunMigrations(ctx, configurator, vm) + if err != nil { + return vm, err + } + + ctx.Logger().Info("Running dex upgrades...") + err = upgradeDexPause(ctx, *keepers.DexKeeper) + if err != nil { + return nil, err + } + + ctx.Logger().Info(fmt.Sprintf("Migration {%s} applied", UpgradeName)) + return vm, nil + } +} + +func upgradeDexPause(ctx sdk.Context, k dexkeeper.Keeper) error { + // Set the dex to paused + ctx.Logger().Info("Pausing dex...") + + params := k.GetParams(ctx) + params.Paused = true + k.SetParams(ctx, params) + + ctx.Logger().Info("Dex is paused ") + + return nil +} diff --git a/app/upgrades/v5.0.0/upgrades_test.go b/app/upgrades/v5.0.0/upgrades_test.go new file mode 100644 index 000000000..61d774aad --- /dev/null +++ b/app/upgrades/v5.0.0/upgrades_test.go @@ -0,0 +1,64 @@ +package v400_test + +import ( + "testing" + + "cosmossdk.io/math" + upgradetypes "cosmossdk.io/x/upgrade/types" + v500 "github.com/neutron-org/neutron/v4/app/upgrades/v5.0.0" + "github.com/neutron-org/neutron/v4/testutil/common/sample" + math_utils "github.com/neutron-org/neutron/v4/utils/math" + "github.com/stretchr/testify/suite" + + "github.com/neutron-org/neutron/v4/testutil" + dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" + dextypes "github.com/neutron-org/neutron/v4/x/dex/types" +) + +type UpgradeTestSuite struct { + testutil.IBCConnectionTestSuite +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +func (suite *UpgradeTestSuite) SetupTest() { + suite.IBCConnectionTestSuite.SetupTest() +} + +func (suite *UpgradeTestSuite) TestUpgradeDexPause() { + var ( + app = suite.GetNeutronZoneApp(suite.ChainA) + ctx = suite.ChainA.GetContext() + msgServer = dexkeeper.NewMsgServerImpl(app.DexKeeper) + ) + + params := app.DexKeeper.GetParams(ctx) + + suite.False(params.Paused) + + upgrade := upgradetypes.Plan{ + Name: v500.UpgradeName, + Info: "some text here", + Height: 100, + } + suite.NoError(app.UpgradeKeeper.ApplyUpgrade(ctx, upgrade)) + + params = app.DexKeeper.GetParams(ctx) + + suite.True(params.Paused) + + price := math_utils.OnePrecDec() + _, err := msgServer.PlaceLimitOrder(ctx, &dextypes.MsgPlaceLimitOrder{ + Creator: sample.AccAddress(), + Receiver: sample.AccAddress(), + TokenIn: "TokenA", + TokenOut: "TokenB", + LimitSellPrice: &price, + AmountIn: math.OneInt(), + }) + + suite.ErrorIs(err, dextypes.ErrDexPaused) + +} From 18751824bd9a2d93723524d9c1231a14c713fb7e Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 17:44:04 -0400 Subject: [PATCH 56/60] fmt --- app/upgrades/v5.0.0/upgrades.go | 7 +++++-- app/upgrades/v5.0.0/upgrades_test.go | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/upgrades/v5.0.0/upgrades.go b/app/upgrades/v5.0.0/upgrades.go index 648145982..eda525e31 100644 --- a/app/upgrades/v5.0.0/upgrades.go +++ b/app/upgrades/v5.0.0/upgrades.go @@ -46,9 +46,12 @@ func upgradeDexPause(ctx sdk.Context, k dexkeeper.Keeper) error { params := k.GetParams(ctx) params.Paused = true - k.SetParams(ctx, params) - ctx.Logger().Info("Dex is paused ") + if err := k.SetParams(ctx, params); err != nil { + return err + } + + ctx.Logger().Info("Dex is paused") return nil } diff --git a/app/upgrades/v5.0.0/upgrades_test.go b/app/upgrades/v5.0.0/upgrades_test.go index 61d774aad..c9e1da782 100644 --- a/app/upgrades/v5.0.0/upgrades_test.go +++ b/app/upgrades/v5.0.0/upgrades_test.go @@ -5,10 +5,11 @@ import ( "cosmossdk.io/math" upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/stretchr/testify/suite" + v500 "github.com/neutron-org/neutron/v4/app/upgrades/v5.0.0" "github.com/neutron-org/neutron/v4/testutil/common/sample" math_utils "github.com/neutron-org/neutron/v4/utils/math" - "github.com/stretchr/testify/suite" "github.com/neutron-org/neutron/v4/testutil" dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" @@ -60,5 +61,4 @@ func (suite *UpgradeTestSuite) TestUpgradeDexPause() { }) suite.ErrorIs(err, dextypes.ErrDexPaused) - } From a51c29a36daddcd8991a2028a605ccef674dadc0 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 17:54:12 -0400 Subject: [PATCH 57/60] Only pause dex for mainnet --- app/upgrades/v5.0.0/upgrades.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/upgrades/v5.0.0/upgrades.go b/app/upgrades/v5.0.0/upgrades.go index eda525e31..debee5718 100644 --- a/app/upgrades/v5.0.0/upgrades.go +++ b/app/upgrades/v5.0.0/upgrades.go @@ -30,7 +30,11 @@ func CreateUpgradeHandler( } ctx.Logger().Info("Running dex upgrades...") - err = upgradeDexPause(ctx, *keepers.DexKeeper) + // Only pause dex for mainnet + if ctx.ChainID() == "neutron-1" { + err = upgradeDexPause(ctx, *keepers.DexKeeper) + } + if err != nil { return nil, err } From 8e40bbe41d48951ae52fa5d375854950b5bec63b Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 17:54:59 -0400 Subject: [PATCH 58/60] typo --- app/upgrades/v5.0.0/upgrades.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/upgrades/v5.0.0/upgrades.go b/app/upgrades/v5.0.0/upgrades.go index debee5718..9c5e46a57 100644 --- a/app/upgrades/v5.0.0/upgrades.go +++ b/app/upgrades/v5.0.0/upgrades.go @@ -33,10 +33,9 @@ func CreateUpgradeHandler( // Only pause dex for mainnet if ctx.ChainID() == "neutron-1" { err = upgradeDexPause(ctx, *keepers.DexKeeper) - } - - if err != nil { - return nil, err + if err != nil { + return nil, err + } } ctx.Logger().Info(fmt.Sprintf("Migration {%s} applied", UpgradeName)) From da18547bd0ba80485ce2ca111ee55eaf580304f3 Mon Sep 17 00:00:00 2001 From: Julian Compagni Portis Date: Mon, 23 Sep 2024 18:28:07 -0400 Subject: [PATCH 59/60] fix tests --- app/upgrades/v5.0.0/upgrades_test.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/upgrades/v5.0.0/upgrades_test.go b/app/upgrades/v5.0.0/upgrades_test.go index c9e1da782..0a5d07207 100644 --- a/app/upgrades/v5.0.0/upgrades_test.go +++ b/app/upgrades/v5.0.0/upgrades_test.go @@ -9,7 +9,6 @@ import ( v500 "github.com/neutron-org/neutron/v4/app/upgrades/v5.0.0" "github.com/neutron-org/neutron/v4/testutil/common/sample" - math_utils "github.com/neutron-org/neutron/v4/utils/math" "github.com/neutron-org/neutron/v4/testutil" dexkeeper "github.com/neutron-org/neutron/v4/x/dex/keeper" @@ -31,7 +30,7 @@ func (suite *UpgradeTestSuite) SetupTest() { func (suite *UpgradeTestSuite) TestUpgradeDexPause() { var ( app = suite.GetNeutronZoneApp(suite.ChainA) - ctx = suite.ChainA.GetContext() + ctx = suite.ChainA.GetContext().WithChainID("neutron-1") msgServer = dexkeeper.NewMsgServerImpl(app.DexKeeper) ) @@ -50,14 +49,16 @@ func (suite *UpgradeTestSuite) TestUpgradeDexPause() { suite.True(params.Paused) - price := math_utils.OnePrecDec() - _, err := msgServer.PlaceLimitOrder(ctx, &dextypes.MsgPlaceLimitOrder{ - Creator: sample.AccAddress(), - Receiver: sample.AccAddress(), - TokenIn: "TokenA", - TokenOut: "TokenB", - LimitSellPrice: &price, - AmountIn: math.OneInt(), + _, err := msgServer.Deposit(ctx, &dextypes.MsgDeposit{ + Creator: sample.AccAddress(), + Receiver: sample.AccAddress(), + TokenA: "TokenA", + TokenB: "TokenB", + TickIndexesAToB: []int64{1}, + Fees: []uint64{1}, + AmountsA: []math.Int{math.OneInt()}, + AmountsB: []math.Int{math.ZeroInt()}, + Options: []*dextypes.DepositOptions{{}}, }) suite.ErrorIs(err, dextypes.ErrDexPaused) From f7b3163f7be94f2b719d446b7046712844823ed7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 08:11:31 +0000 Subject: [PATCH 60/60] Bump github.com/CosmWasm/wasmvm/v2 from 2.1.2 to 2.1.3 Bumps [github.com/CosmWasm/wasmvm/v2](https://github.com/CosmWasm/wasmvm) from 2.1.2 to 2.1.3. - [Release notes](https://github.com/CosmWasm/wasmvm/releases) - [Changelog](https://github.com/CosmWasm/wasmvm/blob/main/CHANGELOG.md) - [Commits](https://github.com/CosmWasm/wasmvm/compare/v2.1.2...v2.1.3) --- updated-dependencies: - dependency-name: github.com/CosmWasm/wasmvm/v2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eb845f99e..e8714d399 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( cosmossdk.io/x/tx v0.13.5 cosmossdk.io/x/upgrade v0.1.4 github.com/CosmWasm/wasmd v0.51.0 - github.com/CosmWasm/wasmvm/v2 v2.1.2 + github.com/CosmWasm/wasmvm/v2 v2.1.3 github.com/cometbft/cometbft v0.38.11 github.com/cosmos/admin-module/v2 v2.0.0-20240430142959-8b3328d1b1a2 github.com/cosmos/cosmos-db v1.0.2 diff --git a/go.sum b/go.sum index 0fae92b6a..c8c82dde1 100644 --- a/go.sum +++ b/go.sum @@ -225,8 +225,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CosmWasm/wasmvm/v2 v2.1.2 h1:GkJ5bAsRlLHfIQVg/FY1VHwLyBwlCjAhDea0B8L+e20= -github.com/CosmWasm/wasmvm/v2 v2.1.2/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg= +github.com/CosmWasm/wasmvm/v2 v2.1.3 h1:CSJTauZqkHyb9yic6JVYCjiGUgxI2MJV2QzfSu8m49c= +github.com/CosmWasm/wasmvm/v2 v2.1.3/go.mod h1:bMhLQL4Yp9CzJi9A83aR7VO9wockOsSlZbT4ztOl6bg= github.com/DataDog/datadog-go v3.2.0+incompatible h1:qSG2N4FghB1He/r2mFrWKCaL7dXCilEuNEeAn20fdD4= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=

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