From 0eacc880962ed06adcc2fad4103524108efdd6e3 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 1 Sep 2022 13:19:09 -0400 Subject: [PATCH 01/24] fix: fix Group-TotalWeight invariant (#13116) --- CHANGELOG.md | 3 +-- store/cachekv/store.go | 11 +++++++---- x/group/keeper/invariants.go | 18 +++++++++++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2748296fb48..9b757e243515 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,10 +127,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### CLI Breaking Changes -* / - ### Bug Fixes +* [#13116](https://github.com/cosmos/cosmos-sdk/pull/13116) Fix a dead-lock in the `Group-TotalWeight` `x/group` invariant. * [#13046](https://github.com/cosmos/cosmos-sdk/pull/13046) Fix missing return statement in BaseApp.Query. * [#12548](https://github.com/cosmos/cosmos-sdk/pull/12548) Prevent signing from wrong key while using multisig. * (genutil) [#12140](https://github.com/cosmos/cosmos-sdk/pull/12140) Fix staking's genesis JSON migrate in the `simd migrate v0.46` CLI command. diff --git a/store/cachekv/store.go b/store/cachekv/store.go index bd467c418f91..6d38fd09181a 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -6,6 +6,7 @@ import ( "sort" "sync" + "github.com/tendermint/tendermint/libs/math" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/internal/conv" @@ -13,7 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/store/tracekv" "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/types/kv" - "github.com/tendermint/tendermint/libs/math" ) // cValue represents a cached value. @@ -378,11 +378,14 @@ func (store *Store) clearUnsortedCacheSubset(unsorted []*kv.Pair, sortState sort if item.Value == nil { // deleted element, tracked by store.deleted // setting arbitrary value - store.sortedCache.Set(item.Key, []byte{}) + if err := store.sortedCache.Set(item.Key, []byte{}); err != nil { + panic(err) + } + continue } - err := store.sortedCache.Set(item.Key, item.Value) - if err != nil { + + if err := store.sortedCache.Set(item.Key, item.Value); err != nil { panic(err) } } diff --git a/x/group/keeper/invariants.go b/x/group/keeper/invariants.go index 2008fd3c9347..24b592a37020 100644 --- a/x/group/keeper/invariants.go +++ b/x/group/keeper/invariants.go @@ -38,12 +38,8 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, g } defer groupIt.Close() + groups := make(map[uint64]group.GroupInfo) for { - membersWeight, err := groupmath.NewNonNegativeDecFromString("0") - if err != nil { - msg += fmt.Sprintf("error while parsing positive dec zero for group member\n%v\n", err) - return msg, broken - } var groupInfo group.GroupInfo _, err = groupIt.LoadNext(&groupInfo) if errors.ErrORMIteratorDone.Is(err) { @@ -54,6 +50,16 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, g return msg, broken } + groups[groupInfo.Id] = groupInfo + } + + for _, groupInfo := range groups { + membersWeight, err := groupmath.NewNonNegativeDecFromString("0") + if err != nil { + msg += fmt.Sprintf("error while parsing positive dec zero for group member\n%v\n", err) + return msg, broken + } + memIt, err := groupMemberByGroupIndex.Get(ctx.KVStore(key), groupInfo.Id) if err != nil { msg += fmt.Sprintf("error while returning group member iterator for group with ID %d\n%v\n", groupInfo.Id, err) @@ -77,6 +83,7 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, g msg += fmt.Sprintf("error while parsing non-nengative decimal for group member %s\n%v\n", groupMember.Member.Address, err) return msg, broken } + membersWeight, err = groupmath.Add(membersWeight, curMemWeight) if err != nil { msg += fmt.Sprintf("decimal addition error while adding group member voting weight to total voting weight\n%v\n", err) @@ -96,5 +103,6 @@ func GroupTotalWeightInvariantHelper(ctx sdk.Context, key storetypes.StoreKey, g break } } + return msg, broken } From 3e3b225a5e77a0da2bdff46f16cb4945f4396c76 Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Thu, 1 Sep 2022 23:53:43 +0530 Subject: [PATCH 02/24] refactor(mint): CLI tests using Tendermint Mock (#13059) * wip: mint CLI tests using Tendermint Mock * try fix test * remove query test * add cli tests Co-authored-by: Aleksandr Bezobchuk --- .../mint/{client/testutil => }/cli_test.go | 5 +- .../testutil => tests/e2e/mint}/grpc.go | 2 +- .../testutil => tests/e2e/mint}/suite.go | 2 +- x/mint/client/cli/query_test.go | 233 ++++++++++++++++++ 4 files changed, 237 insertions(+), 5 deletions(-) rename tests/e2e/mint/{client/testutil => }/cli_test.go (68%) rename {x/mint/client/testutil => tests/e2e/mint}/grpc.go (99%) rename {x/mint/client/testutil => tests/e2e/mint}/suite.go (99%) create mode 100644 x/mint/client/cli/query_test.go diff --git a/tests/e2e/mint/client/testutil/cli_test.go b/tests/e2e/mint/cli_test.go similarity index 68% rename from tests/e2e/mint/client/testutil/cli_test.go rename to tests/e2e/mint/cli_test.go index 513b8f43ebcd..1dc1138fe5d1 100644 --- a/tests/e2e/mint/client/testutil/cli_test.go +++ b/tests/e2e/mint/cli_test.go @@ -1,7 +1,7 @@ //go:build e2e // +build e2e -package testutil +package mint import ( "testing" @@ -10,11 +10,10 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/network" - clienttestutil "github.com/cosmos/cosmos-sdk/x/mint/client/testutil" ) func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 1 - suite.Run(t, clienttestutil.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/mint/client/testutil/grpc.go b/tests/e2e/mint/grpc.go similarity index 99% rename from x/mint/client/testutil/grpc.go rename to tests/e2e/mint/grpc.go index 12b78e0f4b05..3e34fa44a7df 100644 --- a/x/mint/client/testutil/grpc.go +++ b/tests/e2e/mint/grpc.go @@ -1,4 +1,4 @@ -package testutil +package mint import ( "fmt" diff --git a/x/mint/client/testutil/suite.go b/tests/e2e/mint/suite.go similarity index 99% rename from x/mint/client/testutil/suite.go rename to tests/e2e/mint/suite.go index dd90d2d54333..8047f3c86fb9 100644 --- a/x/mint/client/testutil/suite.go +++ b/tests/e2e/mint/suite.go @@ -1,4 +1,4 @@ -package testutil +package mint import ( "fmt" diff --git a/x/mint/client/cli/query_test.go b/x/mint/client/cli/query_test.go new file mode 100644 index 000000000000..bc34c5dec9e3 --- /dev/null +++ b/x/mint/client/cli/query_test.go @@ -0,0 +1,233 @@ +package cli_test + +import ( + "context" + "fmt" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" + coretypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + + "github.com/cosmos/cosmos-sdk/crypto/keyring" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/mint" + mintcli "github.com/cosmos/cosmos-sdk/x/mint/client/cli" + tmcli "github.com/tendermint/tendermint/libs/cli" +) + +var _ client.TendermintRPC = (*mockTendermintRPC)(nil) + +type mockTendermintRPC struct { + rpcclientmock.Client + + responseQuery abci.ResponseQuery +} + +func (_ mockTendermintRPC) BroadcastTxCommit(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + return &coretypes.ResultBroadcastTxCommit{}, nil +} + +func (m mockTendermintRPC) ABCIQueryWithOptions( + _ context.Context, + _ string, _ bytes.HexBytes, + _ rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil +} + +func TestGetCmdQueryParams(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + cmd := mintcli.GetCmdQueryParams() + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + `[--height=1 --output=json]`, + `{"mint_denom":"","inflation_rate_change":"0","inflation_max":"0","inflation_min":"0","goal_bonded":"0","blocks_per_year":"0"}`, + }, + { + "text output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=text", tmcli.OutputFlag)}, + `[--height=1 --output=text]`, + `blocks_per_year: "0" +goal_bonded: "0" +inflation_max: "0" +inflation_min: "0" +inflation_rate_change: "0" +mint_denom: ""`, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.flagArgs) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "params [] [] Query the current minting parameters") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := clitestutil.ExecTestCLICmd(baseCtx, cmd, tc.flagArgs) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} + +func TestGetCmdQueryInflation(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + cmd := mintcli.GetCmdQueryInflation() + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + `[--height=1 --output=json]`, + ``, + }, + { + "text output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=text", tmcli.OutputFlag)}, + `[--height=1 --output=text]`, + ``, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.flagArgs) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "inflation [] [] Query the current minting inflation value") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := clitestutil.ExecTestCLICmd(baseCtx, cmd, tc.flagArgs) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} + +func TestGetCmdQueryAnnualProvisions(t *testing.T) { + encCfg := testutilmod.MakeTestEncodingConfig(mint.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + cmd := mintcli.GetCmdQueryAnnualProvisions() + + testCases := []struct { + name string + flagArgs []string + expCmdOutput string + expectedOutput string + }{ + { + "json output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + `[--height=1 --output=json]`, + ``, + }, + { + "text output", + []string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=text", tmcli.OutputFlag)}, + `[--height=1 --output=text]`, + ``, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.flagArgs) + + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + + if len(tc.flagArgs) != 0 { + require.Contains(t, fmt.Sprint(cmd), "annual-provisions [] [] Query the current minting annual provisions value") + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := clitestutil.ExecTestCLICmd(baseCtx, cmd, tc.flagArgs) + require.NoError(t, err) + require.Equal(t, tc.expectedOutput, strings.TrimSpace(out.String())) + }) + } +} From bf8f015797ed820799bb4301a4330726e6ebb677 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 1 Sep 2022 15:33:54 -0400 Subject: [PATCH 03/24] refactor: update core module to depinject changes (#13115) --- core/appconfig/config.go | 10 +-- core/appconfig/config_test.go | 108 +++++++++++++++++++++++++++++++- core/appmodule/option.go | 15 +---- core/go.mod | 4 +- core/go.sum | 10 +-- core/internal/registry.go | 6 +- core/internal/testpb/modules.go | 106 ------------------------------- 7 files changed, 118 insertions(+), 141 deletions(-) delete mode 100644 core/internal/testpb/modules.go diff --git a/core/appconfig/config.go b/core/appconfig/config.go index 27db644ecff4..75c9c2e90571 100644 --- a/core/appconfig/config.go +++ b/core/appconfig/config.go @@ -2,7 +2,6 @@ package appconfig import ( "fmt" - "reflect" "strings" "google.golang.org/protobuf/encoding/protojson" @@ -94,14 +93,7 @@ func Compose(appConfig *appv1alpha1.Config) depinject.Config { return depinject.Error(err) } - opts = append(opts, depinject.Provide(depinject.ProviderDescriptor{ - Inputs: nil, - Outputs: []depinject.ProviderOutput{{Type: init.ConfigGoType}}, - Fn: func(values []reflect.Value) ([]reflect.Value, error) { - return []reflect.Value{reflect.ValueOf(config)}, nil - }, - Location: depinject.LocationFromCaller(0), - })) + opts = append(opts, depinject.Supply(config)) for _, provider := range init.Providers { opts = append(opts, depinject.ProvideInModule(module.Name, provider)) diff --git a/core/appconfig/config_test.go b/core/appconfig/config_test.go index c5d04ba48465..e67408f6908a 100644 --- a/core/appconfig/config_test.go +++ b/core/appconfig/config_test.go @@ -2,17 +2,21 @@ package appconfig_test import ( "bytes" + "fmt" + "io" "reflect" + "sort" "testing" "gotest.tools/v3/assert" + "cosmossdk.io/depinject" + "cosmossdk.io/core/appconfig" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/internal" "cosmossdk.io/core/internal/testpb" _ "cosmossdk.io/core/internal/testpb" - "cosmossdk.io/depinject" ) func expectContainerErrorContains(t *testing.T, option depinject.Config, contains string) { @@ -56,7 +60,7 @@ modules: expectContainerErrorContains(t, opt, "registered modules are") expectContainerErrorContains(t, opt, "testpb.TestModuleA") - var app testpb.App + var app App opt = appconfig.LoadYAML([]byte(` modules: - name: runtime @@ -119,3 +123,103 @@ modules: `)) expectContainerErrorContains(t, opt, "module should have ModuleDescriptor.go_import specified") } + +// +// Test Module Initialization Logic +// + +func init() { + appmodule.Register(&testpb.TestRuntimeModule{}, + appmodule.Provide(ProvideRuntimeState, ProvideStoreKey, ProvideApp), + ) + + appmodule.Register(&testpb.TestModuleA{}, + appmodule.Provide(ProvideModuleA), + ) + + appmodule.Register(&testpb.TestModuleB{}, + appmodule.Provide(ProvideModuleB), + ) +} + +func ProvideRuntimeState() *RuntimeState { + return &RuntimeState{} +} + +func ProvideStoreKey(key depinject.ModuleKey, state *RuntimeState) StoreKey { + sk := StoreKey{name: key.Name()} + state.storeKeys = append(state.storeKeys, sk) + return sk +} + +func ProvideApp(state *RuntimeState, handlers map[string]Handler) App { + return func(w io.Writer) { + sort.Slice(state.storeKeys, func(i, j int) bool { + return state.storeKeys[i].name < state.storeKeys[j].name + }) + + for _, key := range state.storeKeys { + _, _ = fmt.Fprintf(w, "got store key %s\n", key.name) + } + + var modNames []string + for modName := range handlers { + modNames = append(modNames, modName) + } + + sort.Strings(modNames) + for _, name := range modNames { + _, _ = fmt.Fprintf(w, "running module handler %s\n", name) + _, _ = fmt.Fprintf(w, "result: %s\n", handlers[name].DoSomething()) + } + } +} + +type App func(writer io.Writer) + +type RuntimeState struct { + storeKeys []StoreKey +} + +type StoreKey struct{ name string } + +type Handler struct { + DoSomething func() string +} + +func (h Handler) IsOnePerModuleType() {} + +func ProvideModuleA(key StoreKey) (KeeperA, Handler) { + return keeperA{key: key}, Handler{DoSomething: func() string { + return "hello" + }} +} + +type keeperA struct { + key StoreKey +} + +type KeeperA interface { + Foo() +} + +func (k keeperA) Foo() {} + +func ProvideModuleB(key StoreKey, a KeeperA) (KeeperB, Handler) { + return keeperB{key: key, a: a}, Handler{ + DoSomething: func() string { + return "goodbye" + }, + } +} + +type keeperB struct { + key StoreKey + a KeeperA +} + +type KeeperB interface { + isKeeperB() +} + +func (k keeperB) isKeeperB() {} diff --git a/core/appmodule/option.go b/core/appmodule/option.go index ee1ee6492f72..4c041c0cb707 100644 --- a/core/appmodule/option.go +++ b/core/appmodule/option.go @@ -2,7 +2,6 @@ package appmodule import ( "cosmossdk.io/core/internal" - "cosmossdk.io/depinject" ) // Option is a functional option for implementing modules. @@ -22,12 +21,7 @@ func (f funcOption) apply(initializer *internal.ModuleInitializer) error { func Provide(providers ...interface{}) Option { return funcOption(func(initializer *internal.ModuleInitializer) error { for _, provider := range providers { - desc, err := depinject.ExtractProviderDescriptor(provider) - if err != nil { - return err - } - - initializer.Providers = append(initializer.Providers, desc) + initializer.Providers = append(initializer.Providers, provider) } return nil }) @@ -40,12 +34,7 @@ func Provide(providers ...interface{}) Option { func Invoke(invokers ...interface{}) Option { return funcOption(func(initializer *internal.ModuleInitializer) error { for _, invoker := range invokers { - desc, err := depinject.ExtractInvokerDescriptor(invoker) - if err != nil { - return err - } - - initializer.Invokers = append(initializer.Invokers, desc) + initializer.Invokers = append(initializer.Invokers, invoker) } return nil }) diff --git a/core/go.mod b/core/go.mod index ce5cb8590d13..321ff3fbb6a3 100644 --- a/core/go.mod +++ b/core/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( cosmossdk.io/api v0.1.0-alpha9 - cosmossdk.io/depinject v1.0.0-alpha.2 + cosmossdk.io/depinject v1.0.0-alpha.3 github.com/cosmos/cosmos-proto v1.0.0-alpha7 google.golang.org/protobuf v1.28.1 gotest.tools/v3 v3.3.0 @@ -16,7 +16,7 @@ require ( github.com/google/go-cmp v0.5.8 // indirect github.com/kr/text v0.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect + golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect golang.org/x/net v0.0.0-20220726230323-06994584191e // indirect golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect golang.org/x/text v0.3.7 // indirect diff --git a/core/go.sum b/core/go.sum index 9363f44e91af..00781cfbe2f1 100644 --- a/core/go.sum +++ b/core/go.sum @@ -1,7 +1,7 @@ cosmossdk.io/api v0.1.0-alpha9 h1:8QQT+BhaMpcCgR4Wm8JVuhhtj4a7uZjsxvvWvmsQFB0= cosmossdk.io/api v0.1.0-alpha9/go.mod h1:PyJpp0BY4tHLI0kzkiUzpZxgOE+pJbhDPleYrA5yVio= -cosmossdk.io/depinject v1.0.0-alpha.2 h1:pVcPnqc8bY2GCHVMj77rk6Ew7uz0K3QhrUHdqoKvO5g= -cosmossdk.io/depinject v1.0.0-alpha.2/go.mod h1:Wmu0TV/H4s4s8zaJ9YnaioLyCbqlCvMQ4xTtzJzGzvA= +cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= +cosmossdk.io/depinject v1.0.0-alpha.3/go.mod h1:eRbcdQ7MRpIPEM5YUJh8k97nxHpYbc3sMUnEtt8HPWU= github.com/alecthomas/participle/v2 v2.0.0-alpha7 h1:cK4vjj0VSgb3lN1nuKA5F7dw+1s1pWBe5bx7nNCnN+c= github.com/cockroachdb/apd/v3 v3.1.0 h1:MK3Ow7LH0W8zkd5GMKA1PvS9qG3bWFI95WaVNfyZJ/w= github.com/cosmos/cosmos-proto v1.0.0-alpha7 h1:yqYUOHF2jopwZh4dVQp3xgqwftE5/2hkrwIV6vkUbO0= @@ -37,8 +37,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 h1:tnebWN09GYg9OLPss1KXj8txwZc6X6uMr6VFdcGNbHw= +golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -82,6 +82,6 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A= pgregory.net/rapid v0.4.7/go.mod h1:UYpPVyjFHzYBGHIxLFoupi8vwk6rXNzRY9OMvVxFIOU= -pgregory.net/rapid v0.4.8 h1:d+5SGZWUbJPbl3ss6tmPFqnNeQR6VDOFly+eTjwPiEw= +pgregory.net/rapid v0.5.2 h1:zC+jmuzcz5yJvG/igG06aLx8kcGmZY435NcuyhblKjY= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/core/internal/registry.go b/core/internal/registry.go index beb8a5446332..ce8dbb203f17 100644 --- a/core/internal/registry.go +++ b/core/internal/registry.go @@ -8,8 +8,6 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" - - "cosmossdk.io/depinject" ) // ModuleRegistry is the registry of module initializers indexed by their golang @@ -21,8 +19,8 @@ type ModuleInitializer struct { ConfigGoType reflect.Type ConfigProtoMessage proto.Message Error error - Providers []depinject.ProviderDescriptor - Invokers []depinject.ProviderDescriptor + Providers []interface{} + Invokers []interface{} } // ModulesByProtoMessageName should be used to retrieve modules by their protobuf name. diff --git a/core/internal/testpb/modules.go b/core/internal/testpb/modules.go deleted file mode 100644 index c554ad73e236..000000000000 --- a/core/internal/testpb/modules.go +++ /dev/null @@ -1,106 +0,0 @@ -package testpb - -import ( - "fmt" - "io" - "sort" - - "cosmossdk.io/core/appmodule" - "cosmossdk.io/depinject" -) - -func init() { - appmodule.Register(&TestRuntimeModule{}, - appmodule.Provide(provideRuntimeState, provideStoreKey, provideApp), - ) - - appmodule.Register(&TestModuleA{}, - appmodule.Provide(provideModuleA), - ) - - appmodule.Register(&TestModuleB{}, - appmodule.Provide(provideModuleB), - ) -} - -func provideRuntimeState() *runtimeState { - return &runtimeState{} -} - -func provideStoreKey(key depinject.ModuleKey, state *runtimeState) StoreKey { - sk := StoreKey{name: key.Name()} - state.storeKeys = append(state.storeKeys, sk) - return sk -} - -func provideApp(state *runtimeState, handlers map[string]Handler) App { - return func(w io.Writer) { - sort.Slice(state.storeKeys, func(i, j int) bool { - return state.storeKeys[i].name < state.storeKeys[j].name - }) - - for _, key := range state.storeKeys { - _, _ = fmt.Fprintf(w, "got store key %s\n", key.name) - } - - var modNames []string - for modName := range handlers { - modNames = append(modNames, modName) - } - - sort.Strings(modNames) - for _, name := range modNames { - _, _ = fmt.Fprintf(w, "running module handler %s\n", name) - _, _ = fmt.Fprintf(w, "result: %s\n", handlers[name].DoSomething()) - } - } -} - -type App func(writer io.Writer) - -type runtimeState struct { - storeKeys []StoreKey -} - -type StoreKey struct{ name string } - -type Handler struct { - DoSomething func() string -} - -func (h Handler) IsOnePerModuleType() {} - -func provideModuleA(key StoreKey) (KeeperA, Handler) { - return keeperA{key: key}, Handler{DoSomething: func() string { - return "hello" - }} -} - -type keeperA struct { - key StoreKey -} - -type KeeperA interface { - Foo() -} - -func (k keeperA) Foo() {} - -func provideModuleB(key StoreKey, a KeeperA) (KeeperB, Handler) { - return keeperB{key: key, a: a}, Handler{ - DoSomething: func() string { - return "goodbye" - }, - } -} - -type keeperB struct { - key StoreKey - a KeeperA -} - -type KeeperB interface { - isKeeperB() -} - -func (k keeperB) isKeeperB() {} From db8714da9e9e1dcc4b11682f7543486371d648ab Mon Sep 17 00:00:00 2001 From: Facundo Medica <14063057+facundomedica@users.noreply.github.com> Date: Thu, 1 Sep 2022 14:00:50 -0700 Subject: [PATCH 04/24] refactor: remove use of tmos "github.com/tendermint/tendermint/libs/os" (#13113) --- server/start.go | 7 ++++--- simapp/app.go | 5 +++-- simapp/app_legacy.go | 8 +++++--- simapp/simd/cmd/testnet.go | 9 +++------ testutil/network/util.go | 10 ++++------ x/genutil/client/cli/gentx.go | 5 ++--- x/genutil/client/cli/init.go | 5 +++-- x/genutil/types/genesis_state.go | 4 ++-- x/genutil/utils.go | 10 +++++----- x/upgrade/keeper/keeper.go | 7 +++---- 10 files changed, 34 insertions(+), 36 deletions(-) diff --git a/server/start.go b/server/start.go index 307fde9eaedd..4165b8a618c8 100644 --- a/server/start.go +++ b/server/start.go @@ -13,7 +13,6 @@ import ( "github.com/spf13/cobra" "github.com/tendermint/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" @@ -229,12 +228,14 @@ func startStandAlone(ctx *Context, appCreator types.AppCreator) error { err = svr.Start() if err != nil { - tmos.Exit(err.Error()) + fmt.Println(err.Error()) + os.Exit(1) } defer func() { if err = svr.Stop(); err != nil { - tmos.Exit(err.Error()) + fmt.Println(err.Error()) + os.Exit(1) } }() diff --git a/simapp/app.go b/simapp/app.go index 579b7860658d..5c8e3a4f8947 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -4,13 +4,13 @@ package simapp import ( _ "embed" + "fmt" "io" "os" "path/filepath" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" dbm "github.com/tendermint/tm-db" "cosmossdk.io/depinject" @@ -234,7 +234,8 @@ func NewSimApp( // configure state listening capabilities using AppOptions // we are doing nothing with the returned streamingServices and waitGroup in this case if _, _, err := streaming.LoadStreamingServices(app.App.BaseApp, appOpts, app.appCodec, app.keys); err != nil { - tmos.Exit(err.Error()) + fmt.Println(err.Error()) + os.Exit(1) } /**** Module Options ****/ diff --git a/simapp/app_legacy.go b/simapp/app_legacy.go index e4fed7bca94a..d7875db93862 100644 --- a/simapp/app_legacy.go +++ b/simapp/app_legacy.go @@ -4,6 +4,7 @@ package simapp import ( "encoding/json" + "fmt" "io" "os" "path/filepath" @@ -11,7 +12,6 @@ import ( "github.com/spf13/cast" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" dbm "github.com/tendermint/tm-db" "github.com/cosmos/cosmos-sdk/baseapp" @@ -238,7 +238,8 @@ func NewSimApp( // configure state listening capabilities using AppOptions // we are doing nothing with the returned streamingServices and waitGroup in this case if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil { - tmos.Exit(err.Error()) + fmt.Println(err.Error()) + os.Exit(1) } app := &SimApp{ @@ -481,7 +482,8 @@ func NewSimApp( if loadLatest { if err := app.LoadLatestVersion(); err != nil { - tmos.Exit(err.Error()) + fmt.Println(err.Error()) + os.Exit(1) } } diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index ec7b2f4242ca..8c8556990c20 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -13,7 +13,6 @@ import ( "cosmossdk.io/math" "github.com/spf13/cobra" tmconfig "github.com/tendermint/tendermint/config" - tmos "github.com/tendermint/tendermint/libs/os" tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" tmtime "github.com/tendermint/tendermint/types/time" @@ -469,13 +468,11 @@ func calculateIP(ip string, i int) (string, error) { func writeFile(name string, dir string, contents []byte) error { file := filepath.Join(dir, name) - err := tmos.EnsureDir(dir, 0o755) - if err != nil { - return err + if err := os.MkdirAll(dir, 0o755); err != nil { + return fmt.Errorf("could not create directory %q: %w", dir, err) } - err = os.WriteFile(file, contents, 0o644) //nolint: gosec - if err != nil { + if err := os.WriteFile(file, contents, 0o644); err != nil { //nolint: gosec return err } diff --git a/testutil/network/util.go b/testutil/network/util.go index 55af382dd122..1d3f08c5f8e3 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -2,11 +2,11 @@ package network import ( "encoding/json" + "fmt" "os" "path/filepath" "time" - tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/node" "github.com/tendermint/tendermint/p2p" pvm "github.com/tendermint/tendermint/privval" @@ -194,13 +194,11 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance func writeFile(name string, dir string, contents []byte) error { file := filepath.Join(dir, name) - err := tmos.EnsureDir(dir, 0o755) - if err != nil { - return err + if err := os.MkdirAll(dir, 0o755); err != nil { + return fmt.Errorf("could not create directory %q: %w", dir, err) } - err = os.WriteFile(file, contents, 0o644) //nolint: gosec - if err != nil { + if err := os.WriteFile(file, contents, 0o644); err != nil { //nolint: gosec return err } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 433fa987ea16..5bd273112950 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -11,7 +11,6 @@ import ( "github.com/pkg/errors" "github.com/spf13/cobra" - tmos "github.com/tendermint/tendermint/libs/os" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client" @@ -217,8 +216,8 @@ $ %s gentx my-key-name 1000000stake --home=/path/to/home/dir --keyring-backend=o func makeOutputFilepath(rootDir, nodeID string) (string, error) { writePath := filepath.Join(rootDir, "config", "gentx") - if err := tmos.EnsureDir(writePath, 0o700); err != nil { - return "", err + if err := os.MkdirAll(writePath, 0o700); err != nil { + return "", fmt.Errorf("could not create directory %q: %w", writePath, err) } return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil diff --git a/x/genutil/client/cli/init.go b/x/genutil/client/cli/init.go index f3a186b77fe8..77b763aeb734 100644 --- a/x/genutil/client/cli/init.go +++ b/x/genutil/client/cli/init.go @@ -12,7 +12,6 @@ import ( "github.com/spf13/cobra" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/libs/cli" - tmos "github.com/tendermint/tendermint/libs/os" tmrand "github.com/tendermint/tendermint/libs/rand" "github.com/tendermint/tendermint/types" @@ -118,7 +117,9 @@ func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command { overwrite, _ := cmd.Flags().GetBool(FlagOverwrite) stakingBondDenom, _ := cmd.Flags().GetString(FlagStakingBondDenom) - if !overwrite && tmos.FileExists(genFile) { + // use os.Stat to check if the file exists + _, err = os.Stat(genFile) + if !overwrite && !os.IsNotExist(err) { return fmt.Errorf("genesis.json file already exists: %v", genFile) } diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index ad5454bc2c01..b208f73ea9ce 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -3,8 +3,8 @@ package types import ( "encoding/json" "fmt" + "os" - tmos "github.com/tendermint/tendermint/libs/os" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" @@ -78,7 +78,7 @@ func GenesisStateFromGenDoc(genDoc tmtypes.GenesisDoc) (genesisState map[string] // // NOTE: The pubkey input is this machines pubkey. func GenesisStateFromGenFile(genFile string) (genesisState map[string]json.RawMessage, genDoc *tmtypes.GenesisDoc, err error) { - if !tmos.FileExists(genFile) { + if _, err := os.Stat(genFile); os.IsNotExist(err) { return genesisState, genDoc, fmt.Errorf("%s does not exist, run `init` first", genFile) } diff --git a/x/genutil/utils.go b/x/genutil/utils.go index 7fbdc668d8fb..5fca20fbcb4d 100644 --- a/x/genutil/utils.go +++ b/x/genutil/utils.go @@ -3,13 +3,13 @@ package genutil import ( "encoding/json" "fmt" + "os" "path/filepath" "time" "github.com/cosmos/go-bip39" cfg "github.com/tendermint/tendermint/config" tmed25519 "github.com/tendermint/tendermint/crypto/ed25519" - tmos "github.com/tendermint/tendermint/libs/os" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/privval" tmtypes "github.com/tendermint/tendermint/types" @@ -67,13 +67,13 @@ func InitializeNodeValidatorFilesFromMnemonic(config *cfg.Config, mnemonic strin nodeID = string(nodeKey.ID()) pvKeyFile := config.PrivValidatorKeyFile() - if err := tmos.EnsureDir(filepath.Dir(pvKeyFile), 0o777); err != nil { - return "", nil, err + if err := os.MkdirAll(filepath.Dir(pvKeyFile), 0o777); err != nil { + return "", nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvKeyFile), err) } pvStateFile := config.PrivValidatorStateFile() - if err := tmos.EnsureDir(filepath.Dir(pvStateFile), 0o777); err != nil { - return "", nil, err + if err := os.MkdirAll(filepath.Dir(pvStateFile), 0o777); err != nil { + return "", nil, fmt.Errorf("could not create directory %q: %w", filepath.Dir(pvStateFile), err) } var filePV *privval.FilePV diff --git a/x/upgrade/keeper/keeper.go b/x/upgrade/keeper/keeper.go index 21e3ee70fb4a..9d8eeea467bc 100644 --- a/x/upgrade/keeper/keeper.go +++ b/x/upgrade/keeper/keeper.go @@ -3,13 +3,13 @@ package keeper import ( "encoding/binary" "encoding/json" + "fmt" "os" "path" "path/filepath" "sort" "github.com/tendermint/tendermint/libs/log" - tmos "github.com/tendermint/tendermint/libs/os" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -393,9 +393,8 @@ func (k Keeper) DumpUpgradeInfoToDisk(height int64, p types.Plan) error { // GetUpgradeInfoPath returns the upgrade info file path func (k Keeper) GetUpgradeInfoPath() (string, error) { upgradeInfoFileDir := path.Join(k.getHomeDir(), "data") - err := tmos.EnsureDir(upgradeInfoFileDir, os.ModePerm) - if err != nil { - return "", err + if err := os.MkdirAll(upgradeInfoFileDir, os.ModePerm); err != nil { + return "", fmt.Errorf("could not create directory %q: %w", upgradeInfoFileDir, err) } return filepath.Join(upgradeInfoFileDir, types.UpgradeInfoFilename), nil From 9948fb6c7c93e15d3bd1b43c1437e17e03d1ad14 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Thu, 1 Sep 2022 17:29:28 -0400 Subject: [PATCH 05/24] feat: emit cached context events (#13063) --- CHANGELOG.md | 3 ++- types/context.go | 11 +++++++++-- types/context_test.go | 5 +++++ x/gov/abci.go | 6 ------ x/group/keeper/msg_server.go | 8 +------- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b757e243515..7bee3495755c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,7 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features -* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assests via authz MsgSend grant. +* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assets via authz MsgSend grant. * (sdk.Coins) [#12627](https://github.com/cosmos/cosmos-sdk/pull/12627) Make a Denoms method on sdk.Coins. * (testutil) [#12973](https://github.com/cosmos/cosmos-sdk/pull/12973) Add generic `testutil.RandSliceElem` function which selects a random element from the list. * (client) [#12936](https://github.com/cosmos/cosmos-sdk/pull/12936) Add capability to preprocess transactions before broadcasting from a higher level chain. @@ -93,6 +93,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (context) [#13063](https://github.com/cosmos/cosmos-sdk/pull/13063) Update `Context#CacheContext` to automatically emit all events on the parent context's `EventManager`. * (x/bank) [#12706](https://github.com/cosmos/cosmos-sdk/pull/12706) Removed the `testutil` package from the `x/bank/client` package. * (simapp) [#12747](https://github.com/cosmos/cosmos-sdk/pull/12747) Remove `simapp.MakeTestEncodingConfig`. Please use `moduletestutil.MakeTestEncodingConfig` (`types/module/testutil`) in tests instead. * (x/bank) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) `NewSendAuthorization` takes a new argument of an optional list of addresses allowed to receive bank assests via authz MsgSend grant. You can pass `nil` for the same behavior as before, i.e. any recipient is allowed. diff --git a/types/context.go b/types/context.go index d4bca9cec645..8a050a1b0803 100644 --- a/types/context.go +++ b/types/context.go @@ -268,11 +268,18 @@ func (c Context) TransientStore(key storetypes.StoreKey) KVStore { // CacheContext returns a new Context with the multi-store cached and a new // EventManager. The cached context is written to the context when writeCache -// is called. +// is called. Note, events are automatically emitted on the parent context's +// EventManager when the caller executes the write. func (c Context) CacheContext() (cc Context, writeCache func()) { cms := c.MultiStore().CacheMultiStore() cc = c.WithMultiStore(cms).WithEventManager(NewEventManager()) - return cc, cms.Write + + writeCache = func() { + c.EventManager().EmitEvents(cc.EventManager().Events()) + cms.Write() + } + + return cc, writeCache } var _ context.Context = Context{} diff --git a/types/context_test.go b/types/context_test.go index 95406f55c8a9..f5c7cadeb541 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -42,6 +42,10 @@ func (s *contextTestSuite) TestCacheContext() { s.Require().Equal(v1, cstore.Get(k1)) s.Require().Nil(cstore.Get(k2)) + // emit some events + cctx.EventManager().EmitEvent(types.NewEvent("foo", types.NewAttribute("key", "value"))) + cctx.EventManager().EmitEvent(types.NewEvent("bar", types.NewAttribute("key", "value"))) + cstore.Set(k2, v2) s.Require().Equal(v2, cstore.Get(k2)) s.Require().Nil(store.Get(k2)) @@ -49,6 +53,7 @@ func (s *contextTestSuite) TestCacheContext() { write() s.Require().Equal(v2, store.Get(k2)) + s.Require().Len(ctx.EventManager().Events(), 2) } func (s *contextTestSuite) TestLogContext() { diff --git a/x/gov/abci.go b/x/gov/abci.go index a4edadc6888e..f45cc68c3ff0 100644 --- a/x/gov/abci.go +++ b/x/gov/abci.go @@ -85,12 +85,6 @@ func EndBlocker(ctx sdk.Context, keeper *keeper.Keeper) { tagValue = types.AttributeValueProposalPassed logMsg = "passed" - // The cached context is created with a new EventManager. However, since - // the proposal handler execution was successful, we want to track/keep - // any events emitted, so we re-emit to "merge" the events into the - // original Context's EventManager. - ctx.EventManager().EmitEvents(cacheCtx.EventManager().Events()) - // write state to the underlying multi-store writeCache() } else { diff --git a/x/group/keeper/msg_server.go b/x/group/keeper/msg_server.go index fb1ab258901c..6f6cee539f93 100644 --- a/x/group/keeper/msg_server.go +++ b/x/group/keeper/msg_server.go @@ -754,19 +754,13 @@ func (k Keeper) Exec(goCtx context.Context, req *group.MsgExec) (*group.MsgExecR return nil, err } - results, err := k.doExecuteMsgs(cacheCtx, k.router, proposal, addr) - if err != nil { + if _, err := k.doExecuteMsgs(cacheCtx, k.router, proposal, addr); err != nil { proposal.ExecutorResult = group.PROPOSAL_EXECUTOR_RESULT_FAILURE logs = fmt.Sprintf("proposal execution failed on proposal %d, because of error %s", id, err.Error()) k.Logger(ctx).Info("proposal execution failed", "cause", err, "proposalID", id) } else { proposal.ExecutorResult = group.PROPOSAL_EXECUTOR_RESULT_SUCCESS flush() - - for _, res := range results { - // NOTE: The sdk msg handler creates a new EventManager, so events must be correctly propagated back to the current context - ctx.EventManager().EmitEvents(res.GetEvents()) - } } } From dd556936b23d7443cb7fb1da394c35117efa9da7 Mon Sep 17 00:00:00 2001 From: cool-developer <51834436+cool-develope@users.noreply.github.com> Date: Thu, 1 Sep 2022 22:10:52 -0700 Subject: [PATCH 06/24] refactor: use mocks for x/auth/vesting module unit tests (#13127) * add msg_server test for x/auth/vesting * Update msg_server_test.go * Update x/auth/vesting/msg_server_test.go Co-authored-by: Aleksandr Bezobchuk * Update x/auth/vesting/msg_server_test.go Co-authored-by: Aleksandr Bezobchuk Co-authored-by: Marko Co-authored-by: Aleksandr Bezobchuk --- CHANGELOG.md | 2 +- scripts/mockgen.sh | 1 + .../auth/vesting/client/testutil/cli_test.go | 3 +- .../auth/vesting/client/testutil/suite.go | 0 x/auth/vesting/msg_server_test.go | 254 ++++++++++++++++++ .../testutil/expected_keepers_mocks.go | 82 ++++++ x/staking/module_test.go | 1 - 7 files changed, 339 insertions(+), 4 deletions(-) rename {x => tests/e2e}/auth/vesting/client/testutil/suite.go (100%) create mode 100644 x/auth/vesting/msg_server_test.go create mode 100644 x/auth/vesting/testutil/expected_keepers_mocks.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bee3495755c..74ef913933cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,7 +73,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#13048](https://github.com/cosmos/cosmos-sdk/pull/13048) Add handling of AccountNumberStoreKeyPrefix to the x/auth simulation decoder. * [#13101](https://github.com/cosmos/cosmos-sdk/pull/13101) Remove weights from `simapp/params` and `testutil/sims`. They are now in their respective modules. * (simapp) [#13107](https://github.com/cosmos/cosmos-sdk/pull/13107)Β Call `SetIAVLCacheSize` with the configured value in simapp. - +* [#12398](https://github.com/cosmos/cosmos-sdk/issues/12398) Refactor all `x` modules to unit-test via mocks and decouple `simapp`. ### State Machine Breaking diff --git a/scripts/mockgen.sh b/scripts/mockgen.sh index 7b57d0ce7a0b..afd60457621d 100755 --- a/scripts/mockgen.sh +++ b/scripts/mockgen.sh @@ -26,3 +26,4 @@ $mockgen_cmd -source=x/slashing/types/expected_keepers.go -package testutil -des $mockgen_cmd -source=x/genutil/types/expected_keepers.go -package testutil -destination x/genutil/testutil/expected_keepers_mocks.go $mockgen_cmd -source=x/gov/testutil/expected_keepers.go -package testutil -destination x/gov/testutil/expected_keepers_mocks.go $mockgen_cmd -source=x/staking/types/expected_keepers.go -package testutil -destination x/staking/testutil/expected_keepers_mocks.go +$mockgen_cmd -source=x/auth/vesting/types/expected_keepers.go -package testutil -destination x/auth/vesting/testutil/expected_keepers_mocks.go diff --git a/tests/e2e/auth/vesting/client/testutil/cli_test.go b/tests/e2e/auth/vesting/client/testutil/cli_test.go index 7f3e580db1ec..e98d19c6dda8 100644 --- a/tests/e2e/auth/vesting/client/testutil/cli_test.go +++ b/tests/e2e/auth/vesting/client/testutil/cli_test.go @@ -10,11 +10,10 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/network" - testutil2 "github.com/cosmos/cosmos-sdk/x/auth/vesting/client/testutil" ) func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 1 - suite.Run(t, testutil2.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/auth/vesting/client/testutil/suite.go b/tests/e2e/auth/vesting/client/testutil/suite.go similarity index 100% rename from x/auth/vesting/client/testutil/suite.go rename to tests/e2e/auth/vesting/client/testutil/suite.go diff --git a/x/auth/vesting/msg_server_test.go b/x/auth/vesting/msg_server_test.go new file mode 100644 index 000000000000..574b4120021b --- /dev/null +++ b/x/auth/vesting/msg_server_test.go @@ -0,0 +1,254 @@ +package vesting_test + +import ( + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/suite" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtime "github.com/tendermint/tendermint/types/time" + + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + "github.com/cosmos/cosmos-sdk/testutil" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + vestingtestutil "github.com/cosmos/cosmos-sdk/x/auth/vesting/testutil" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" +) + +var ( + fromAddr = sdk.AccAddress([]byte("from1________________")) + to1Addr = sdk.AccAddress([]byte("to1__________________")) + to2Addr = sdk.AccAddress([]byte("to2__________________")) + to3Addr = sdk.AccAddress([]byte("to3__________________")) + fooCoin = sdk.NewInt64Coin("foo", 100) + periodCoin = sdk.NewInt64Coin("foo", 20) +) + +type VestingTestSuite struct { + suite.Suite + + ctx sdk.Context + accountKeeper authkeeper.AccountKeeper + bankKeeper *vestingtestutil.MockBankKeeper + msgServer vestingtypes.MsgServer +} + +func (s *VestingTestSuite) SetupTest() { + key := sdk.NewKVStoreKey(authtypes.StoreKey) + testCtx := testutil.DefaultContextWithDB(s.T(), key, sdk.NewTransientStoreKey("transient_test")) + s.ctx = testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: tmtime.Now()}) + encCfg := moduletestutil.MakeTestEncodingConfig() + + maccPerms := map[string][]string{} + + ctrl := gomock.NewController(s.T()) + s.bankKeeper = vestingtestutil.NewMockBankKeeper(ctrl) + s.accountKeeper = authkeeper.NewAccountKeeper( + encCfg.Codec, + key, + authtypes.ProtoBaseAccount, + maccPerms, + "cosmos", + authtypes.NewModuleAddress("gov").String(), + ) + + vestingtypes.RegisterInterfaces(encCfg.InterfaceRegistry) + authtypes.RegisterInterfaces(encCfg.InterfaceRegistry) + s.msgServer = vesting.NewMsgServerImpl(s.accountKeeper, s.bankKeeper) +} + +func (s *VestingTestSuite) TestCreateVestingAccount() { + testCases := map[string]struct { + preRun func() + input *vestingtypes.MsgCreateVestingAccount + expErr bool + expErrMsg string + }{ + "create for existing account": { + preRun: func() { + toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.accountKeeper.SetAccount(s.ctx, toAcc) + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(false) + }, + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + time.Now().Unix(), + true, + ), + expErr: true, + expErrMsg: "already exists", + }, + "create a valid delayed vesting account": { + preRun: func() { + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to2Addr).Return(false) + s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to2Addr, sdk.Coins{fooCoin}).Return(nil) + }, + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to2Addr, + sdk.Coins{fooCoin}, + time.Now().Unix(), + true, + ), + expErr: false, + expErrMsg: "", + }, + "create a valid continuous vesting account": { + preRun: func() { + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to3Addr).Return(false) + s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to3Addr, sdk.Coins{fooCoin}).Return(nil) + }, + input: vestingtypes.NewMsgCreateVestingAccount( + fromAddr, + to3Addr, + sdk.Coins{fooCoin}, + time.Now().Unix(), + false, + ), + expErr: false, + expErrMsg: "", + }, + } + + for name, tc := range testCases { + s.Run(name, func() { + tc.preRun() + _, err := s.msgServer.CreateVestingAccount(s.ctx, tc.input) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *VestingTestSuite) TestCreatePermanentLockedAccount() { + testCases := map[string]struct { + preRun func() + input *vestingtypes.MsgCreatePermanentLockedAccount + expErr bool + expErrMsg string + }{ + "create for existing account": { + preRun: func() { + toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to1Addr).Return(false) + s.accountKeeper.SetAccount(s.ctx, toAcc) + }, + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + fromAddr, + to1Addr, + sdk.Coins{fooCoin}, + ), + expErr: true, + expErrMsg: "already exists", + }, + "create a valid permanent locked account": { + preRun: func() { + s.bankKeeper.EXPECT().IsSendEnabledCoins(gomock.Any(), fooCoin).Return(nil) + s.bankKeeper.EXPECT().BlockedAddr(to2Addr).Return(false) + s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to2Addr, sdk.Coins{fooCoin}).Return(nil) + }, + input: vestingtypes.NewMsgCreatePermanentLockedAccount( + fromAddr, + to2Addr, + sdk.Coins{fooCoin}, + ), + expErr: false, + expErrMsg: "", + }, + } + + for name, tc := range testCases { + s.Run(name, func() { + tc.preRun() + _, err := s.msgServer.CreatePermanentLockedAccount(s.ctx, tc.input) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + } + }) + } +} + +func (s *VestingTestSuite) TestCreatePeriodicVestingAccount() { + testCases := map[string]struct { + preRun func() + input *vestingtypes.MsgCreatePeriodicVestingAccount + expErr bool + expErrMsg string + }{ + "create for existing account": { + preRun: func() { + toAcc := s.accountKeeper.NewAccountWithAddress(s.ctx, to1Addr) + s.accountKeeper.SetAccount(s.ctx, toAcc) + }, + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to1Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + }, + ), + expErr: true, + expErrMsg: "already exists", + }, + "create a valid periodic vesting account": { + preRun: func() { + s.bankKeeper.EXPECT().SendCoins(gomock.Any(), fromAddr, to2Addr, gomock.Any()).Return(nil) + }, + input: vestingtypes.NewMsgCreatePeriodicVestingAccount( + fromAddr, + to2Addr, + time.Now().Unix(), + []vestingtypes.Period{ + { + Length: 10, + Amount: sdk.NewCoins(periodCoin), + }, + { + Length: 20, + Amount: sdk.NewCoins(fooCoin), + }, + }, + ), + expErr: false, + expErrMsg: "", + }, + } + + for name, tc := range testCases { + s.Run(name, func() { + tc.preRun() + _, err := s.msgServer.CreatePeriodicVestingAccount(s.ctx, tc.input) + if tc.expErr { + s.Require().Error(err) + s.Require().Contains(err.Error(), tc.expErrMsg) + } else { + s.Require().NoError(err) + } + }) + } +} + +func TestVestingTestSuite(t *testing.T) { + suite.Run(t, new(VestingTestSuite)) +} diff --git a/x/auth/vesting/testutil/expected_keepers_mocks.go b/x/auth/vesting/testutil/expected_keepers_mocks.go new file mode 100644 index 000000000000..fd1fe6140d9c --- /dev/null +++ b/x/auth/vesting/testutil/expected_keepers_mocks.go @@ -0,0 +1,82 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: x/auth/vesting/types/expected_keepers.go + +// Package testutil is a generated GoMock package. +package testutil + +import ( + reflect "reflect" + + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" +) + +// MockBankKeeper is a mock of BankKeeper interface. +type MockBankKeeper struct { + ctrl *gomock.Controller + recorder *MockBankKeeperMockRecorder +} + +// MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. +type MockBankKeeperMockRecorder struct { + mock *MockBankKeeper +} + +// NewMockBankKeeper creates a new mock instance. +func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper { + mock := &MockBankKeeper{ctrl: ctrl} + mock.recorder = &MockBankKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { + return m.recorder +} + +// BlockedAddr mocks base method. +func (m *MockBankKeeper) BlockedAddr(addr types.AccAddress) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockedAddr", addr) + ret0, _ := ret[0].(bool) + return ret0 +} + +// BlockedAddr indicates an expected call of BlockedAddr. +func (mr *MockBankKeeperMockRecorder) BlockedAddr(addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedAddr", reflect.TypeOf((*MockBankKeeper)(nil).BlockedAddr), addr) +} + +// IsSendEnabledCoins mocks base method. +func (m *MockBankKeeper) IsSendEnabledCoins(ctx types.Context, coins ...types.Coin) error { + m.ctrl.T.Helper() + varargs := []interface{}{ctx} + for _, a := range coins { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "IsSendEnabledCoins", varargs...) + ret0, _ := ret[0].(error) + return ret0 +} + +// IsSendEnabledCoins indicates an expected call of IsSendEnabledCoins. +func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoins(ctx interface{}, coins ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{ctx}, coins...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoins", reflect.TypeOf((*MockBankKeeper)(nil).IsSendEnabledCoins), varargs...) +} + +// SendCoins mocks base method. +func (m *MockBankKeeper) SendCoins(ctx types.Context, fromAddr, toAddr types.AccAddress, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoins", ctx, fromAddr, toAddr, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoins indicates an expected call of SendCoins. +func (mr *MockBankKeeperMockRecorder) SendCoins(ctx, fromAddr, toAddr, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoins", reflect.TypeOf((*MockBankKeeper)(nil).SendCoins), ctx, fromAddr, toAddr, amt) +} diff --git a/x/staking/module_test.go b/x/staking/module_test.go index f5f9014c3bfc..2ff9a3d472a1 100644 --- a/x/staking/module_test.go +++ b/x/staking/module_test.go @@ -20,7 +20,6 @@ func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { ctx := app.BaseApp.NewContext(false, tmproto.Header{}) acc := accountKeeper.GetAccount(ctx, authtypes.NewModuleAddress(types.BondedPoolName)) - require.NotNil(t, acc) acc = accountKeeper.GetAccount(ctx, authtypes.NewModuleAddress(types.NotBondedPoolName)) From 26326bbf55c9df5e1f8eb1b8b8c5ad79d153349f Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Fri, 2 Sep 2022 11:48:02 +0530 Subject: [PATCH 07/24] use require instead of assert in cli test (#13132) --- x/crisis/client/cli/tx_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/x/crisis/client/cli/tx_test.go b/x/crisis/client/cli/tx_test.go index 65cb24f226c6..ddfa0a2010e8 100644 --- a/x/crisis/client/cli/tx_test.go +++ b/x/crisis/client/cli/tx_test.go @@ -6,7 +6,7 @@ import ( "io" "testing" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" coretypes "github.com/tendermint/tendermint/rpc/core/types" @@ -97,19 +97,19 @@ func TestNewMsgVerifyInvariantTxCmd(t *testing.T) { cmd := cli.NewMsgVerifyInvariantTxCmd() cmd.SetOut(io.Discard) - assert.NotNil(t, cmd) + require.NotNil(t, cmd) cmd.SetContext(ctx) cmd.SetArgs(tc.args) - assert.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) + require.NoError(t, client.SetCmdClientContextHandler(baseCtx, cmd)) err := cmd.Execute() if tc.expectErr { - assert.Error(t, err) - assert.Contains(t, err.Error(), tc.errString) + require.Error(t, err) + require.Contains(t, err.Error(), tc.errString) } else { - assert.NoError(t, err) + require.NoError(t, err) } }) } From 6d6b804a7334a8e3cb475d961e864f633b55aaa7 Mon Sep 17 00:00:00 2001 From: Sam Hart Date: Fri, 2 Sep 2022 11:04:08 +0200 Subject: [PATCH 08/24] docs: adds gov groups metadata spec (#13118) --- x/gov/spec/08_metadata.md | 30 +++++++++++++++++++++ x/gov/spec/README.md | 3 +++ x/group/spec/06_metadata.md | 52 +++++++++++++++++++++++++++++++++++++ x/group/spec/README.md | 5 ++++ 4 files changed, 90 insertions(+) create mode 100644 x/gov/spec/08_metadata.md create mode 100644 x/group/spec/06_metadata.md diff --git a/x/gov/spec/08_metadata.md b/x/gov/spec/08_metadata.md new file mode 100644 index 000000000000..fcd161c76c6c --- /dev/null +++ b/x/gov/spec/08_metadata.md @@ -0,0 +1,30 @@ + + +# Metadata + +The gov module has two locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the gov and group modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. + +## Proposal +Location: off-chain as json object stored on IPFS (mirrors [group proposal](../../group/spec/06_metadata.md#proposal)) + +```json +{ + "title": "", + "authors": "", + "summary": "", + "details": "", + "proposalForumURL": "", + "voteOptionContext": "", +} +``` + +## Vote +Location: on-chain as json within 255 character limit (mirrors [group vote](../../group/spec/06_metadata.md#vote)) + +```json +{ + "justification": "", +} +``` \ No newline at end of file diff --git a/x/gov/spec/README.md b/x/gov/spec/README.md index f0e1af55fb05..3a5a2decf758 100644 --- a/x/gov/spec/README.md +++ b/x/gov/spec/README.md @@ -60,3 +60,6 @@ staking token of the chain. * [CLI](07_client.md#cli) * [gRPC](07_client.md#grpc) * [REST](07_client.md#rest) +8. **[Metadata](08_metadata.md)** + * [Proposal](08_metadata.md#proposal) + * [Vote](08_metadata.md#vote) diff --git a/x/group/spec/06_metadata.md b/x/group/spec/06_metadata.md new file mode 100644 index 000000000000..27108673557e --- /dev/null +++ b/x/group/spec/06_metadata.md @@ -0,0 +1,52 @@ + + +# Metadata + +The group module has four locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the group and gov modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. + +## Proposal +Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../../gov/spec/08_metadata.md#proposal)) + +```json +{ + "title": "", + "authors": "", + "summary": "", + "details": "", + "proposalForumURL": "", + "voteOptionContext": "", +} +``` + +## Vote +Location: on-chain as json within 255 character limit (mirrors [gov vote](../../gov/spec/08_metadata.md#vote)) + +```json +{ + "justification": "", +} +``` + +## Group +Location: off-chain as json object stored on IPFS + +```json +{ + "name": "", + "description": "", + "groupWebsiteURL": "", + "groupForumURL": "", +} +``` + +## Decision policy +Location: on-chain as json within 255 character limit + +```json +{ + "name": "", + "description": "", +} +``` \ No newline at end of file diff --git a/x/group/spec/README.md b/x/group/spec/README.md index a97a12fe724c..362a56e7016c 100644 --- a/x/group/spec/README.md +++ b/x/group/spec/README.md @@ -56,3 +56,8 @@ This module allows the creation and management of on-chain multisig accounts and * [CLI](05_client.md#cli) * [gRPC](05_client.md#grpc) * [REST](05_client.md#rest) +6. **[Metadata](06_metadata.md)** + * [Proposal](06_metadata.md#proposal) + * [Vote](06_metadata.md#vote) + * [Group](06_metadata.md#group) + * [Decision policy](06_metadata.md#decision%20policy) \ No newline at end of file From f5f84ad12af360a91a45ea9ddb2072f5ab9c2c16 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 2 Sep 2022 13:53:24 +0200 Subject: [PATCH 09/24] chore: replace deprecated dgrijalva/jwt-go dep (#13093) * chore: replace deprecated dgrijalva/jwt-go dep * Update go.mod --- go.mod | 3 +++ go.sum | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a6e00ade6c9c..2c437b0c1878 100644 --- a/go.mod +++ b/go.mod @@ -292,6 +292,9 @@ require ( replace ( github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 + // dgrijalva/jwt-go is deprecated and doesn't receive security updates. + // TODO: remove it: https://github.com/cosmos/cosmos-sdk/issues/13134 + github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2 // Fix upstream GHSA-h395-qcrw-5vmq vulnerability. // TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409 github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.8.1 diff --git a/go.sum b/go.sum index 491b51ec6ac6..7bd03da8ceef 100644 --- a/go.sum +++ b/go.sum @@ -274,7 +274,6 @@ github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI= github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -400,6 +399,7 @@ github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZg github.com/gogo/gateway v1.1.0 h1:u0SuhL9+Il+UbjM9VIE3ntfRujKbvVpFvNB4HbjeVQ0= github.com/gogo/gateway v1.1.0/go.mod h1:S7rR8FRQyG3QFESeSv4l2WnsyzlCLG0CzBbUUo/mbic= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= From 7a3ff0dd4a99bddb27d031e425ffdba7560a11c3 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 2 Sep 2022 16:09:15 +0200 Subject: [PATCH 10/24] docs: update contributing (#13137) Co-authored-by: Marko --- CONTRIBUTING.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0c8ee1eb7d07..9eb3b634aaa6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,7 @@ discussion or proposing code changes. To ensure a smooth workflow for all contributors, the general procedure for contributing has been established: 1. Start by browsing [new issues](https://github.com/cosmos/cosmos-sdk/issues) and [discussions](https://github.com/cosmos/cosmos-sdk/discussions). If you are looking for something interesting or if you have something in your mind, there is a chance it had been discussed. - * Looking for a good place to start contributing? How about checking out some [good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)? + * Looking for a good place to start contributing? How about checking out some [good first issues](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) or [bugs](https://github.com/cosmos/cosmos-sdk/issues?q=is%3Aopen+is%3Aissue+label%3A%22T%3A+Bug%22)? 2. Determine whether a GitHub issue or discussion is more appropriate for your needs: 1. If want to propose something new that requires specification or an additional design, or you would like to change a process, start with a [new discussion](https://github.com/cosmos/cosmos-sdk/discussions/new). With discussions, we can better handle the design process using discussion threads. A discussion usually leads to one or more issues. 2. If the issue you want addressed is a specific proposal or a bug, then open a [new issue](https://github.com/cosmos/cosmos-sdk/issues/new/choose). @@ -53,20 +53,18 @@ taken place in a GitHub issue, that PR runs a high likelihood of being rejected. ## Teams Dev Calls -The Cosmos SDK has many stakeholders contributing and shaping the project. Regen Network Development leads the Cosmos SDK R&D, and welcomes long-term contributors and additional maintainers from other projects. We use self-organizing principles to coordinate and collaborate across organizations in structured "Working Groups" that focus on specific problem domains or architectural components of the Cosmos SDK. +The Cosmos SDK has many stakeholders contributing and shaping the project. The Core SDK team is composed of Interchain GmbH and Regen Network Development developers. Any long-term contributors and additional maintainers from other projects are welcome. We use self-organizing principles to coordinate and collaborate across organizations in structured "EPIC" that focus on specific problem domains or architectural components of the Cosmos SDK. -The developers are organized in working groups which are listed on a ["Working Groups & Arch Process" Github Issue](https://github.com/cosmos/cosmos-sdk/issues/9058) (pinned at the top of the [issues list](https://github.com/cosmos/cosmos-sdk/issues)). +The developers work in sprints, which are available in a [GitHub Project](https://github.com/orgs/cosmos/projects/26/views/22). The current EPICs are pinned at the top of the [issues list](https://github.com/cosmos/cosmos-sdk/issues). -The important development announcements are shared on [Discord](https://discord.com/invite/cosmosnetwork) in the \#dev-announcements channel. +The important development announcements are shared on [Discord](https://discord.com/invite/cosmosnetwork) in the `#dev-announcements` channel. To synchronize we have few major meetings: -* Architecture calls: bi-weekly on Fridays at 14:00 UTC (alternating with the grooming meeting below). -* Grooming / Planning: bi-weekly on Fridays at 14:00 UTC (alternating with the architecture meeting above). -* Cosmos Community SDK Development Call on the last Wednesday of every month at 17:00 UTC. -* Cosmos Roadmap Prioritization every 4 weeks on Tuesday at 15:00 UTC (limited participation). +* Cosmos SDK Sprint Review on Monday and Thursday at 14:00 UTC (limited participation to core devs). +* Cosmos SDK Community Call on Thursday at 16:00 UTC. -If you would like to join one of those calls, then please contact us on [Discord](https://discord.com/invite/cosmosnetwork) or reach out directly to Marko (@marbar3778). +If you would like to join one of the community call, then please contact us on [Discord](https://discord.com/invite/cosmosnetwork) or reach out directly to Marko (@marbar3778). ## Architecture Decision Records (ADR) @@ -161,7 +159,7 @@ If you open a PR on the Cosmos SDK, it is mandatory to update the relevant docum * If your change relates to the core SDK (baseapp, store, ...), be sure to update the content in `docs/basics/`, `docs/core/` and/or `docs/building-modules/` folders. * If your changes relate to the core of the CLI (not specifically to module's CLI/Rest), then modify the content in the `docs/run-node/` folder. -* If your changes relate to a module, then be sure to update the module's spec in `x/moduleName/docs/spec/`. +* If your changes relate to a module, then be sure to update the module's spec in `x/{moduleName}/docs/spec/`. When writing documentation, follow the [Documentation Writing Guidelines](./docs/DOC_WRITING_GUIDELINES.md). @@ -207,7 +205,6 @@ For example, in vscode your `.vscode/settings.json` should look like: "protoc": { "options": [ "--proto_path=${workspaceRoot}/proto", - "--proto_path=${workspaceRoot}/third_party/proto" ] } } @@ -287,8 +284,7 @@ is broken up into three distinct stages: **Strategy Discovery**, **Concept Appro #### Time Bound Period -* Once a PR for an ADR is opened, reviewers are expected to perform a first - review within 1 week of pull request being open +* Once a PR for an ADR is opened, reviewers are expected to perform a first review within 1 week of pull request being open * Time bound period for individual ADR Pull Requests to be merged should not exceed 2 weeks * Total time bound period for an ADR to reach a decision (`ABANDONED | ACCEPTED | REJECTED`) should not exceed 4 weeks From 6a4d2a16a54c10956907969421799eb944bec8f7 Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Fri, 2 Sep 2022 21:47:11 +0530 Subject: [PATCH 11/24] refactor(evidence): CLI tests using Tendermint Mock (#13056) * wip * fix something * remove test case from tx test * fix test * add build tags to cli test * use require instead of assert * add cli tests --- .../{client/testutil => }/cli_test.go | 5 +- .../testutil => tests/e2e/evidence}/suite.go | 2 +- x/evidence/client/cli/tx_test.go | 132 ++++++++++++++++++ 3 files changed, 135 insertions(+), 4 deletions(-) rename tests/e2e/evidence/{client/testutil => }/cli_test.go (67%) rename {x/evidence/client/testutil => tests/e2e/evidence}/suite.go (99%) create mode 100644 x/evidence/client/cli/tx_test.go diff --git a/tests/e2e/evidence/client/testutil/cli_test.go b/tests/e2e/evidence/cli_test.go similarity index 67% rename from tests/e2e/evidence/client/testutil/cli_test.go rename to tests/e2e/evidence/cli_test.go index d5ea5fa80de6..8c9053421203 100644 --- a/tests/e2e/evidence/client/testutil/cli_test.go +++ b/tests/e2e/evidence/cli_test.go @@ -1,7 +1,7 @@ //go:build e2e // +build e2e -package testutil +package evidence import ( "testing" @@ -10,11 +10,10 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/network" - clienttestutil "github.com/cosmos/cosmos-sdk/x/evidence/client/testutil" ) func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 1 - suite.Run(t, clienttestutil.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/evidence/client/testutil/suite.go b/tests/e2e/evidence/suite.go similarity index 99% rename from x/evidence/client/testutil/suite.go rename to tests/e2e/evidence/suite.go index 32eae04fd5d1..7e683a577ade 100644 --- a/x/evidence/client/testutil/suite.go +++ b/tests/e2e/evidence/suite.go @@ -1,4 +1,4 @@ -package testutil +package evidence import ( "strings" diff --git a/x/evidence/client/cli/tx_test.go b/x/evidence/client/cli/tx_test.go new file mode 100644 index 000000000000..629f12ef3a28 --- /dev/null +++ b/x/evidence/client/cli/tx_test.go @@ -0,0 +1,132 @@ +package cli_test + +import ( + "bytes" + "context" + "fmt" + "io" + "strings" + "testing" + + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" + coretypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/evidence" + "github.com/cosmos/cosmos-sdk/x/evidence/client/cli" +) + +var _ client.TendermintRPC = (*mockTendermintRPC)(nil) + +type mockTendermintRPC struct { + rpcclientmock.Client + + responseQuery abci.ResponseQuery +} + +func newMockTendermintRPC(respQuery abci.ResponseQuery) mockTendermintRPC { + return mockTendermintRPC{responseQuery: respQuery} +} + +func (_ mockTendermintRPC) BroadcastTxCommit(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + return &coretypes.ResultBroadcastTxCommit{}, nil +} + +func (m mockTendermintRPC) ABCIQueryWithOptions( + _ context.Context, + _ string, _ tmbytes.HexBytes, + _ rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil +} + +func TestGetQueryCmd(t *testing.T) { + cmd := cli.GetQueryCmd() + cmd.SetOut(io.Discard) + require.NotNil(t, cmd) + + encCfg := testutilmod.MakeTestEncodingConfig(evidence.AppModuleBasic{}) + kr := keyring.NewInMemory(encCfg.Codec) + baseCtx := client.Context{}. + WithKeyring(kr). + WithTxConfig(encCfg.TxConfig). + WithCodec(encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + testCases := map[string]struct { + args []string + ctxGen func() client.Context + expCmdOutput string + expectedOutput string + expectErr bool + }{ + "non-existent evidence": { + []string{"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}, + func() client.Context { + bz, _ := encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return baseCtx.WithClient(c) + }, + "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660", + "", + true, + }, + "all evidence (default pagination)": { + []string{}, + func() client.Context { + bz, _ := encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return baseCtx.WithClient(c) + }, + "", + "evidence: []\npagination: null", + false, + }, + } + + for name, tc := range testCases { + tc := tc + + t.Run(name, func(t *testing.T) { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + require.NoError(t, client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + require.Contains(t, fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := clitestutil.ExecTestCLICmd(baseCtx, cmd, tc.args) + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + require.Contains(t, fmt.Sprint(cmd), "evidence [] [] Query for evidence by hash or for all (paginated) submitted evidence") + require.Contains(t, strings.TrimSpace(out.String()), tc.expectedOutput) + }) + } +} From ccdc355eea4eecac72395b7660b757ca45d394f1 Mon Sep 17 00:00:00 2001 From: Marko Date: Fri, 2 Sep 2022 21:52:35 +0200 Subject: [PATCH 12/24] chore: remove query router (#13142) --- baseapp/abci.go | 40 ------------------------------------ baseapp/baseapp.go | 5 ----- baseapp/queryrouter.go | 41 ------------------------------------- baseapp/queryrouter_test.go | 33 ----------------------------- 4 files changed, 119 deletions(-) delete mode 100644 baseapp/queryrouter.go delete mode 100644 baseapp/queryrouter_test.go diff --git a/baseapp/abci.go b/baseapp/abci.go index 6c6bd2f81ea3..924a9f8191be 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -420,9 +420,6 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) { case QueryPathP2P: return handleQueryP2P(app, path) - - case QueryPathCustom: - return handleQueryCustom(app, path, req) } return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"), app.trace) @@ -816,43 +813,6 @@ func handleQueryP2P(app *BaseApp, path []string) abci.ResponseQuery { return resp } -func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery { - // path[0] should be "custom" because "/custom" prefix is required for keeper - // queries. - // - // The QueryRouter routes using path[1]. For example, in the path - // "custom/gov/proposal", QueryRouter routes using "gov". - if len(path) < 2 || path[1] == "" { - return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified"), app.trace) - } - - querier := app.queryRouter.Route(path[1]) - if querier == nil { - return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1]), app.trace) - } - - ctx, err := app.createQueryContext(req.Height, req.Prove) - if err != nil { - return sdkerrors.QueryResult(err, app.trace) - } - - // Passes the rest of the path as an argument to the querier. - // - // For example, in the path "custom/gov/proposal/test", the gov querier gets - // []string{"proposal", "test"} as the path. - resBytes, err := querier(ctx, path[2:], req) - if err != nil { - res := sdkerrors.QueryResult(err, app.trace) - res.Height = req.Height - return res - } - - return abci.ResponseQuery{ - Height: req.Height, - Value: resBytes, - } -} - // SplitABCIQueryPath splits a string path using the delimiter '/'. // // e.g. "this/is/funny" becomes []string{"this", "is", "funny"} diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index e199a67c2fbb..cab7aa27e5d9 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -48,7 +48,6 @@ type BaseApp struct { //nolint: maligned db dbm.DB // common DB backend cms sdk.CommitMultiStore // Main (uncached) state storeLoader StoreLoader // function to handle store loading, may be overridden with SetStoreLoader() - queryRouter sdk.QueryRouter // router for redirecting query calls grpcQueryRouter *GRPCQueryRouter // router for redirecting gRPC query calls msgServiceRouter *MsgServiceRouter // router for redirecting Msg service messages interfaceRegistry codectypes.InterfaceRegistry @@ -147,7 +146,6 @@ func NewBaseApp( db: db, cms: store.NewCommitMultiStore(db), storeLoader: DefaultStoreLoader, - queryRouter: NewQueryRouter(), grpcQueryRouter: NewGRPCQueryRouter(), msgServiceRouter: NewMsgServiceRouter(), txDecoder: txDecoder, @@ -364,9 +362,6 @@ func (app *BaseApp) setIndexEvents(ie []string) { } } -// QueryRouter returns the QueryRouter of a BaseApp. -func (app *BaseApp) QueryRouter() sdk.QueryRouter { return app.queryRouter } - // Seal seals a BaseApp. It prohibits any further modifications to a BaseApp. func (app *BaseApp) Seal() { app.sealed = true } diff --git a/baseapp/queryrouter.go b/baseapp/queryrouter.go deleted file mode 100644 index 1727b2ab2df6..000000000000 --- a/baseapp/queryrouter.go +++ /dev/null @@ -1,41 +0,0 @@ -package baseapp - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type QueryRouter struct { - routes map[string]sdk.Querier -} - -var _ sdk.QueryRouter = NewQueryRouter() - -// NewQueryRouter returns a reference to a new QueryRouter. -func NewQueryRouter() *QueryRouter { - return &QueryRouter{ - routes: map[string]sdk.Querier{}, - } -} - -// AddRoute adds a query path to the router with a given Querier. It will panic -// if a duplicate route is given. The route must be alphanumeric. -func (qrt *QueryRouter) AddRoute(path string, q sdk.Querier) sdk.QueryRouter { - if !sdk.IsAlphaNumeric(path) { - panic("route expressions can only contain alphanumeric characters") - } - - if qrt.routes[path] != nil { - panic(fmt.Sprintf("route %s has already been initialized", path)) - } - - qrt.routes[path] = q - - return qrt -} - -// Route returns the Querier for a given query route path. -func (qrt *QueryRouter) Route(path string) sdk.Querier { - return qrt.routes[path] -} diff --git a/baseapp/queryrouter_test.go b/baseapp/queryrouter_test.go deleted file mode 100644 index c7637f17000e..000000000000 --- a/baseapp/queryrouter_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package baseapp - -import ( - "testing" - - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var testQuerier = func(_ sdk.Context, _ []string, _ abci.RequestQuery) ([]byte, error) { - return nil, nil -} - -func TestQueryRouter(t *testing.T) { - qr := NewQueryRouter() - - // require panic on invalid route - require.Panics(t, func() { - qr.AddRoute("*", testQuerier) - }) - - qr.AddRoute("testRoute", testQuerier) - q := qr.Route("testRoute") - require.NotNil(t, q) - - // require panic on duplicate route - require.Panics(t, func() { - qr.AddRoute("testRoute", testQuerier) - }) -} From 3ffa1d19df7e8ba2307f4cdeb4af25ae89bf4186 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Fri, 2 Sep 2022 18:17:08 -0400 Subject: [PATCH 13/24] feat(depinject): allow module keys to manually be created for codegen/manual wiring (#13124) --- depinject/config.go | 4 ++-- depinject/container.go | 13 ++---------- depinject/module_key.go | 39 ++++++++++++++++++++++++++++++++++++ depinject/module_key_test.go | 25 +++++++++++++++++++++++ 4 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 depinject/module_key_test.go diff --git a/depinject/config.go b/depinject/config.go index ff947bc627bd..f43a4bac1633 100644 --- a/depinject/config.go +++ b/depinject/config.go @@ -36,7 +36,7 @@ func ProvideInModule(moduleName string, providers ...interface{}) Config { return errors.Errorf("expected non-empty module name") } - return provide(ctr, ctr.createOrGetModuleKey(moduleName), providers) + return provide(ctr, ctr.moduleKeyContext.createOrGetModuleKey(moduleName), providers) }) } @@ -83,7 +83,7 @@ func InvokeInModule(moduleName string, invokers ...interface{}) Config { return errors.Errorf("expected non-empty module name") } - return invoke(ctr, ctr.createOrGetModuleKey(moduleName), invokers) + return invoke(ctr, ctr.moduleKeyContext.createOrGetModuleKey(moduleName), invokers) }) } diff --git a/depinject/container.go b/depinject/container.go index d2998f585828..148a8c28ccdd 100644 --- a/depinject/container.go +++ b/depinject/container.go @@ -17,7 +17,7 @@ type container struct { interfaceBindings map[string]interfaceBinding invokers []invoker - moduleKeys map[string]*moduleKey + moduleKeyContext *ModuleKeyContext resolveStack []resolveFrame callerStack []Location @@ -48,7 +48,7 @@ func newContainer(cfg *debugConfig) *container { return &container{ debugConfig: cfg, resolvers: map[string]resolver{}, - moduleKeys: map[string]*moduleKey{}, + moduleKeyContext: &ModuleKeyContext{}, interfaceBindings: map[string]interfaceBinding{}, callerStack: nil, callerMap: map[Location]bool{}, @@ -498,15 +498,6 @@ func (c *container) build(loc Location, outputs ...interface{}) error { return nil } -func (c container) createOrGetModuleKey(name string) *moduleKey { - if s, ok := c.moduleKeys[name]; ok { - return s - } - s := &moduleKey{name} - c.moduleKeys[name] = s - return s -} - func (c container) formatResolveStack() string { buf := &bytes.Buffer{} _, _ = fmt.Fprintf(buf, "\twhile resolving:\n") diff --git a/depinject/module_key.go b/depinject/module_key.go index ff8902a44202..8fba64f9436a 100644 --- a/depinject/module_key.go +++ b/depinject/module_key.go @@ -25,10 +25,18 @@ type moduleKey struct { name string } +// Name returns the module key's name. func (k ModuleKey) Name() string { return k.name } +// Equals checks if the module key is equal to another module key. Module keys +// will be equal only if they have the same name and come from the same +// ModuleKeyContext. +func (k ModuleKey) Equals(other ModuleKey) bool { + return k.moduleKey == other.moduleKey +} + var moduleKeyType = reflect.TypeOf(ModuleKey{}) // OwnModuleKey is a type which can be used in a module to retrieve its own @@ -36,3 +44,34 @@ var moduleKeyType = reflect.TypeOf(ModuleKey{}) type OwnModuleKey ModuleKey var ownModuleKeyType = reflect.TypeOf((*OwnModuleKey)(nil)).Elem() + +// ModuleKeyContext defines a context for non-forgeable module keys. +// All module keys with the same name from the same context should be equal +// and module keys with the same name but from different contexts should be +// not equal. +// +// Usage: +// moduleKeyCtx := &ModuleKeyContext{} +// fooKey := moduleKeyCtx.For("foo") +type ModuleKeyContext struct { + moduleKeys map[string]*moduleKey +} + +// For returns a new or existing module key for the given name within the context. +func (c *ModuleKeyContext) For(moduleName string) ModuleKey { + return ModuleKey{c.createOrGetModuleKey(moduleName)} +} + +func (c *ModuleKeyContext) createOrGetModuleKey(moduleName string) *moduleKey { + if c.moduleKeys == nil { + c.moduleKeys = map[string]*moduleKey{} + } + + if k, ok := c.moduleKeys[moduleName]; ok { + return k + } + + k := &moduleKey{moduleName} + c.moduleKeys[moduleName] = k + return k +} diff --git a/depinject/module_key_test.go b/depinject/module_key_test.go new file mode 100644 index 000000000000..5a226c0e363e --- /dev/null +++ b/depinject/module_key_test.go @@ -0,0 +1,25 @@ +package depinject + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestModuleKeyEquals(t *testing.T) { + ctx := &ModuleKeyContext{} + + fooKey := ctx.For("foo") + fooKey2 := ctx.For("foo") + // two foo keys from the same context should be equal + assert.Assert(t, fooKey.Equals(fooKey2)) + + barKey := ctx.For("bar") + // foo and bar keys should be not equal + assert.Assert(t, !fooKey.Equals(barKey)) + + ctx2 := &ModuleKeyContext{} + fooKeyFromAnotherCtx := ctx2.For("foo") + // foo keys from different context should be not equal + assert.Assert(t, !fooKey.Equals(fooKeyFromAnotherCtx)) +} From e09516f4795c637ab12b30bf732ce5d86da78424 Mon Sep 17 00:00:00 2001 From: Marko Date: Mon, 5 Sep 2022 09:39:12 +0200 Subject: [PATCH 14/24] chore: bump tendermint version (#13148) --- Makefile | 6 ++-- baseapp/abci.go | 18 +++++++---- baseapp/abci_test.go | 2 +- baseapp/baseapp.go | 8 ++--- baseapp/baseapp_test.go | 8 ++--- baseapp/deliver_tx_test.go | 12 ++++---- baseapp/params.go | 3 +- baseapp/params_test.go | 11 +++---- codec/proto_codec.go | 2 +- crypto/keys/secp256k1/secp256k1.go | 2 +- go.mod | 9 +++--- go.sum | 22 +++++--------- server/export.go | 14 ++++----- server/rosetta/converter.go | 10 +++--- server/types/app.go | 3 +- store/streaming/file/service_test.go | 16 +++++----- tests/e2e/server/export_test.go | 3 +- tests/integration/bank/keeper/keeper_test.go | 18 +++++------ testutil/sims/app_helpers.go | 4 +-- types/context.go | 8 ++--- types/context_test.go | 2 +- types/events.go | 21 +++---------- types/events_test.go | 32 ++++++++++---------- types/result_test.go | 12 ++++---- x/authz/keeper/keeper.go | 8 ++--- x/bank/keeper/keeper_test.go | 18 +++++------ x/evidence/abci.go | 2 +- x/evidence/types/evidence.go | 2 +- x/evidence/types/evidence_test.go | 4 +-- x/params/types/consensus_params.go | 3 +- x/simulation/mock_tendermint.go | 10 +++--- x/simulation/params.go | 7 ++--- x/slashing/abci_test.go | 6 ++-- x/upgrade/abci.go | 2 +- 34 files changed, 145 insertions(+), 163 deletions(-) diff --git a/Makefile b/Makefile index a0613927c85e..c6a605247b5d 100644 --- a/Makefile +++ b/Makefile @@ -427,7 +427,7 @@ proto-check-breaking: @$(DOCKER_BUF) breaking --against $(HTTPS_GIT)#branch=main -TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.34.21/proto/tendermint +TM_URL = https://raw.githubusercontent.com/tendermint/tendermint/v0.37.0-alpha.1/proto/tendermint GOGO_PROTO_URL = https://raw.githubusercontent.com/regen-network/protobuf/v1.3.3-alpha.regen.1 COSMOS_PROTO_URL = https://raw.githubusercontent.com/regen-network/cosmos-proto/v0.3.1 CONFIO_URL = https://raw.githubusercontent.com/confio/ics23/go/v0.7.0 @@ -477,8 +477,8 @@ proto-update-deps: @mkdir -p $(TM_P2P) @curl -sSL $(TM_URL)/p2p/types.proto > $(TM_P2P)/types.proto - @mkdir -p $(CONFIO_TYPES) - @curl -sSL $(CONFIO_URL)/proofs.proto > $(CONFIO_TYPES)/proofs.proto + + ## insert go package option into proofs.proto file ## Issue link: https://github.com/confio/ics23/issues/32 @sed -i '4ioption go_package = "github.com/confio/ics23/go";' $(CONFIO_TYPES)/proofs.proto diff --git a/baseapp/abci.go b/baseapp/abci.go index 924a9f8191be..b59c63dbee14 100644 --- a/baseapp/abci.go +++ b/baseapp/abci.go @@ -111,12 +111,6 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC } } -// SetOption implements the ABCI interface. -func (app *BaseApp) SetOption(req abci.RequestSetOption) (res abci.ResponseSetOption) { - // TODO: Implement! - return -} - // Info implements the ABCI interface. func (app *BaseApp) Info(req abci.RequestInfo) abci.ResponseInfo { lastCommitID := app.cms.LastCommitID() @@ -238,6 +232,18 @@ func (app *BaseApp) EndBlock(req abci.RequestEndBlock) (res abci.ResponseEndBloc return res } +// ProcessProposal implements the ability for the application to verify and/or modify transactions in a block proposal. +func (app *BaseApp) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal { + // treated as a noop until app side mempool is implemented + return abci.ResponsePrepareProposal{Txs: req.Txs} +} + +// ProcessProposal implements the ability for the application to verify transactions in a block proposal, and decide if they should accept the block or not. +func (app *BaseApp) ProcessProposal(req abci.RequestProcessProposal) abci.ResponseProcessProposal { + // accept all proposed blocks until app side mempool is implemented + return abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_ACCEPT} +} + // CheckTx implements the ABCI interface and executes a tx in CheckTx mode. In // CheckTx mode, messages are not executed. This means messages are only validated // and only the AnteHandler is executed. State is persisted to the BaseApp's diff --git a/baseapp/abci_test.go b/baseapp/abci_test.go index fd383128c7d5..7ff313c41a07 100644 --- a/baseapp/abci_test.go +++ b/baseapp/abci_test.go @@ -118,7 +118,7 @@ func TestGetBlockRentionHeight(t *testing.T) { tc.bapp.SetParamStore(¶mStore{db: dbm.NewMemDB()}) tc.bapp.InitChain(abci.RequestInitChain{ - ConsensusParams: &abci.ConsensusParams{ + ConsensusParams: &tmproto.ConsensusParams{ Evidence: &tmproto.EvidenceParams{ MaxAgeNumBlocks: tc.maxAgeBlocks, }, diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index cab7aa27e5d9..dbe20e20ddfc 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -394,15 +394,15 @@ func (app *BaseApp) setDeliverState(header tmproto.Header) { // GetConsensusParams returns the current consensus parameters from the BaseApp's // ParamStore. If the BaseApp has no ParamStore defined, nil is returned. -func (app *BaseApp) GetConsensusParams(ctx sdk.Context) *abci.ConsensusParams { +func (app *BaseApp) GetConsensusParams(ctx sdk.Context) *tmproto.ConsensusParams { if app.paramStore == nil { return nil } - cp := new(abci.ConsensusParams) + cp := new(tmproto.ConsensusParams) if app.paramStore.Has(ctx, ParamStoreKeyBlockParams) { - var bp abci.BlockParams + var bp tmproto.BlockParams app.paramStore.Get(ctx, ParamStoreKeyBlockParams, &bp) cp.Block = &bp @@ -433,7 +433,7 @@ func (app *BaseApp) AddRunTxRecoveryHandler(handlers ...RecoveryHandler) { } // StoreConsensusParams sets the consensus parameters to the baseapp's param store. -func (app *BaseApp) StoreConsensusParams(ctx sdk.Context, cp *abci.ConsensusParams) { +func (app *BaseApp) StoreConsensusParams(ctx sdk.Context, cp *tmproto.ConsensusParams) { if app.paramStore == nil { panic("cannot store consensus params with no params store set") } diff --git a/baseapp/baseapp_test.go b/baseapp/baseapp_test.go index e60394d5e2df..697841e1a81d 100644 --- a/baseapp/baseapp_test.go +++ b/baseapp/baseapp_test.go @@ -30,16 +30,16 @@ func TestGetMaximumBlockGas(t *testing.T) { app.InitChain(abci.RequestInitChain{}) ctx := app.NewContext(true, tmproto.Header{}) - app.StoreConsensusParams(ctx, &abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 0}}) + app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 0}}) require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -1}}) + app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -1}}) require.Equal(t, uint64(0), app.getMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: 5000000}}) + app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: 5000000}}) require.Equal(t, uint64(5000000), app.getMaximumBlockGas(ctx)) - app.StoreConsensusParams(ctx, &abci.ConsensusParams{Block: &abci.BlockParams{MaxGas: -5000000}}) + app.StoreConsensusParams(ctx, &tmproto.ConsensusParams{Block: &tmproto.BlockParams{MaxGas: -5000000}}) require.Panics(t, func() { app.getMaximumBlockGas(ctx) }) } diff --git a/baseapp/deliver_tx_test.go b/baseapp/deliver_tx_test.go index 601a5b642a57..8cac0b94c403 100644 --- a/baseapp/deliver_tx_test.go +++ b/baseapp/deliver_tx_test.go @@ -959,8 +959,8 @@ func TestBaseApp_EndBlock(t *testing.T) { name := t.Name() logger := defaultLogger() - cp := &abci.ConsensusParams{ - Block: &abci.BlockParams{ + cp := &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxGas: 5000000, }, } @@ -1565,8 +1565,8 @@ func TestMaxBlockGasLimits(t *testing.T) { app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) app.InitChain(abci.RequestInitChain{ - ConsensusParams: &abci.ConsensusParams{ - Block: &abci.BlockParams{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxGas: 100, }, }, @@ -1824,8 +1824,8 @@ func TestGasConsumptionBadTx(t *testing.T) { app.SetParamStore(¶mStore{db: dbm.NewMemDB()}) app.InitChain(abci.RequestInitChain{ - ConsensusParams: &abci.ConsensusParams{ - Block: &abci.BlockParams{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxGas: 9, }, }, diff --git a/baseapp/params.go b/baseapp/params.go index 14701d524798..5cf31125b027 100644 --- a/baseapp/params.go +++ b/baseapp/params.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" - abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -31,7 +30,7 @@ type ParamStore interface { // ValidateBlockParams defines a stateless validation on BlockParams. This function // is called whenever the parameters are updated or stored. func ValidateBlockParams(i interface{}) error { - v, ok := i.(abci.BlockParams) + v, ok := i.(tmproto.BlockParams) if !ok { return fmt.Errorf("invalid parameter type: %T", i) } diff --git a/baseapp/params_test.go b/baseapp/params_test.go index 6507e17a8aea..3f9d26a56f2f 100644 --- a/baseapp/params_test.go +++ b/baseapp/params_test.go @@ -4,7 +4,6 @@ import ( "testing" "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" @@ -16,11 +15,11 @@ func TestValidateBlockParams(t *testing.T) { expectErr bool }{ {nil, true}, - {&abci.BlockParams{}, true}, - {abci.BlockParams{}, true}, - {abci.BlockParams{MaxBytes: -1, MaxGas: -1}, true}, - {abci.BlockParams{MaxBytes: 2000000, MaxGas: -5}, true}, - {abci.BlockParams{MaxBytes: 2000000, MaxGas: 300000}, false}, + {&tmproto.BlockParams{}, true}, + {tmproto.BlockParams{}, true}, + {tmproto.BlockParams{MaxBytes: -1, MaxGas: -1}, true}, + {tmproto.BlockParams{MaxBytes: 2000000, MaxGas: -5}, true}, + {tmproto.BlockParams{MaxBytes: 2000000, MaxGas: 300000}, false}, } for _, tc := range testCases { diff --git a/codec/proto_codec.go b/codec/proto_codec.go index 5225bd08d426..dc96d21fbca5 100644 --- a/codec/proto_codec.go +++ b/codec/proto_codec.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - legacyproto "github.com/golang/protobuf/proto" //nolint:staticcheck // we're aware this is deprecated and using it anyhow. + legacyproto "github.com/golang/protobuf/proto" //nolint:staticcheck "google.golang.org/grpc/encoding" "google.golang.org/protobuf/proto" diff --git a/crypto/keys/secp256k1/secp256k1.go b/crypto/keys/secp256k1/secp256k1.go index 9ec713acbe36..98bb17c24764 100644 --- a/crypto/keys/secp256k1/secp256k1.go +++ b/crypto/keys/secp256k1/secp256k1.go @@ -10,7 +10,7 @@ import ( secp256k1 "github.com/btcsuite/btcd/btcec" "github.com/tendermint/tendermint/crypto" - "golang.org/x/crypto/ripemd160" //nolint: staticcheck // necessary for Bitcoin address format + "golang.org/x/crypto/ripemd160" //nolint: staticcheck "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" diff --git a/go.mod b/go.mod index 2c437b0c1878..468f7b04efa9 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/tendermint/btcd v0.1.1 github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 github.com/tendermint/go-amino v0.16.0 - github.com/tendermint/tendermint v0.34.21 + github.com/tendermint/tendermint v0.37.0-alpha.1 github.com/tendermint/tm-db v0.6.7 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e @@ -81,7 +81,6 @@ require ( github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/OpenPeeDeeP/depguard v1.1.0 // indirect - github.com/Workiva/go-datastructures v1.0.53 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/ashanbrown/forbidigo v1.3.0 // indirect @@ -198,7 +197,7 @@ require ( github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mbilski/exhaustivestruct v1.2.0 // indirect github.com/mgechev/revive v1.2.3 // indirect - github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect + github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect @@ -224,12 +223,12 @@ require ( github.com/quasilyte/gogrep v0.0.0-20220120141003-628d8b3623b5 // indirect github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect - github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect + github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rs/cors v1.8.2 // indirect github.com/ryancurrah/gomodguard v1.2.4 // indirect github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect - github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.13.0 // indirect github.com/securego/gosec/v2 v2.13.1 // indirect diff --git a/go.sum b/go.sum index 7bd03da8ceef..54c131ef9215 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= -github.com/Workiva/go-datastructures v1.0.53/go.mod h1:1yZL+zfsztete+ePzZz/Zb1/t5BnDuE2Ya2MMGhzP6A= github.com/adlio/schema v1.3.3 h1:oBJn8I02PyTB466pZO1UZEn1TV5XLlifBSyMrmHl/1I= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= @@ -746,8 +744,9 @@ github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aks github.com/mgechev/revive v1.2.3 h1:NzIEEa9+WimQ6q2Ov7OcNeySS/IOcwtkQ8RAh0R5UJ4= github.com/mgechev/revive v1.2.3/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0= github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0 h1:QRUSJEgZn2Snx0EmT/QLXibWjSUDjKWvXIT19NBVp94= +github.com/mimoo/StrobeGo v0.0.0-20210601165009-122bf33a46e0/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -848,7 +847,6 @@ github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -916,8 +914,8 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8 github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= -github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/regen-network/cosmos-proto v0.3.1 h1:rV7iM4SSFAagvy8RiyhiACbWEGotmqzywPxOvwMdxcg= github.com/regen-network/cosmos-proto v0.3.1/go.mod h1:jO0sVX6a1B36nmE8C9xBFXpNwWejXC7QqCOnH3O0+YM= github.com/regen-network/gocuke v0.6.2 h1:pHviZ0kKAq2U2hN2q3smKNxct6hS0mGByFMHGnWA97M= @@ -946,8 +944,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA= github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= -github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa h1:0U2s5loxrTy6/VgfVoLuVLFJcURKLH49ie0zSch7gh4= -github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.13.0 h1:uObNudVEEHf6JbOJy5bgKJloA1bWjxR9fwgNFpPzKnI= @@ -1039,8 +1037,8 @@ github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RM github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/tendermint v0.34.21 h1:UiGGnBFHVrZhoQVQ7EfwSOLuCtarqCSsRf8VrklqB7s= -github.com/tendermint/tendermint v0.34.21/go.mod h1:XDvfg6U7grcFTDx7VkzxnhazQ/bspGJAn4DZ6DcLLjQ= +github.com/tendermint/tendermint v0.37.0-alpha.1 h1:sE/jlVRBX00nsyH/Kroya17BR0RkBvWCZDzz1qzW7gU= +github.com/tendermint/tendermint v0.37.0-alpha.1/go.mod h1:f8Nk7ZdkIYqle2nzjkOib4XNlwXcSCoHvcG969xRuOs= github.com/tendermint/tm-db v0.6.7 h1:fE00Cbl0jayAoqlExN6oyQJ7fR/ZtoVOmvPJ//+shu8= github.com/tendermint/tm-db v0.6.7/go.mod h1:byQDzFkZV1syXr/ReXS808NxA2xvyuuVgXOJ/088L6I= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= @@ -1053,13 +1051,11 @@ github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDH github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/timonwong/logrlint v0.1.0 h1:phZCcypL/vtx6cGxObJgWZ5wexZF5SXFPLOM+ru0e/M= github.com/timonwong/logrlint v0.1.0/go.mod h1:Zleg4Gw+kRxNej+Ra7o+tEaW5k1qthTaYKU7rSD39LU= -github.com/tinylib/msgp v1.1.5/go.mod h1:eQsjooMTnV42mHu917E26IogZ2930nFyBQdofk10Udg= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomarrell/wrapcheck/v2 v2.6.2 h1:3dI6YNcrJTQ/CJQ6M/DUkc0gnqYSIk6o0rChn9E/D0M= github.com/tomarrell/wrapcheck/v2 v2.6.2/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg= github.com/tommy-muehle/go-mnd/v2 v2.5.0 h1:iAj0a8e6+dXSL7Liq0aXPox36FiN1dBbjA6lt9fl65s= github.com/tommy-muehle/go-mnd/v2 v2.5.0/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ttacon/chalk v0.0.0-20160626202418-22c06c80ed31/go.mod h1:onvgF043R+lC5RZ8IT9rBXDaEDnpnw/Cl+HFiw+v/7Q= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= @@ -1468,7 +1464,6 @@ golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1719,7 +1714,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/server/export.go b/server/export.go index 1ae4f1c723d5..a50501284d8d 100644 --- a/server/export.go +++ b/server/export.go @@ -8,7 +8,6 @@ import ( "github.com/spf13/cobra" tmjson "github.com/tendermint/tendermint/libs/json" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/client/flags" @@ -80,18 +79,17 @@ func ExportCmd(appExporter types.AppExporter, defaultNodeHome string) *cobra.Com doc.AppState = exported.AppState doc.Validators = exported.Validators doc.InitialHeight = exported.Height - doc.ConsensusParams = &tmproto.ConsensusParams{ - Block: tmproto.BlockParams{ - MaxBytes: exported.ConsensusParams.Block.MaxBytes, - MaxGas: exported.ConsensusParams.Block.MaxGas, - TimeIotaMs: doc.ConsensusParams.Block.TimeIotaMs, + doc.ConsensusParams = &tmtypes.ConsensusParams{ + Block: tmtypes.BlockParams{ + MaxBytes: exported.ConsensusParams.Block.MaxBytes, + MaxGas: exported.ConsensusParams.Block.MaxGas, }, - Evidence: tmproto.EvidenceParams{ + Evidence: tmtypes.EvidenceParams{ MaxAgeNumBlocks: exported.ConsensusParams.Evidence.MaxAgeNumBlocks, MaxAgeDuration: exported.ConsensusParams.Evidence.MaxAgeDuration, MaxBytes: exported.ConsensusParams.Evidence.MaxBytes, }, - Validator: tmproto.ValidatorParams{ + Validator: tmtypes.ValidatorParams{ PubKeyTypes: exported.ConsensusParams.Validator.PubKeyTypes, }, } diff --git a/server/rosetta/converter.go b/server/rosetta/converter.go index 7e0e27376a9d..d2d331a17596 100644 --- a/server/rosetta/converter.go +++ b/server/rosetta/converter.go @@ -338,8 +338,8 @@ func sdkEventToBalanceOperations(status string, event abci.Event) (operations [] default: return nil, false case banktypes.EventTypeCoinSpent: - spender := sdk.MustAccAddressFromBech32(string(event.Attributes[0].Value)) - coins, err := sdk.ParseCoinsNormalized(string(event.Attributes[1].Value)) + spender := sdk.MustAccAddressFromBech32(event.Attributes[0].Value) + coins, err := sdk.ParseCoinsNormalized(event.Attributes[1].Value) if err != nil { panic(err) } @@ -349,8 +349,8 @@ func sdkEventToBalanceOperations(status string, event abci.Event) (operations [] accountIdentifier = spender.String() case banktypes.EventTypeCoinReceived: - receiver := sdk.MustAccAddressFromBech32(string(event.Attributes[0].Value)) - coins, err := sdk.ParseCoinsNormalized(string(event.Attributes[1].Value)) + receiver := sdk.MustAccAddressFromBech32(event.Attributes[0].Value) + coins, err := sdk.ParseCoinsNormalized(event.Attributes[1].Value) if err != nil { panic(err) } @@ -362,7 +362,7 @@ func sdkEventToBalanceOperations(status string, event abci.Event) (operations [] // rosetta does not have the concept of burning coins, so we need to mock // the burn as a send to an address that cannot be resolved to anything case banktypes.EventTypeCoinBurn: - coins, err := sdk.ParseCoinsNormalized(string(event.Attributes[1].Value)) + coins, err := sdk.ParseCoinsNormalized(event.Attributes[1].Value) if err != nil { panic(err) } diff --git a/server/types/app.go b/server/types/app.go index 69cc0476f046..b6474d97e91e 100644 --- a/server/types/app.go +++ b/server/types/app.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/tendermint/abci/types" "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" @@ -74,7 +75,7 @@ type ( // Height is the app's latest block height. Height int64 // ConsensusParams are the exported consensus params for ABCI. - ConsensusParams *abci.ConsensusParams + ConsensusParams *tmproto.ConsensusParams } // AppExporter is a function that dumps all app state to diff --git a/store/streaming/file/service_test.go b/store/streaming/file/service_test.go index 52f477ed6a00..5960403a269a 100644 --- a/store/streaming/file/service_test.go +++ b/store/streaming/file/service_test.go @@ -8,14 +8,14 @@ import ( "sync" "testing" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/codec" codecTypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - types1 "github.com/tendermint/tendermint/proto/tendermint/types" ) var ( @@ -28,12 +28,12 @@ var ( // test abci message types mockHash = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9} testBeginBlockReq = abci.RequestBeginBlock{ - Header: types1.Header{ + Header: tmproto.Header{ Height: 1, }, - ByzantineValidators: []abci.Evidence{}, + ByzantineValidators: []abci.Misbehavior{}, Hash: mockHash, - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Round: 1, Votes: []abci.VoteInfo{}, }, @@ -53,7 +53,7 @@ var ( } testEndBlockRes = abci.ResponseEndBlock{ Events: []abci.Event{}, - ConsensusParamUpdates: &abci.ConsensusParams{}, + ConsensusParamUpdates: &tmproto.ConsensusParams{}, ValidatorUpdates: []abci.ValidatorUpdate{}, } mockTxBytes1 = []byte{9, 8, 7, 6, 5, 4, 3, 2, 1} diff --git a/tests/e2e/server/export_test.go b/tests/e2e/server/export_test.go index dc9e8e763e68..0238ddd8f5b9 100644 --- a/tests/e2e/server/export_test.go +++ b/tests/e2e/server/export_test.go @@ -35,7 +35,7 @@ import ( func TestExportCmd_ConsensusParams(t *testing.T) { tempDir := t.TempDir() - _, ctx, genDoc, cmd := setupApp(t, tempDir) + _, ctx, _, cmd := setupApp(t, tempDir) output := &bytes.Buffer{} cmd.SetOut(output) @@ -50,7 +50,6 @@ func TestExportCmd_ConsensusParams(t *testing.T) { require.Equal(t, simtestutil.DefaultConsensusParams.Block.MaxBytes, exportedGenDoc.ConsensusParams.Block.MaxBytes) require.Equal(t, simtestutil.DefaultConsensusParams.Block.MaxGas, exportedGenDoc.ConsensusParams.Block.MaxGas) - require.Equal(t, genDoc.ConsensusParams.Block.TimeIotaMs, exportedGenDoc.ConsensusParams.Block.TimeIotaMs) require.Equal(t, simtestutil.DefaultConsensusParams.Evidence.MaxAgeDuration, exportedGenDoc.ConsensusParams.Evidence.MaxAgeDuration) require.Equal(t, simtestutil.DefaultConsensusParams.Evidence.MaxAgeNumBlocks, exportedGenDoc.ConsensusParams.Evidence.MaxAgeNumBlocks) diff --git a/tests/integration/bank/keeper/keeper_test.go b/tests/integration/bank/keeper/keeper_test.go index c76dc170703a..24413331d28b 100644 --- a/tests/integration/bank/keeper/keeper_test.go +++ b/tests/integration/bank/keeper/keeper_test.go @@ -602,15 +602,15 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { } event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr2.String())}, + abci.EventAttribute{Key: types.AttributeKeyRecipient, Value: addr2.String()}, ) event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + abci.EventAttribute{Key: types.AttributeKeySender, Value: addr.String()}, ) event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}, + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins.String()}, ) event2 := sdk.Event{ @@ -619,7 +619,7 @@ func (suite *IntegrationTestSuite) TestMsgSendEvents() { } event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + abci.EventAttribute{Key: types.AttributeKeySender, Value: addr.String()}, ) // events are shifted due to the funding account events @@ -676,7 +676,7 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { } event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeySender), Value: []byte(addr.String())}, + abci.EventAttribute{Key: types.AttributeKeySender, Value: addr.String()}, ) suite.Require().Equal(abci.Event(event1), events[7]) @@ -698,22 +698,22 @@ func (suite *IntegrationTestSuite) TestMsgMultiSendEvents() { } event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr3.String())}, + abci.EventAttribute{Key: types.AttributeKeyRecipient, Value: addr3.String()}, ) event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins.String()}) event3 := sdk.Event{ Type: types.EventTypeTransfer, Attributes: []abci.EventAttribute{}, } event3.Attributes = append( event3.Attributes, - abci.EventAttribute{Key: []byte(types.AttributeKeyRecipient), Value: []byte(addr4.String())}, + abci.EventAttribute{Key: types.AttributeKeyRecipient, Value: addr4.String()}, ) event3.Attributes = append( event3.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins2.String()}, ) // events are shifted due to the funding account events suite.Require().Equal(abci.Event(event1), events[25]) diff --git a/testutil/sims/app_helpers.go b/testutil/sims/app_helpers.go index 5db49d1e87de..fb030e49f812 100644 --- a/testutil/sims/app_helpers.go +++ b/testutil/sims/app_helpers.go @@ -36,8 +36,8 @@ const ( // DefaultConsensusParams defines the default Tendermint consensus params used in // SimApp testing. -var DefaultConsensusParams = &abci.ConsensusParams{ - Block: &abci.BlockParams{ +var DefaultConsensusParams = &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxBytes: 200000, MaxGas: 2000000, }, diff --git a/types/context.go b/types/context.go index 8a050a1b0803..56765bb7329a 100644 --- a/types/context.go +++ b/types/context.go @@ -36,7 +36,7 @@ type Context struct { checkTx bool recheckTx bool // if recheckTx == true, then checkTx must also be true minGasPrice DecCoins - consParams *abci.ConsensusParams + consParams *tmproto.ConsensusParams eventManager *EventManager priority int64 // The tx priority, only relevant in CheckTx } @@ -74,8 +74,8 @@ func (c Context) HeaderHash() tmbytes.HexBytes { return hash } -func (c Context) ConsensusParams() *abci.ConsensusParams { - return proto.Clone(c.consParams).(*abci.ConsensusParams) +func (c Context) ConsensusParams() *tmproto.ConsensusParams { + return proto.Clone(c.consParams).(*tmproto.ConsensusParams) } func (c Context) Deadline() (deadline time.Time, ok bool) { @@ -217,7 +217,7 @@ func (c Context) WithMinGasPrices(gasPrices DecCoins) Context { } // WithConsensusParams returns a Context with an updated consensus params -func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context { +func (c Context) WithConsensusParams(params *tmproto.ConsensusParams) Context { c.consParams = params return c } diff --git a/types/context_test.go b/types/context_test.go index f5c7cadeb541..b84276e9ade7 100644 --- a/types/context_test.go +++ b/types/context_test.go @@ -132,7 +132,7 @@ func (s *contextTestSuite) TestContextWithCustom() { // test consensus param s.Require().Nil(ctx.ConsensusParams()) - cp := &abci.ConsensusParams{} + cp := &tmproto.ConsensusParams{} s.Require().Equal(cp, ctx.WithConsensusParams(cp).ConsensusParams()) // test inner context diff --git a/types/events.go b/types/events.go index b7ce9868ec66..9fee6b3b4c70 100644 --- a/types/events.go +++ b/types/events.go @@ -98,8 +98,8 @@ func TypedEventToEvent(tev proto.Message) (Event, error) { for _, k := range keys { v := attrMap[k] attrs = append(attrs, abci.EventAttribute{ - Key: []byte(k), - Value: v, + Key: k, + Value: string(v), }) } @@ -130,7 +130,7 @@ func ParseTypedEvent(event abci.Event) (proto.Message, error) { attrMap := make(map[string]json.RawMessage) for _, attr := range event.Attributes { - attrMap[string(attr.Key)] = json.RawMessage(attr.Value) + attrMap[attr.Key] = json.RawMessage(attr.Value) } attrBytes, err := json.Marshal(attrMap) @@ -186,18 +186,7 @@ func (a Attribute) String() string { // ToKVPair converts an Attribute object into a Tendermint key/value pair. func (a Attribute) ToKVPair() abci.EventAttribute { - return abci.EventAttribute{Key: toBytes(a.Key), Value: toBytes(a.Value)} -} - -func toBytes(i interface{}) []byte { - switch x := i.(type) { - case []uint8: - return x - case string: - return []byte(x) - default: - panic(i) - } + return abci.EventAttribute{Key: a.Key, Value: a.Value} } // AppendAttributes adds one or more attributes to an Event. @@ -295,7 +284,7 @@ func StringifyEvent(e abci.Event) StringEvent { for _, attr := range e.Attributes { res.Attributes = append( res.Attributes, - Attribute{Key: string(attr.Key), Value: string(attr.Value)}, + Attribute{Key: attr.Key, Value: attr.Value}, ) } diff --git a/types/events_test.go b/types/events_test.go index 8565a14be02d..f95f8a1612d1 100644 --- a/types/events_test.go +++ b/types/events_test.go @@ -158,15 +158,15 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() { { Type: "message", Attributes: []abci.EventAttribute{ - {Key: []byte("sender"), Value: []byte("foo")}, - {Key: []byte("recipient"), Value: []byte("bar")}, + {Key: "sender", Value: "foo"}, + {Key: "recipient", Value: "bar"}, }, }, { Type: "staking", Attributes: []abci.EventAttribute{ - {Key: []byte("deposit"), Value: []byte("5")}, - {Key: []byte("unbond"), Value: []byte("10")}, + {Key: "deposit", Value: "5"}, + {Key: "unbond", Value: "10"}, }, }, } @@ -182,15 +182,15 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() { { Type: "message", Attributes: []abci.EventAttribute{ - {Key: []byte("sender"), Value: []byte("foo"), Index: true}, - {Key: []byte("recipient"), Value: []byte("bar"), Index: true}, + {Key: "sender", Value: "foo", Index: true}, + {Key: "recipient", Value: "bar", Index: true}, }, }, { Type: "staking", Attributes: []abci.EventAttribute{ - {Key: []byte("deposit"), Value: []byte("5"), Index: true}, - {Key: []byte("unbond"), Value: []byte("10"), Index: true}, + {Key: "deposit", Value: "5", Index: true}, + {Key: "unbond", Value: "10", Index: true}, }, }, }, @@ -202,15 +202,15 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() { { Type: "message", Attributes: []abci.EventAttribute{ - {Key: []byte("sender"), Value: []byte("foo"), Index: true}, - {Key: []byte("recipient"), Value: []byte("bar")}, + {Key: "sender", Value: "foo", Index: true}, + {Key: "recipient", Value: "bar"}, }, }, { Type: "staking", Attributes: []abci.EventAttribute{ - {Key: []byte("deposit"), Value: []byte("5"), Index: true}, - {Key: []byte("unbond"), Value: []byte("10")}, + {Key: "deposit", Value: "5", Index: true}, + {Key: "unbond", Value: "10"}, }, }, }, @@ -225,15 +225,15 @@ func (s *eventsTestSuite) TestMarkEventsToIndex() { { Type: "message", Attributes: []abci.EventAttribute{ - {Key: []byte("sender"), Value: []byte("foo"), Index: true}, - {Key: []byte("recipient"), Value: []byte("bar"), Index: true}, + {Key: "sender", Value: "foo", Index: true}, + {Key: "recipient", Value: "bar", Index: true}, }, }, { Type: "staking", Attributes: []abci.EventAttribute{ - {Key: []byte("deposit"), Value: []byte("5"), Index: true}, - {Key: []byte("unbond"), Value: []byte("10"), Index: true}, + {Key: "deposit", Value: "5", Index: true}, + {Key: "unbond", Value: "10", Index: true}, }, }, }, diff --git a/types/result_test.go b/types/result_test.go index a7ef4ef06ab7..5c58313b1145 100644 --- a/types/result_test.go +++ b/types/result_test.go @@ -159,8 +159,8 @@ func (s *resultTestSuite) TestResponseFormatBroadcastTxCommit() { Type: "message", Attributes: []abci.EventAttribute{ { - Key: []byte("action"), - Value: []byte("foo"), + Key: "action", + Value: "foo", Index: true, }, }, @@ -184,8 +184,8 @@ func (s *resultTestSuite) TestResponseFormatBroadcastTxCommit() { Type: "message", Attributes: []abci.EventAttribute{ { - Key: []byte("action"), - Value: []byte("foo"), + Key: "action", + Value: "foo", Index: true, }, }, @@ -209,8 +209,8 @@ func (s *resultTestSuite) TestResponseFormatBroadcastTxCommit() { Type: "message", Attributes: []abci.EventAttribute{ { - Key: []byte("action"), - Value: []byte("foo"), + Key: "action", + Value: "foo", Index: true, }, }, diff --git a/x/authz/keeper/keeper.go b/x/authz/keeper/keeper.go index a5a5a5e7afd9..7e1b6c790b7e 100644 --- a/x/authz/keeper/keeper.go +++ b/x/authz/keeper/keeper.go @@ -149,7 +149,7 @@ func (k Keeper) DispatchActions(ctx sdk.Context, grantee sdk.AccAddress, msgs [] sdkEvents := make([]sdk.Event, 0, len(events)) for _, event := range events { e := event - e.Attributes = append(e.Attributes, abci.EventAttribute{Key: []byte("authz_msg_index"), Value: []byte(strconv.Itoa(i))}) + e.Attributes = append(e.Attributes, abci.EventAttribute{Key: "authz_msg_index", Value: strconv.Itoa(i)}) sdkEvents = append(sdkEvents, sdk.Event(e)) } @@ -252,9 +252,9 @@ func (k Keeper) GetAuthorizations(ctx sdk.Context, grantee sdk.AccAddress, grant // GetAuthorization returns an Authorization and it's expiration time. // A nil Authorization is returned under the following circumstances: -// - No grant is found. -// - A grant is found, but it is expired. -// - There was an error getting the authorization from the grant. +// - No grant is found. +// - A grant is found, but it is expired. +// - There was an error getting the authorization from the grant. func (k Keeper) GetAuthorization(ctx sdk.Context, grantee sdk.AccAddress, granter sdk.AccAddress, msgType string) (authz.Authorization, *time.Time) { grant, found := k.getGrant(ctx, grantStoreKey(grantee, granter, msgType)) if !found || (grant.Expiration != nil && grant.Expiration.Before(ctx.BlockHeader().Time)) { diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index d492f1ae9d2f..090f79456123 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -643,15 +643,15 @@ func (suite *KeeperTestSuite) TestMsgSendEvents() { } event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeyRecipient), Value: []byte(accAddrs[1].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeyRecipient, Value: accAddrs[1].String()}, ) event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeySender), Value: []byte(accAddrs[0].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeySender, Value: accAddrs[0].String()}, ) event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}, + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins.String()}, ) event2 := sdk.Event{ @@ -660,7 +660,7 @@ func (suite *KeeperTestSuite) TestMsgSendEvents() { } event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeySender), Value: []byte(accAddrs[0].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeySender, Value: accAddrs[0].String()}, ) // events are shifted due to the funding account events @@ -713,7 +713,7 @@ func (suite *KeeperTestSuite) TestMsgMultiSendEvents() { } event1.Attributes = append( event1.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeySender), Value: []byte(accAddrs[0].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeySender, Value: accAddrs[0].String()}, ) require.Equal(abci.Event(event1), events[7]) @@ -738,22 +738,22 @@ func (suite *KeeperTestSuite) TestMsgMultiSendEvents() { } event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeyRecipient), Value: []byte(accAddrs[2].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeyRecipient, Value: accAddrs[2].String()}, ) event2.Attributes = append( event2.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins.String())}) + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins.String()}) event3 := sdk.Event{ Type: banktypes.EventTypeTransfer, Attributes: []abci.EventAttribute{}, } event3.Attributes = append( event3.Attributes, - abci.EventAttribute{Key: []byte(banktypes.AttributeKeyRecipient), Value: []byte(accAddrs[3].String())}, + abci.EventAttribute{Key: banktypes.AttributeKeyRecipient, Value: accAddrs[3].String()}, ) event3.Attributes = append( event3.Attributes, - abci.EventAttribute{Key: []byte(sdk.AttributeKeyAmount), Value: []byte(newCoins2.String())}, + abci.EventAttribute{Key: sdk.AttributeKeyAmount, Value: newCoins2.String()}, ) // events are shifted due to the funding account events require.Equal(abci.Event(event1), events[25]) diff --git a/x/evidence/abci.go b/x/evidence/abci.go index 63866fd2bc68..6812de29c187 100644 --- a/x/evidence/abci.go +++ b/x/evidence/abci.go @@ -21,7 +21,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) switch tmEvidence.Type { // It's still ongoing discussion how should we treat and slash attacks with // premeditation. So for now we agree to treat them in the same way. - case abci.EvidenceType_DUPLICATE_VOTE, abci.EvidenceType_LIGHT_CLIENT_ATTACK: + case abci.MisbehaviorType_DUPLICATE_VOTE, abci.MisbehaviorType_LIGHT_CLIENT_ATTACK: evidence := types.FromABCIEvidence(tmEvidence) k.HandleEquivocationEvidence(ctx, evidence.(*types.Equivocation)) diff --git a/x/evidence/types/evidence.go b/x/evidence/types/evidence.go index 70b992a9ffc1..cdcb984f8c83 100644 --- a/x/evidence/types/evidence.go +++ b/x/evidence/types/evidence.go @@ -87,7 +87,7 @@ func (e Equivocation) GetTotalPower() int64 { return 0 } // FromABCIEvidence converts a Tendermint concrete Evidence type to // SDK Evidence using Equivocation as the concrete type. -func FromABCIEvidence(e abci.Evidence) exported.Evidence { +func FromABCIEvidence(e abci.Misbehavior) exported.Evidence { bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() consAddr, err := sdk.Bech32ifyAddressBytes(bech32PrefixConsAddr, e.Validator.Address) if err != nil { diff --git a/x/evidence/types/evidence_test.go b/x/evidence/types/evidence_test.go index 46b88a115bc6..4ac2cd34b72b 100644 --- a/x/evidence/types/evidence_test.go +++ b/x/evidence/types/evidence_test.go @@ -72,8 +72,8 @@ func TestEquivocationValidateBasic(t *testing.T) { func TestEvidenceAddressConversion(t *testing.T) { sdk.GetConfig().SetBech32PrefixForConsensusNode("testcnclcons", "testcnclconspub") - tmEvidence := abci.Evidence{ - Type: abci.EvidenceType_DUPLICATE_VOTE, + tmEvidence := abci.Misbehavior{ + Type: abci.MisbehaviorType_DUPLICATE_VOTE, Validator: abci.Validator{ Address: []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Power: 100, diff --git a/x/params/types/consensus_params.go b/x/params/types/consensus_params.go index fe27f7e8d9aa..4c7edb562090 100644 --- a/x/params/types/consensus_params.go +++ b/x/params/types/consensus_params.go @@ -1,7 +1,6 @@ package types import ( - abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/baseapp" @@ -15,7 +14,7 @@ import ( func ConsensusParamsKeyTable() KeyTable { return NewKeyTable( NewParamSetPair( - baseapp.ParamStoreKeyBlockParams, abci.BlockParams{}, baseapp.ValidateBlockParams, + baseapp.ParamStoreKeyBlockParams, tmproto.BlockParams{}, baseapp.ValidateBlockParams, ), NewParamSetPair( baseapp.ParamStoreKeyEvidenceParams, tmproto.EvidenceParams{}, baseapp.ValidateEvidenceParams, diff --git a/x/simulation/mock_tendermint.go b/x/simulation/mock_tendermint.go index 7d7f1dc99725..6c7c5e7481e4 100644 --- a/x/simulation/mock_tendermint.go +++ b/x/simulation/mock_tendermint.go @@ -166,14 +166,14 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, if len(pastTimes) == 0 { return abci.RequestBeginBlock{ Header: header, - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Votes: voteInfos, }, } } // TODO: Determine capacity before allocation - evidence := make([]abci.Evidence, 0) + evidence := make([]abci.Misbehavior, 0) for r.Float64() < params.EvidenceFraction() { height := header.Height @@ -195,8 +195,8 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, } evidence = append(evidence, - abci.Evidence{ - Type: abci.EvidenceType_DUPLICATE_VOTE, + abci.Misbehavior{ + Type: abci.MisbehaviorType_DUPLICATE_VOTE, Validator: validator, Height: height, Time: time, @@ -209,7 +209,7 @@ func RandomRequestBeginBlock(r *rand.Rand, params Params, return abci.RequestBeginBlock{ Header: header, - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Votes: voteInfos, }, ByzantineValidators: evidence, diff --git a/x/simulation/params.go b/x/simulation/params.go index 51dfb6439f10..acc7d9b6d8f7 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -5,7 +5,6 @@ import ( "fmt" "math/rand" - abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/tendermint/tendermint/types" @@ -151,7 +150,7 @@ func (w WeightedProposalContent) ContentSimulatorFn() simulation.ContentSimulato // Param change proposals // randomConsensusParams returns random simulation consensus parameters, it extracts the Evidence from the Staking genesis state. -func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSONCodec) *abci.ConsensusParams { +func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSONCodec) *tmproto.ConsensusParams { var genesisState map[string]json.RawMessage err := json.Unmarshal(appState, &genesisState) if err != nil { @@ -159,8 +158,8 @@ func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSO } stakingGenesisState := stakingtypes.GetGenesisStateFromAppState(cdc, genesisState) - consensusParams := &abci.ConsensusParams{ - Block: &abci.BlockParams{ + consensusParams := &tmproto.ConsensusParams{ + Block: &tmproto.BlockParams{ MaxBytes: int64(simulation.RandIntBetween(r, 20000000, 30000000)), MaxGas: -1, }, diff --git a/x/slashing/abci_test.go b/x/slashing/abci_test.go index 3b83c8d8c2e0..6add22132fa8 100644 --- a/x/slashing/abci_test.go +++ b/x/slashing/abci_test.go @@ -60,7 +60,7 @@ func TestBeginBlocker(t *testing.T) { // mark the validator as having signed req := abci.RequestBeginBlock{ - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Votes: []abci.VoteInfo{{ Validator: val, SignedLastBlock: true, @@ -83,7 +83,7 @@ func TestBeginBlocker(t *testing.T) { for ; height < slashingKeeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Votes: []abci.VoteInfo{{ Validator: val, SignedLastBlock: true, @@ -98,7 +98,7 @@ func TestBeginBlocker(t *testing.T) { for ; height < ((slashingKeeper.SignedBlocksWindow(ctx) * 2) - slashingKeeper.MinSignedPerWindow(ctx) + 1); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ - LastCommitInfo: abci.LastCommitInfo{ + LastCommitInfo: abci.CommitInfo{ Votes: []abci.VoteInfo{{ Validator: val, SignedLastBlock: false, diff --git a/x/upgrade/abci.go b/x/upgrade/abci.go index f0214751422c..91795b9f709e 100644 --- a/x/upgrade/abci.go +++ b/x/upgrade/abci.go @@ -85,7 +85,7 @@ func BeginBlocker(k keeper.Keeper, ctx sdk.Context, _ abci.RequestBeginBlock) { cp := ctx.ConsensusParams() if cp != nil && cp.Version != nil { - appVersion = cp.Version.AppVersion + appVersion = cp.Version.App } panic(fmt.Sprintf("Wrong app version %d, upgrade handler is missing for %s upgrade plan", appVersion, lastAppliedPlan)) From ca86ec5e930b74305cafcb116376b2ea3e0473ec Mon Sep 17 00:00:00 2001 From: Elias Naur <103319121+elias-orijtech@users.noreply.github.com> Date: Mon, 5 Sep 2022 13:23:48 +0200 Subject: [PATCH 15/24] fix(fuzz): fix OSS-Fuzz build (#13152) CC @odeke-em --- fuzz/oss-fuzz-build.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/fuzz/oss-fuzz-build.sh b/fuzz/oss-fuzz-build.sh index ddf00e83cc5f..13ab0bfc806a 100644 --- a/fuzz/oss-fuzz-build.sh +++ b/fuzz/oss-fuzz-build.sh @@ -13,7 +13,6 @@ build_go_fuzzer() { } go get github.com/AdamKorcz/go-118-fuzz-build/utils -go get github.com/prometheus/common/expfmt@v0.32.1 build_go_fuzzer FuzzCryptoHDDerivePrivateKeyForPath fuzz_crypto_hd_deriveprivatekeyforpath build_go_fuzzer FuzzCryptoHDNewParamsFromPath fuzz_crypto_hd_newparamsfrompath From a0682b14f4efeeefe235b23e4e196099e969fd76 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Mon, 5 Sep 2022 08:26:40 -0400 Subject: [PATCH 16/24] chore: collapse module spec and readme (#13143) * updates * add auth and separate vesting * authz * capability * crisis * epoching * nft * mint * params * upgrade * fix website build * finish other modules * fix `pre.sh` and update modules title * add docs * display vesting in docs * add page splitting for missing modules * updates * improve `pre.sh` Co-authored-by: marbar3778 Co-authored-by: Julien Robert --- docs/{CosmWasm => cosmwasm}/README.md | 0 docs/pre.sh | 25 +- x/README.md | 32 +- x/auth/README.md | 620 +++- x/auth/spec/01_concepts.md | 43 - x/auth/spec/02_state.md | 73 - x/auth/spec/03_antehandlers.md | 40 - x/auth/spec/04_keepers.md | 47 - x/auth/spec/06_params.md | 15 - x/auth/spec/07_client.md | 421 --- x/auth/spec/README.md | 45 - .../{spec/05_vesting.md => vesting/README.md} | 48 +- x/authz/README.md | 331 +- x/authz/spec/01_concepts.md | 55 - x/authz/spec/02_state.md | 27 - x/authz/spec/03_messages.md | 46 - x/authz/spec/04_events.md | 7 - x/authz/spec/05_client.md | 172 - x/authz/spec/README.md | 30 - x/bank/README.md | 938 +++++- x/bank/spec/01_state.md | 29 - x/bank/spec/02_keepers.md | 148 - x/bank/spec/03_messages.md | 38 - x/bank/spec/04_events.md | 149 - x/bank/spec/05_params.md | 24 - x/bank/spec/06_client.md | 454 --- x/bank/spec/README.md | 106 - x/capability/README.md | 138 +- x/capability/spec/01_concepts.md | 35 - x/capability/spec/02_state.md | 26 - x/capability/spec/README.md | 77 - x/crisis/README.md | 116 +- x/crisis/spec/01_state.md | 18 - x/crisis/spec/02_messages.md | 25 - x/crisis/spec/03_events.md | 18 - x/crisis/spec/04_params.md | 11 - x/crisis/spec/05_client.md | 31 - x/crisis/spec/README.md | 26 - x/distribution/README.md | 994 +++++- x/distribution/spec/01_concepts.md | 34 - x/distribution/spec/02_state.md | 73 - x/distribution/spec/03_begin_block.md | 75 - x/distribution/spec/04_messages.md | 132 - x/distribution/spec/05_hooks.md | 59 - x/distribution/spec/06_events.md | 48 - x/distribution/spec/07_params.md | 17 - x/distribution/spec/08_client.md | 469 --- x/distribution/spec/README.md | 104 - x/epoching/README.md | 91 +- x/epoching/spec/01_state.md | 58 - x/epoching/spec/03_to_improve.md | 44 - x/epoching/spec/README.md | 37 - x/evidence/README.md | 551 ++- x/evidence/spec/01_concepts.md | 78 - x/evidence/spec/02_state.md | 19 - x/evidence/spec/03_messages.md | 55 - x/evidence/spec/04_events.md | 18 - x/evidence/spec/05_params.md | 7 - x/evidence/spec/06_begin_block.md | 154 - x/evidence/spec/07_client.md | 188 -- x/evidence/spec/README.md | 40 - x/feegrant/README.md | 374 ++- x/feegrant/spec/01_concepts.md | 93 - x/feegrant/spec/02_state.md | 23 - x/feegrant/spec/03_messages.md | 17 - x/feegrant/spec/04_events.md | 33 - x/feegrant/spec/05_client.md | 184 - x/feegrant/spec/README.md | 37 - x/gov/README.md | 2625 ++++++++++++++- x/gov/spec/01_concepts.md | 203 -- x/gov/spec/02_state.md | 219 -- x/gov/spec/03_messages.md | 183 - x/gov/spec/04_events.md | 65 - x/gov/spec/05_future_improvements.md | 30 - x/gov/spec/06_params.md | 28 - x/gov/spec/07_client.md | 1794 ---------- x/gov/spec/08_metadata.md | 30 - x/gov/spec/README.md | 65 - x/group/{spec/05_client.md => README.md} | 604 +++- x/group/internal/orm/README.md | 119 + x/group/internal/orm/spec/01_table.md | 47 - .../internal/orm/spec/02_secondary_index.md | 24 - .../orm/spec/03_iterator_pagination.md | 28 - x/group/internal/orm/spec/README.md | 15 - x/group/spec/01_concepts.md | 157 - x/group/spec/02_state.md | 105 - x/group/spec/03_messages.md | 159 - x/group/spec/04_events.md | 72 - x/group/spec/06_metadata.md | 52 - x/group/spec/README.md | 63 - x/mint/README.md | 386 ++- x/mint/spec/01_concepts.md | 28 - x/mint/spec/02_state.md | 22 - x/mint/spec/03_begin_block.md | 66 - x/mint/spec/04_params.md | 16 - x/mint/spec/05_events.md | 16 - x/mint/spec/06_client.md | 224 -- x/mint/spec/README.md | 26 - x/nft/README.md | 88 + x/nft/spec/01_concepts.md | 13 - x/nft/spec/02_state.md | 35 - x/nft/spec/03_messages.md | 17 - x/nft/spec/04_events.md | 3 - x/nft/spec/README.md | 22 - x/params/README.md | 83 +- x/params/spec/01_keeper.md | 19 - x/params/spec/02_subspace.md | 38 - x/params/spec/README.md | 31 - x/slashing/README.md | 825 ++++- x/slashing/spec/01_concepts.md | 57 - x/slashing/spec/02_state.md | 60 - x/slashing/spec/03_messages.md | 51 - x/slashing/spec/04_begin_block.md | 98 - x/slashing/spec/05_hooks.md | 45 - x/slashing/spec/06_events.md | 46 - x/slashing/spec/07_tombstone.md | 127 - x/slashing/spec/08_params.md | 15 - x/slashing/spec/09_client.md | 294 -- x/slashing/spec/README.md | 49 - x/staking/README.md | 2968 ++++++++++++++++- x/staking/spec/01_state.md | 217 -- x/staking/spec/02_state_transitions.md | 180 - x/staking/spec/03_messages.md | 187 -- x/staking/spec/04_begin_block.md | 16 - x/staking/spec/05_end_block.md | 77 - x/staking/spec/06_hooks.md | 29 - x/staking/spec/07_events.md | 90 - x/staking/spec/08_params.md | 16 - x/staking/spec/09_client.md | 2101 ------------ x/staking/spec/README.md | 56 - x/upgrade/README.md | 621 +++- x/upgrade/spec/01_concepts.md | 104 - x/upgrade/spec/02_state.md | 20 - x/upgrade/spec/03_events.md | 8 - x/upgrade/spec/04_client.md | 459 --- x/upgrade/spec/05_resources.md | 9 - x/upgrade/spec/README.md | 32 - 137 files changed, 12526 insertions(+), 12741 deletions(-) rename docs/{CosmWasm => cosmwasm}/README.md (100%) delete mode 100644 x/auth/spec/01_concepts.md delete mode 100644 x/auth/spec/02_state.md delete mode 100644 x/auth/spec/03_antehandlers.md delete mode 100644 x/auth/spec/04_keepers.md delete mode 100644 x/auth/spec/06_params.md delete mode 100644 x/auth/spec/07_client.md delete mode 100644 x/auth/spec/README.md rename x/auth/{spec/05_vesting.md => vesting/README.md} (92%) delete mode 100644 x/authz/spec/01_concepts.md delete mode 100644 x/authz/spec/02_state.md delete mode 100644 x/authz/spec/03_messages.md delete mode 100644 x/authz/spec/04_events.md delete mode 100644 x/authz/spec/05_client.md delete mode 100644 x/authz/spec/README.md delete mode 100644 x/bank/spec/01_state.md delete mode 100644 x/bank/spec/02_keepers.md delete mode 100644 x/bank/spec/03_messages.md delete mode 100644 x/bank/spec/04_events.md delete mode 100644 x/bank/spec/05_params.md delete mode 100644 x/bank/spec/06_client.md delete mode 100644 x/bank/spec/README.md delete mode 100644 x/capability/spec/01_concepts.md delete mode 100644 x/capability/spec/02_state.md delete mode 100644 x/capability/spec/README.md delete mode 100644 x/crisis/spec/01_state.md delete mode 100644 x/crisis/spec/02_messages.md delete mode 100644 x/crisis/spec/03_events.md delete mode 100644 x/crisis/spec/04_params.md delete mode 100644 x/crisis/spec/05_client.md delete mode 100644 x/crisis/spec/README.md delete mode 100644 x/distribution/spec/01_concepts.md delete mode 100644 x/distribution/spec/02_state.md delete mode 100644 x/distribution/spec/03_begin_block.md delete mode 100644 x/distribution/spec/04_messages.md delete mode 100644 x/distribution/spec/05_hooks.md delete mode 100644 x/distribution/spec/06_events.md delete mode 100644 x/distribution/spec/07_params.md delete mode 100644 x/distribution/spec/08_client.md delete mode 100644 x/distribution/spec/README.md delete mode 100644 x/epoching/spec/01_state.md delete mode 100644 x/epoching/spec/03_to_improve.md delete mode 100644 x/epoching/spec/README.md delete mode 100644 x/evidence/spec/01_concepts.md delete mode 100644 x/evidence/spec/02_state.md delete mode 100644 x/evidence/spec/03_messages.md delete mode 100644 x/evidence/spec/04_events.md delete mode 100644 x/evidence/spec/05_params.md delete mode 100644 x/evidence/spec/06_begin_block.md delete mode 100644 x/evidence/spec/07_client.md delete mode 100644 x/evidence/spec/README.md delete mode 100644 x/feegrant/spec/01_concepts.md delete mode 100644 x/feegrant/spec/02_state.md delete mode 100644 x/feegrant/spec/03_messages.md delete mode 100644 x/feegrant/spec/04_events.md delete mode 100644 x/feegrant/spec/05_client.md delete mode 100644 x/feegrant/spec/README.md delete mode 100644 x/gov/spec/01_concepts.md delete mode 100644 x/gov/spec/02_state.md delete mode 100644 x/gov/spec/03_messages.md delete mode 100644 x/gov/spec/04_events.md delete mode 100644 x/gov/spec/05_future_improvements.md delete mode 100644 x/gov/spec/06_params.md delete mode 100644 x/gov/spec/07_client.md delete mode 100644 x/gov/spec/08_metadata.md delete mode 100644 x/gov/spec/README.md rename x/group/{spec/05_client.md => README.md} (53%) create mode 100644 x/group/internal/orm/README.md delete mode 100644 x/group/internal/orm/spec/01_table.md delete mode 100644 x/group/internal/orm/spec/02_secondary_index.md delete mode 100644 x/group/internal/orm/spec/03_iterator_pagination.md delete mode 100644 x/group/internal/orm/spec/README.md delete mode 100644 x/group/spec/01_concepts.md delete mode 100644 x/group/spec/02_state.md delete mode 100644 x/group/spec/03_messages.md delete mode 100644 x/group/spec/04_events.md delete mode 100644 x/group/spec/06_metadata.md delete mode 100644 x/group/spec/README.md delete mode 100644 x/mint/spec/01_concepts.md delete mode 100644 x/mint/spec/02_state.md delete mode 100644 x/mint/spec/03_begin_block.md delete mode 100644 x/mint/spec/04_params.md delete mode 100644 x/mint/spec/05_events.md delete mode 100644 x/mint/spec/06_client.md delete mode 100644 x/mint/spec/README.md create mode 100644 x/nft/README.md delete mode 100644 x/nft/spec/01_concepts.md delete mode 100644 x/nft/spec/02_state.md delete mode 100644 x/nft/spec/03_messages.md delete mode 100644 x/nft/spec/04_events.md delete mode 100644 x/nft/spec/README.md delete mode 100644 x/params/spec/01_keeper.md delete mode 100644 x/params/spec/02_subspace.md delete mode 100644 x/params/spec/README.md delete mode 100644 x/slashing/spec/01_concepts.md delete mode 100644 x/slashing/spec/02_state.md delete mode 100644 x/slashing/spec/03_messages.md delete mode 100644 x/slashing/spec/04_begin_block.md delete mode 100644 x/slashing/spec/05_hooks.md delete mode 100644 x/slashing/spec/06_events.md delete mode 100644 x/slashing/spec/07_tombstone.md delete mode 100644 x/slashing/spec/08_params.md delete mode 100644 x/slashing/spec/09_client.md delete mode 100644 x/slashing/spec/README.md delete mode 100644 x/staking/spec/01_state.md delete mode 100644 x/staking/spec/02_state_transitions.md delete mode 100644 x/staking/spec/03_messages.md delete mode 100644 x/staking/spec/04_begin_block.md delete mode 100644 x/staking/spec/05_end_block.md delete mode 100644 x/staking/spec/06_hooks.md delete mode 100644 x/staking/spec/07_events.md delete mode 100644 x/staking/spec/08_params.md delete mode 100644 x/staking/spec/09_client.md delete mode 100644 x/staking/spec/README.md delete mode 100644 x/upgrade/spec/01_concepts.md delete mode 100644 x/upgrade/spec/02_state.md delete mode 100644 x/upgrade/spec/03_events.md delete mode 100644 x/upgrade/spec/04_client.md delete mode 100644 x/upgrade/spec/05_resources.md delete mode 100644 x/upgrade/spec/README.md diff --git a/docs/CosmWasm/README.md b/docs/cosmwasm/README.md similarity index 100% rename from docs/CosmWasm/README.md rename to docs/cosmwasm/README.md diff --git a/docs/pre.sh b/docs/pre.sh index 495fd912ef27..5fb5c3f94d72 100755 --- a/docs/pre.sh +++ b/docs/pre.sh @@ -4,11 +4,30 @@ mkdir -p modules for D in ../x/*; do if [ -d "${D}" ]; then - rm -rf "modules/$(echo $D | awk -F/ '{print $NF}')" - mkdir -p "modules/$(echo $D | awk -F/ '{print $NF}')" && cp -r $D/spec/* "$_" + MODDOC=modules/$(echo $D | awk -F/ '{print $NF}') + rm -rf $MODDOC + mkdir -p $MODDOC && cp -r $D/README.md "$_" + if [ -f "$MODDOC/README.md" ]; then + cd $MODDOC + # This ensures that we have multiples pages for the modules documantation + # This is easier to read for the user + # In order to split pages, we need to add a in the module README.md, for each pages that we want. + csplit -k -q README.md '/ -# Auth +# `x/auth` -* [Auth](spec/README.md) - Authentication of accounts and transactions for Cosmos SDK applications. +## Abstract + +This document specifies the auth module of the Cosmos SDK. + +The auth module is responsible for specifying the base transaction and account types +for an application, since the SDK itself is agnostic to these particulars. It contains +the middlewares, where all basic transaction validity checks (signatures, nonces, auxiliary fields) +are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts. + +This module is used in the Cosmos Hub. + +## Contents + +* [Concepts](#concepts) + * [Gas & Fees](#gas--fees) +* [State](#state) + * [Accounts](#accounts) +* [AnteHandlers](#antehandlers) +* [Keepers](#keepers) + * [Account Keeper](#account-keeper) +* [Parameters](#parameters) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) + + + +# Concepts + +**Note:** The auth module is different from the [authz module](../modules/authz/). + +The differences are: + +* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types. +* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter. + +## Gas & Fees + +Fees serve two purposes for an operator of the network. + +Fees limit the growth of the state stored by every full node and allow for +general purpose censorship of transactions of little economic value. Fees +are best suited as an anti-spam mechanism where validators are disinterested in +the use of the network and identities of users. + +Fees are determined by the gas limits and gas prices transactions provide, where +`fees = ceil(gasLimit * gasPrices)`. Txs incur gas costs for all state reads/writes, +signature verification, as well as costs proportional to the tx size. Operators +should set minimum gas prices when starting their nodes. They must set the unit +costs of gas in each token denomination they wish to support: + +`simd start ... --minimum-gas-prices=0.00001stake;0.05photinos` + +When adding transactions to mempool or gossipping transactions, validators check +if the transaction's gas prices, which are determined by the provided fees, meet +any of the validator's minimum gas prices. In other words, a transaction must +provide a fee of at least one denomination that matches a validator's minimum +gas price. + +Tendermint does not currently provide fee based mempool prioritization, and fee +based mempool filtering is local to node and not part of consensus. But with +minimum gas prices set, such a mechanism could be implemented by node operators. + +Because the market value for tokens will fluctuate, validators are expected to +dynamically adjust their minimum gas prices to a level that would encourage the +use of the network. + + + +# State + +## Accounts + +Accounts contain authentication information for a uniquely identified external user of an SDK blockchain, +including public key, address, and account number / sequence number for replay protection. For efficiency, +since account balances must also be fetched to pay fees, account structs also store the balance of a user +as `sdk.Coins`. + +Accounts are exposed externally as an interface, and stored internally as +either a base account or vesting account. Module clients wishing to add more +account types may do so. + +* `0x01 | Address -> ProtocolBuffer(account)` + +### Account Interface + +The account interface exposes methods to read and write standard account information. +Note that all of these methods operate on an account struct confirming to the +interface - in order to write the account to the store, the account keeper will +need to be used. + +```go +// AccountI is an interface used to store coins at a given address within state. +// It presumes a notion of sequence numbers for replay protection, +// a notion of account numbers for replay protection for previously pruned accounts, +// and a pubkey for authentication purposes. +// +// Many complex conditions can be used in the concrete struct which implements AccountI. +type AccountI interface { + proto.Message + + GetAddress() sdk.AccAddress + SetAddress(sdk.AccAddress) error // errors if already set. + + GetPubKey() crypto.PubKey // can return nil. + SetPubKey(crypto.PubKey) error + + GetAccountNumber() uint64 + SetAccountNumber(uint64) error + + GetSequence() uint64 + SetSequence(uint64) error + + // Ensure that account implements stringer + String() string +} +``` + +#### Base Account + +A base account is the simplest and most common account type, which just stores all requisite +fields directly in a struct. + +```protobuf +// BaseAccount defines a base account type. It contains all the necessary fields +// for basic account functionality. Any custom account type should extend this +// type for additional functionality (e.g. vesting). +message BaseAccount { + string address = 1; + google.protobuf.Any pub_key = 2; + uint64 account_number = 3; + uint64 sequence = 4; +} +``` + +### Vesting Account + +See [Vesting](https://docs.cosmos.network/main/modules/vesting/). + + + +# AnteHandlers + +The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool. +The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-010-modular-antehandler.md). + +Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`. + +## Decorators + +The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order: + +* `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used. + +* `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions. + +* `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`. + +* `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error. + +* `TxTimeoutHeightDecorator`: Check for a `tx` height timeout. + +* `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error. + +* `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters. + +* `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it deducts fees from the fee granter account. + +* `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context. + +* `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters. + +* `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. + +* `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. + +* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. + + + +# Keepers + +The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts. + +## Account Keeper + +Presently only one fully-permissioned account keeper is exposed, which has the ability to both read and write +all fields of all accounts, and to iterate over all stored accounts. + +```go +// AccountKeeperI is the interface contract that x/auth's keeper implements. +type AccountKeeperI interface { + // Return a new account with the next account number and the specified address. Does not save the new account to the store. + NewAccountWithAddress(sdk.Context, sdk.AccAddress) types.AccountI + + // Return a new account with the next account number. Does not save the new account to the store. + NewAccount(sdk.Context, types.AccountI) types.AccountI + + // Check if an account exists in the store. + HasAccount(sdk.Context, sdk.AccAddress) bool + + // Retrieve an account from the store. + GetAccount(sdk.Context, sdk.AccAddress) types.AccountI + + // Set an account in the store. + SetAccount(sdk.Context, types.AccountI) + + // Remove an account from the store. + RemoveAccount(sdk.Context, types.AccountI) + + // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. + IterateAccounts(sdk.Context, func(types.AccountI) bool) + + // Fetch the public key of an account at a specified address + GetPubKey(sdk.Context, sdk.AccAddress) (crypto.PubKey, error) + + // Fetch the sequence of an account at a specified address. + GetSequence(sdk.Context, sdk.AccAddress) (uint64, error) + + // Fetch the next account number, and increment the internal counter. + GetNextAccountNumber(sdk.Context) uint64 +} +``` + + + +# Parameters + +The auth module contains the following parameters: + +| Key | Type | Example | +| ---------------------- | --------------- | ------- | +| MaxMemoCharacters | uint64 | 256 | +| TxSigLimit | uint64 | 7 | +| TxSizeCostPerByte | uint64 | 10 | +| SigVerifyCostED25519 | uint64 | 590 | +| SigVerifyCostSecp256k1 | uint64 | 1000 | + + + +# Client + +## CLI + +A user can query and interact with the `auth` module using the CLI. + +### Query + +The `query` commands allow users to query `auth` state. + +```bash +simd query auth --help +``` + +#### account + +The `account` command allow users to query for an account by it's address. + +```bash +simd query auth account [address] [flags] +``` + +Example: + +```bash +simd query auth account cosmos1... +``` + +Example Output: + +```bash +'@type': /cosmos.auth.v1beta1.BaseAccount +account_number: "0" +address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 +pub_key: + '@type': /cosmos.crypto.secp256k1.PubKey + key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD +sequence: "1" +``` + +#### accounts + +The `accounts` command allow users to query all the available accounts. + +```bash +simd query auth accounts [flags] +``` + +Example: + +```bash +simd query auth accounts +``` + +Example Output: + +```bash +accounts: +- '@type': /cosmos.auth.v1beta1.BaseAccount + account_number: "0" + address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 + pub_key: + '@type': /cosmos.crypto.secp256k1.PubKey + key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD + sequence: "1" +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "8" + address: cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr + pub_key: null + sequence: "0" + name: transfer + permissions: + - minter + - burner +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "4" + address: cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh + pub_key: null + sequence: "0" + name: bonded_tokens_pool + permissions: + - burner + - staking +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "5" + address: cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r + pub_key: null + sequence: "0" + name: not_bonded_tokens_pool + permissions: + - burner + - staking +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "6" + address: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn + pub_key: null + sequence: "0" + name: gov + permissions: + - burner +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "3" + address: cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl + pub_key: null + sequence: "0" + name: distribution + permissions: [] +- '@type': /cosmos.auth.v1beta1.BaseAccount + account_number: "1" + address: cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j + pub_key: null + sequence: "0" +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "7" + address: cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q + pub_key: null + sequence: "0" + name: mint + permissions: + - minter +- '@type': /cosmos.auth.v1beta1.ModuleAccount + base_account: + account_number: "2" + address: cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta + pub_key: null + sequence: "0" + name: fee_collector + permissions: [] +pagination: + next_key: null + total: "0" +``` + +#### params + +The `params` command allow users to query the current auth parameters. + +```bash +simd query auth params [flags] +``` + +Example: + +```bash +simd query auth params +``` + +Example Output: + +```bash +max_memo_characters: "256" +sig_verify_cost_ed25519: "590" +sig_verify_cost_secp256k1: "1000" +tx_sig_limit: "7" +tx_size_cost_per_byte: "10" +``` + +## gRPC + +A user can query the `auth` module using gRPC endpoints. + +### Account + +The `account` endpoint allow users to query for an account by it's address. + +```bash +cosmos.auth.v1beta1.Query/Account +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Account +``` + +Example Output: + +```bash +{ + "account":{ + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", + "pubKey":{ + "@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" + }, + "sequence":"1" + } +} +``` + +### Accounts + +The `accounts` endpoint allow users to query all the available accounts. + +```bash +cosmos.auth.v1beta1.Query/Accounts +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Accounts +``` + +Example Output: + +```bash +{ + "accounts":[ + { + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", + "pubKey":{ + "@type":"/cosmos.crypto.secp256k1.PubKey", + "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" + }, + "sequence":"1" + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr", + "accountNumber":"8" + }, + "name":"transfer", + "permissions":[ + "minter", + "burner" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + "accountNumber":"4" + }, + "name":"bonded_tokens_pool", + "permissions":[ + "burner", + "staking" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r", + "accountNumber":"5" + }, + "name":"not_bonded_tokens_pool", + "permissions":[ + "burner", + "staking" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", + "accountNumber":"6" + }, + "name":"gov", + "permissions":[ + "burner" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl", + "accountNumber":"3" + }, + "name":"distribution" + }, + { + "@type":"/cosmos.auth.v1beta1.BaseAccount", + "accountNumber":"1", + "address":"cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j" + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q", + "accountNumber":"7" + }, + "name":"mint", + "permissions":[ + "minter" + ] + }, + { + "@type":"/cosmos.auth.v1beta1.ModuleAccount", + "baseAccount":{ + "address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", + "accountNumber":"2" + }, + "name":"fee_collector" + } + ], + "pagination":{ + "total":"9" + } +} +``` + +### Params + +The `params` endpoint allow users to query the current auth parameters. + +```bash +cosmos.auth.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.auth.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "params": { + "maxMemoCharacters": "256", + "txSigLimit": "7", + "txSizeCostPerByte": "10", + "sigVerifyCostEd25519": "590", + "sigVerifyCostSecp256k1": "1000" + } +} +``` + +## REST + +A user can query the `auth` module using REST endpoints. + +### Account + +The `account` endpoint allow users to query for an account by it's address. + +```bash +/cosmos/auth/v1beta1/account?address={address} +``` + +### Accounts + +The `accounts` endpoint allow users to query all the available accounts. + +```bash +/cosmos/auth/v1beta1/accounts +``` + +### Params + +The `params` endpoint allow users to query the current auth parameters. + +```bash +/cosmos/auth/v1beta1/params +``` diff --git a/x/auth/spec/01_concepts.md b/x/auth/spec/01_concepts.md deleted file mode 100644 index e028ebe8e9a3..000000000000 --- a/x/auth/spec/01_concepts.md +++ /dev/null @@ -1,43 +0,0 @@ - - -# Concepts - -**Note:** The auth module is different from the [authz module](../modules/authz/). - -The differences are: - -* `auth` - authentication of accounts and transactions for Cosmos SDK applications and is responsible for specifying the base transaction and account types. -* `authz` - authorization for accounts to perform actions on behalf of other accounts and enables a granter to grant authorizations to a grantee that allows the grantee to execute messages on behalf of the granter. - -## Gas & Fees - -Fees serve two purposes for an operator of the network. - -Fees limit the growth of the state stored by every full node and allow for -general purpose censorship of transactions of little economic value. Fees -are best suited as an anti-spam mechanism where validators are disinterested in -the use of the network and identities of users. - -Fees are determined by the gas limits and gas prices transactions provide, where -`fees = ceil(gasLimit * gasPrices)`. Txs incur gas costs for all state reads/writes, -signature verification, as well as costs proportional to the tx size. Operators -should set minimum gas prices when starting their nodes. They must set the unit -costs of gas in each token denomination they wish to support: - -`simd start ... --minimum-gas-prices=0.00001stake;0.05photinos` - -When adding transactions to mempool or gossipping transactions, validators check -if the transaction's gas prices, which are determined by the provided fees, meet -any of the validator's minimum gas prices. In other words, a transaction must -provide a fee of at least one denomination that matches a validator's minimum -gas price. - -Tendermint does not currently provide fee based mempool prioritization, and fee -based mempool filtering is local to node and not part of consensus. But with -minimum gas prices set, such a mechanism could be implemented by node operators. - -Because the market value for tokens will fluctuate, validators are expected to -dynamically adjust their minimum gas prices to a level that would encourage the -use of the network. diff --git a/x/auth/spec/02_state.md b/x/auth/spec/02_state.md deleted file mode 100644 index 560e93421f02..000000000000 --- a/x/auth/spec/02_state.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# State - -## Accounts - -Accounts contain authentication information for a uniquely identified external user of an SDK blockchain, -including public key, address, and account number / sequence number for replay protection. For efficiency, -since account balances must also be fetched to pay fees, account structs also store the balance of a user -as `sdk.Coins`. - -Accounts are exposed externally as an interface, and stored internally as -either a base account or vesting account. Module clients wishing to add more -account types may do so. - -* `0x01 | Address -> ProtocolBuffer(account)` - -### Account Interface - -The account interface exposes methods to read and write standard account information. -Note that all of these methods operate on an account struct confirming to the -interface - in order to write the account to the store, the account keeper will -need to be used. - -```go -// AccountI is an interface used to store coins at a given address within state. -// It presumes a notion of sequence numbers for replay protection, -// a notion of account numbers for replay protection for previously pruned accounts, -// and a pubkey for authentication purposes. -// -// Many complex conditions can be used in the concrete struct which implements AccountI. -type AccountI interface { - proto.Message - - GetAddress() sdk.AccAddress - SetAddress(sdk.AccAddress) error // errors if already set. - - GetPubKey() crypto.PubKey // can return nil. - SetPubKey(crypto.PubKey) error - - GetAccountNumber() uint64 - SetAccountNumber(uint64) error - - GetSequence() uint64 - SetSequence(uint64) error - - // Ensure that account implements stringer - String() string -} -``` - -#### Base Account - -A base account is the simplest and most common account type, which just stores all requisite -fields directly in a struct. - -```protobuf -// BaseAccount defines a base account type. It contains all the necessary fields -// for basic account functionality. Any custom account type should extend this -// type for additional functionality (e.g. vesting). -message BaseAccount { - string address = 1; - google.protobuf.Any pub_key = 2; - uint64 account_number = 3; - uint64 sequence = 4; -} -``` - -### Vesting Account - -See [Vesting](05_vesting.md). diff --git a/x/auth/spec/03_antehandlers.md b/x/auth/spec/03_antehandlers.md deleted file mode 100644 index 3227d8dff276..000000000000 --- a/x/auth/spec/03_antehandlers.md +++ /dev/null @@ -1,40 +0,0 @@ - - -# AnteHandlers - -The `x/auth` module presently has no transaction handlers of its own, but does expose the special `AnteHandler`, used for performing basic validity checks on a transaction, such that it could be thrown out of the mempool. -The `AnteHandler` can be seen as a set of decorators that check transactions within the current context, per [ADR 010](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-010-modular-antehandler.md). - -Note that the `AnteHandler` is called on both `CheckTx` and `DeliverTx`, as Tendermint proposers presently have the ability to include in their proposed block transactions which fail `CheckTx`. - -## Decorators - -The auth module provides `AnteDecorator`s that are recursively chained together into a single `AnteHandler` in the following order: - -* `SetUpContextDecorator`: Sets the `GasMeter` in the `Context` and wraps the next `AnteHandler` with a defer clause to recover from any downstream `OutOfGas` panics in the `AnteHandler` chain to return an error with information on gas provided and gas used. - -* `RejectExtensionOptionsDecorator`: Rejects all extension options which can optionally be included in protobuf transactions. - -* `MempoolFeeDecorator`: Checks if the `tx` fee is above local mempool `minFee` parameter during `CheckTx`. - -* `ValidateBasicDecorator`: Calls `tx.ValidateBasic` and returns any non-nil error. - -* `TxTimeoutHeightDecorator`: Check for a `tx` height timeout. - -* `ValidateMemoDecorator`: Validates `tx` memo with application parameters and returns any non-nil error. - -* `ConsumeGasTxSizeDecorator`: Consumes gas proportional to the `tx` size based on application parameters. - -* `DeductFeeDecorator`: Deducts the `FeeAmount` from first signer of the `tx`. If the `x/feegrant` module is enabled and a fee granter is set, it deducts fees from the fee granter account. - -* `SetPubKeyDecorator`: Sets the pubkey from a `tx`'s signers that does not already have its corresponding pubkey saved in the state machine and in the current context. - -* `ValidateSigCountDecorator`: Validates the number of signatures in `tx` based on app-parameters. - -* `SigGasConsumeDecorator`: Consumes parameter-defined amount of gas for each signature. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. - -* `SigVerificationDecorator`: Verifies all signatures are valid. This requires pubkeys to be set in context for all signers as part of `SetPubKeyDecorator`. - -* `IncrementSequenceDecorator`: Increments the account sequence for each signer to prevent replay attacks. diff --git a/x/auth/spec/04_keepers.md b/x/auth/spec/04_keepers.md deleted file mode 100644 index 268ced5c3eb8..000000000000 --- a/x/auth/spec/04_keepers.md +++ /dev/null @@ -1,47 +0,0 @@ - - -# Keepers - -The auth module only exposes one keeper, the account keeper, which can be used to read and write accounts. - -## Account Keeper - -Presently only one fully-permissioned account keeper is exposed, which has the ability to both read and write -all fields of all accounts, and to iterate over all stored accounts. - -```go -// AccountKeeperI is the interface contract that x/auth's keeper implements. -type AccountKeeperI interface { - // Return a new account with the next account number and the specified address. Does not save the new account to the store. - NewAccountWithAddress(sdk.Context, sdk.AccAddress) types.AccountI - - // Return a new account with the next account number. Does not save the new account to the store. - NewAccount(sdk.Context, types.AccountI) types.AccountI - - // Check if an account exists in the store. - HasAccount(sdk.Context, sdk.AccAddress) bool - - // Retrieve an account from the store. - GetAccount(sdk.Context, sdk.AccAddress) types.AccountI - - // Set an account in the store. - SetAccount(sdk.Context, types.AccountI) - - // Remove an account from the store. - RemoveAccount(sdk.Context, types.AccountI) - - // Iterate over all accounts, calling the provided function. Stop iteration when it returns true. - IterateAccounts(sdk.Context, func(types.AccountI) bool) - - // Fetch the public key of an account at a specified address - GetPubKey(sdk.Context, sdk.AccAddress) (crypto.PubKey, error) - - // Fetch the sequence of an account at a specified address. - GetSequence(sdk.Context, sdk.AccAddress) (uint64, error) - - // Fetch the next account number, and increment the internal counter. - GetNextAccountNumber(sdk.Context) uint64 -} -``` diff --git a/x/auth/spec/06_params.md b/x/auth/spec/06_params.md deleted file mode 100644 index 414e1888f1c6..000000000000 --- a/x/auth/spec/06_params.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Parameters - -The auth module contains the following parameters: - -| Key | Type | Example | -| ---------------------- | --------------- | ------- | -| MaxMemoCharacters | uint64 | 256 | -| TxSigLimit | uint64 | 7 | -| TxSizeCostPerByte | uint64 | 10 | -| SigVerifyCostED25519 | uint64 | 590 | -| SigVerifyCostSecp256k1 | uint64 | 1000 | diff --git a/x/auth/spec/07_client.md b/x/auth/spec/07_client.md deleted file mode 100644 index bcfdc6f6faee..000000000000 --- a/x/auth/spec/07_client.md +++ /dev/null @@ -1,421 +0,0 @@ - - -# Client - -# Auth - -## CLI - -A user can query and interact with the `auth` module using the CLI. - -### Query - -The `query` commands allow users to query `auth` state. - -```bash -simd query auth --help -``` - -#### account - -The `account` command allow users to query for an account by it's address. - -```bash -simd query auth account [address] [flags] -``` - -Example: - -```bash -simd query auth account cosmos1... -``` - -Example Output: - -```bash -'@type': /cosmos.auth.v1beta1.BaseAccount -account_number: "0" -address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 -pub_key: - '@type': /cosmos.crypto.secp256k1.PubKey - key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD -sequence: "1" -``` - -#### accounts - -The `accounts` command allow users to query all the available accounts. - -```bash -simd query auth accounts [flags] -``` - -Example: - -```bash -simd query auth accounts -``` - -Example Output: - -```bash -accounts: -- '@type': /cosmos.auth.v1beta1.BaseAccount - account_number: "0" - address: cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2 - pub_key: - '@type': /cosmos.crypto.secp256k1.PubKey - key: ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD - sequence: "1" -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "8" - address: cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr - pub_key: null - sequence: "0" - name: transfer - permissions: - - minter - - burner -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "4" - address: cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh - pub_key: null - sequence: "0" - name: bonded_tokens_pool - permissions: - - burner - - staking -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "5" - address: cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r - pub_key: null - sequence: "0" - name: not_bonded_tokens_pool - permissions: - - burner - - staking -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "6" - address: cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn - pub_key: null - sequence: "0" - name: gov - permissions: - - burner -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "3" - address: cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl - pub_key: null - sequence: "0" - name: distribution - permissions: [] -- '@type': /cosmos.auth.v1beta1.BaseAccount - account_number: "1" - address: cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j - pub_key: null - sequence: "0" -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "7" - address: cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q - pub_key: null - sequence: "0" - name: mint - permissions: - - minter -- '@type': /cosmos.auth.v1beta1.ModuleAccount - base_account: - account_number: "2" - address: cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta - pub_key: null - sequence: "0" - name: fee_collector - permissions: [] -pagination: - next_key: null - total: "0" -``` - -#### params - -The `params` command allow users to query the current auth parameters. - -```bash -simd query auth params [flags] -``` - -Example: - -```bash -simd query auth params -``` - -Example Output: - -```bash -max_memo_characters: "256" -sig_verify_cost_ed25519: "590" -sig_verify_cost_secp256k1: "1000" -tx_sig_limit: "7" -tx_size_cost_per_byte: "10" -``` - -## gRPC - -A user can query the `auth` module using gRPC endpoints. - -### Account - -The `account` endpoint allow users to query for an account by it's address. - -```bash -cosmos.auth.v1beta1.Query/Account -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.auth.v1beta1.Query/Account -``` - -Example Output: - -```bash -{ - "account":{ - "@type":"/cosmos.auth.v1beta1.BaseAccount", - "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", - "pubKey":{ - "@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" - }, - "sequence":"1" - } -} -``` - -### Accounts - -The `accounts` endpoint allow users to query all the available accounts. - -```bash -cosmos.auth.v1beta1.Query/Accounts -``` - -Example: - -```bash -grpcurl -plaintext \ - localhost:9090 \ - cosmos.auth.v1beta1.Query/Accounts -``` - -Example Output: - -```bash -{ - "accounts":[ - { - "@type":"/cosmos.auth.v1beta1.BaseAccount", - "address":"cosmos1zwg6tpl8aw4rawv8sgag9086lpw5hv33u5ctr2", - "pubKey":{ - "@type":"/cosmos.crypto.secp256k1.PubKey", - "key":"ApDrE38zZdd7wLmFS9YmqO684y5DG6fjZ4rVeihF/AQD" - }, - "sequence":"1" - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos1yl6hdjhmkf37639730gffanpzndzdpmhwlkfhr", - "accountNumber":"8" - }, - "name":"transfer", - "permissions":[ - "minter", - "burner" - ] - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", - "accountNumber":"4" - }, - "name":"bonded_tokens_pool", - "permissions":[ - "burner", - "staking" - ] - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos1tygms3xhhs3yv487phx3dw4a95jn7t7lpm470r", - "accountNumber":"5" - }, - "name":"not_bonded_tokens_pool", - "permissions":[ - "burner", - "staking" - ] - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn", - "accountNumber":"6" - }, - "name":"gov", - "permissions":[ - "burner" - ] - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos1jv65s3grqf6v6jl3dp4t6c9t9rk99cd88lyufl", - "accountNumber":"3" - }, - "name":"distribution" - }, - { - "@type":"/cosmos.auth.v1beta1.BaseAccount", - "accountNumber":"1", - "address":"cosmos147k3r7v2tvwqhcmaxcfql7j8rmkrlsemxshd3j" - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos1m3h30wlvsf8llruxtpukdvsy0km2kum8g38c8q", - "accountNumber":"7" - }, - "name":"mint", - "permissions":[ - "minter" - ] - }, - { - "@type":"/cosmos.auth.v1beta1.ModuleAccount", - "baseAccount":{ - "address":"cosmos17xpfvakm2amg962yls6f84z3kell8c5lserqta", - "accountNumber":"2" - }, - "name":"fee_collector" - } - ], - "pagination":{ - "total":"9" - } -} -``` - -### Params - -The `params` endpoint allow users to query the current auth parameters. - -```bash -cosmos.auth.v1beta1.Query/Params -``` - -Example: - -```bash -grpcurl -plaintext \ - localhost:9090 \ - cosmos.auth.v1beta1.Query/Params -``` - -Example Output: - -```bash -{ - "params": { - "maxMemoCharacters": "256", - "txSigLimit": "7", - "txSizeCostPerByte": "10", - "sigVerifyCostEd25519": "590", - "sigVerifyCostSecp256k1": "1000" - } -} -``` - -## REST - -A user can query the `auth` module using REST endpoints. - -### Account - -The `account` endpoint allow users to query for an account by it's address. - -```bash -/cosmos/auth/v1beta1/account?address={address} -``` - -### Accounts - -The `accounts` endpoint allow users to query all the available accounts. - -```bash -/cosmos/auth/v1beta1/accounts -``` - -### Params - -The `params` endpoint allow users to query the current auth parameters. - -```bash -/cosmos/auth/v1beta1/params -``` - -# Vesting - -## CLI - -A user can query and interact with the `vesting` module using the CLI. - -### Transactions - -The `tx` commands allow users to interact with the `vesting` module. - -```bash -simd tx vesting --help -``` - -#### create-periodic-vesting-account - -The `create-periodic-vesting-account` command creates a new vesting account funded with an allocation of tokens, where a sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation. - -```bash -simd tx vesting create-periodic-vesting-account [to_address] [periods_json_file] [flags] -``` - -Example: - -```bash -simd tx vesting create-periodic-vesting-account cosmos1.. periods.json -``` - -#### create-vesting-account - -The `create-vesting-account` command creates a new vesting account funded with an allocation of tokens. The account can either be a delayed or continuous vesting account, which is determined by the '--delayed' flag. All vesting accouts created will have their start time set by the committed block's time. The end_time must be provided as a UNIX epoch timestamp. - -```bash -simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags] -``` - -Example: - -```bash -simd tx vesting create-vesting-account cosmos1.. 100stake 2592000 -``` diff --git a/x/auth/spec/README.md b/x/auth/spec/README.md deleted file mode 100644 index 1090bb6baa1e..000000000000 --- a/x/auth/spec/README.md +++ /dev/null @@ -1,45 +0,0 @@ - - -# `auth` - -## Abstract - -This document specifies the auth module of the Cosmos SDK. - -The auth module is responsible for specifying the base transaction and account types -for an application, since the SDK itself is agnostic to these particulars. It contains -the middlewares, where all basic transaction validity checks (signatures, nonces, auxiliary fields) -are performed, and exposes the account keeper, which allows other modules to read, write, and modify accounts. - -This module is used in the Cosmos Hub. - -## Contents - -1. **[Concepts](01_concepts.md)** - * [Gas & Fees](01_concepts.md#gas-&-fees) -2. **[State](02_state.md)** - * [Accounts](02_state.md#accounts) -3. **[AnteHandlers](03_antehandlers.md)** -4. **[Keepers](04_keepers.md)** - * [Account Keeper](04_keepers.md#account-keeper) -5. **[Vesting](05_vesting.md)** - * [Intro and Requirements](05_vesting.md#intro-and-requirements) - * [Vesting Account Types](05_vesting.md#vesting-account-types) - * [Vesting Account Specification](05_vesting.md#vesting-account-specification) - * [Keepers & Handlers](05_vesting.md#keepers-&-handlers) - * [Genesis Initialization](05_vesting.md#genesis-initialization) - * [Examples](05_vesting.md#examples) - * [Glossary](05_vesting.md#glossary) -6. **[Parameters](06_params.md)** -7. **[Client](07_client.md)** - * **[Auth](07_client.md#auth)** - * [CLI](07_client.md#cli) - * [gRPC](07_client.md#grpc) - * [REST](07_client.md#rest) - * **[Vesting](07_client.md#vesting)** - * [CLI](07_client.md#vesting#cli) diff --git a/x/auth/spec/05_vesting.md b/x/auth/vesting/README.md similarity index 92% rename from x/auth/spec/05_vesting.md rename to x/auth/vesting/README.md index b7783482dbb6..f76053404c66 100644 --- a/x/auth/spec/05_vesting.md +++ b/x/auth/vesting/README.md @@ -1,5 +1,8 @@ # Vesting @@ -32,6 +35,8 @@ order: 5 * [Slashing](#slashing) * [Periodic Vesting](#periodic-vesting) * [Glossary](#glossary) + * [Client](#client) + * [CLI](#vesting#cli) ## Intro and Requirements @@ -628,3 +633,44 @@ all coins at a given time. according to a custom vesting schedule. * PermanentLockedAccount: It does not ever release coins, locking them indefinitely. Coins in this account can still be used for delegating and for governance votes even while locked. + + +## CLI + +A user can query and interact with the `vesting` module using the CLI. + +### Transactions + +The `tx` commands allow users to interact with the `vesting` module. + +```bash +simd tx vesting --help +``` + +#### create-periodic-vesting-account + +The `create-periodic-vesting-account` command creates a new vesting account funded with an allocation of tokens, where a sequence of coins and period length in seconds. Periods are sequential, in that the duration of of a period only starts at the end of the previous period. The duration of the first period starts upon account creation. + +```bash +simd tx vesting create-periodic-vesting-account [to_address] [periods_json_file] [flags] +``` + +Example: + +```bash +simd tx vesting create-periodic-vesting-account cosmos1.. periods.json +``` + +#### create-vesting-account + +The `create-vesting-account` command creates a new vesting account funded with an allocation of tokens. The account can either be a delayed or continuous vesting account, which is determined by the '--delayed' flag. All vesting accouts created will have their start time set by the committed block's time. The end_time must be provided as a UNIX epoch timestamp. + +```bash +simd tx vesting create-vesting-account [to_address] [amount] [end_time] [flags] +``` + +Example: + +```bash +simd tx vesting create-vesting-account cosmos1.. 100stake 2592000 +``` diff --git a/x/authz/README.md b/x/authz/README.md index a4e6fcca3c9f..ebe5bf6530bf 100644 --- a/x/authz/README.md +++ b/x/authz/README.md @@ -1,7 +1,334 @@ -# Authz +# `x/authz` -* [Authz](spec/README.md) - Authorization for accounts to perform actions on behalf of other accounts. +## Abstract + +`x/authz` is an implementation of a Cosmos SDK module, per [ADR 30](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md), that allows +granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the `Authorization` interface. + +## Contents + +* [Concepts](#concepts) + * [Authorization and Grant](#authorization-and-grant) + * [Built-in Authorizations](#built-in-authorizations) + * [Gas](#gas) +* [State](#state) + * [Grant](#grant) + * [GrantQueue](#grantqueue) +* [Messages](#messages) + * [MsgGrant](#msggrant) + * [MsgRevoke](#msgrevoke) + * [MsgExec](#msgexec) +* [Events](#events) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) + + + +# Concepts + +## Authorization and Grant + +The `x/authz` module defines interfaces and messages grant authorizations to perform actions +on behalf of one account to other accounts. The design is defined in the [ADR 030](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md). + +A *grant* is an allowance to execute a Msg by the grantee on behalf of the granter. +Authorization is an interface that must be implemented by a concrete authorization logic to validate and execute grants. Authorizations are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details. + +**Note:** The authz module is different from the [auth (authentication)](../modules/auth/) module that is responsible for specifying the base transaction and account types. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/authorizations.go#L11-L25 + +## Built-in Authorizations + +The Cosmos SDK `x/authz` module comes with following authorization types: + +### GenericAuthorization + +`GenericAuthorization` implements the `Authorization` interface that gives unrestricted permission to execute the provided Msg on behalf of granter's account. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L13-L20 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/generic_authorization.go#L16-L29 + +* `msg` stores Msg type URL. + +### SendAuthorization + +`SendAuthorization` implements the `Authorization` interface for the `cosmos.bank.v1beta1.MsgSend` Msg. It takes a (positive) `SpendLimit` that specifies the maximum amount of tokens the grantee can spend. The `SpendLimit` is updated as the tokens are spent. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/authz.proto#L10-L19 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/bank/types/send_authorization.go#L23-L38 + +* `spend_limit` keeps track of how many coins are left in the authorization. + +### StakeAuthorization + +`StakeAuthorization` implements the `Authorization` interface for messages in the [staking module](https://docs.cosmos.network/v0.44/modules/staking/). It takes an `AuthorizationType` to specify whether you want to authorise delegating, undelegating or redelegating (i.e. these have to be authorised seperately). It also takes a required `MaxTokens` that keeps track of a limit to the amount of tokens that can be delegated/undelegated/redelegated. If left empty, the amount is unlimited. Additionally, this Msg takes an `AllowList` or a `DenyList`, which allows you to select which validators you allow or deny grantees to stake with. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/authz.proto#L10-L33 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/staking/types/authz.go#L15-L35 + +## Gas + +In order to prevent DoS attacks, granting `StakeAuthorization`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK iterates over these lists and charge 10 gas for each validator in both of the lists. + +Since the state maintaining a list for granter, grantee pair with same expiration, we are iterating over the list to remove the grant (incase of any revoke of paritcular `msgType`) from the list and we are charging 20 gas per iteration. + + + +# State + +## Grant + +Grants are identified by combining granter address (the address bytes of the granter), grantee address (the address bytes of the grantee) and Authorization type (its type URL). Hence we only allow one grant for the (granter, grantee, Authorization) triple. + +* Grant: `0x01 | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes | msgType_bytes -> ProtocolBuffer(AuthorizationGrant)` + +The grant object encapsulates an `Authorization` type and an expiration timestamp: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L22-L30 + +## GrantQueue + +We are maintaining a queue for authz pruning. Whenever a grant is created, an item will be added to `GrantQueue` with a key of expiration, granter, grantee. + +* GrantQueue: `0x02 | expiration_bytes | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes -> ProtocalBuffer(GrantQueueItem)` + +The `expiration_bytes` are the expiration date in UTC with the format `"2006-01-02T15:04:05.000000000"`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/keeper/keys.go#L78-L93 + +The `GrantQueueItem` object contains the list of type urls between granter and grantee that expire at the time indicated in the key. + + + +# Messages + +In this section we describe the processing of messages for the authz module. + +## MsgGrant + +An authorization grant is created using the `MsgGrant` message. +If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant overwrites the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L32-L41 + +The message handling should fail if: + +* both granter and grantee have the same address. +* provided `Expiration` time is less than current unix timestamp (but a grant will be created if no `expiration` time is provided since `expiration` is optional). +* provided `Grant.Authorization` is not implemented. +* `Authorization.MsgTypeURL()` is not defined in the router (there is no defined handler in the app router to handle that Msg types). + +## MsgRevoke + +A grant can be removed with the `MsgRevoke` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L66-L72 + +The message handling should fail if: + +* both granter and grantee have the same address. +* provided `MsgTypeUrl` is empty. + +NOTE: The `MsgExec` message removes a grant if the grant has expired. + +## MsgExec + +When a grantee wants to execute a transaction on behalf of a granter, they must send `MsgExec`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L51-L59 + +The message handling should fail if: + +* provided `Authorization` is not implemented. +* grantee doesn't have permission to run the transaction. +* if granted authorization is expired. + + + +# Events + +The authz module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main/cosmos.authz.v1beta1#cosmos.authz.v1beta1.EventGrant). + + + +# Client + +## CLI + +A user can query and interact with the `authz` module using the CLI. + +### Query + +The `query` commands allow users to query `authz` state. + +```bash +simd query authz --help +``` + +#### grants + +The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. + +```bash +simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags] +``` + +Example: + +```bash +simd query authz grants cosmos1.. cosmos1.. /cosmos.bank.v1beta1.MsgSend +``` + +Example Output: + +```bash +grants: +- authorization: + '@type': /cosmos.bank.v1beta1.SendAuthorization + spend_limit: + - amount: "100" + denom: stake + expiration: "2022-01-01T00:00:00Z" +pagination: null +``` + +### Transactions + +The `tx` commands allow users to interact with the `authz` module. + +```bash +simd tx authz --help +``` + +#### exec + +The `exec` command allows a grantee to execute a transaction on behalf of granter. + +```bash + simd tx authz exec [tx-json-file] --from [grantee] [flags] +``` + +Example: + +```bash +simd tx authz exec tx.json --from=cosmos1.. +``` + +#### grant + +The `grant` command allows a granter to grant an authorization to a grantee. + +```bash +simd tx authz grant --from [flags] +``` + +Example: + +```bash +simd tx authz grant cosmos1.. send --spend-limit=100stake --from=cosmos1.. +``` + +#### revoke + +The `revoke` command allows a granter to revoke an authorization from a grantee. + +```bash +simd tx authz revoke [grantee] [msg-type-url] --from=[granter] [flags] +``` + +Example: + +```bash +simd tx authz revoke cosmos1.. /cosmos.bank.v1beta1.MsgSend --from=cosmos1.. +``` + +## gRPC + +A user can query the `authz` module using gRPC endpoints. + +### Grants + +The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. + +```bash +cosmos.authz.v1beta1.Query/Grants +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"granter":"cosmos1..","grantee":"cosmos1..","msg_type_url":"/cosmos.bank.v1beta1.MsgSend"}' \ + localhost:9090 \ + cosmos.authz.v1beta1.Query/Grants +``` + +Example Output: + +```bash +{ + "grants": [ + { + "authorization": { + "@type": "/cosmos.bank.v1beta1.SendAuthorization", + "spendLimit": [ + { + "denom":"stake", + "amount":"100" + } + ] + }, + "expiration": "2022-01-01T00:00:00Z" + } + ] +} +``` + +## REST + +A user can query the `authz` module using REST endpoints. + +```bash +/cosmos/authz/v1beta1/grants +``` + +Example: + +```bash +curl "localhost:1317/cosmos/authz/v1beta1/grants?granter=cosmos1..&grantee=cosmos1..&msg_type_url=/cosmos.bank.v1beta1.MsgSend" +``` + +Example Output: + +```bash +{ + "grants": [ + { + "authorization": { + "@type": "/cosmos.bank.v1beta1.SendAuthorization", + "spend_limit": [ + { + "denom": "stake", + "amount": "100" + } + ] + }, + "expiration": "2022-01-01T00:00:00Z" + } + ], + "pagination": null +} +``` diff --git a/x/authz/spec/01_concepts.md b/x/authz/spec/01_concepts.md deleted file mode 100644 index c7f678733298..000000000000 --- a/x/authz/spec/01_concepts.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# Concepts - -## Authorization and Grant - -The `x/authz` module defines interfaces and messages grant authorizations to perform actions -on behalf of one account to other accounts. The design is defined in the [ADR 030](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md). - -A *grant* is an allowance to execute a Msg by the grantee on behalf of the granter. -Authorization is an interface that must be implemented by a concrete authorization logic to validate and execute grants. Authorizations are extensible and can be defined for any Msg service method even outside of the module where the Msg method is defined. See the `SendAuthorization` example in the next section for more details. - -**Note:** The authz module is different from the [auth (authentication)](../modules/auth/) module that is responsible for specifying the base transaction and account types. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/authorizations.go#L11-L25 - -## Built-in Authorizations - -The Cosmos SDK `x/authz` module comes with following authorization types: - -### GenericAuthorization - -`GenericAuthorization` implements the `Authorization` interface that gives unrestricted permission to execute the provided Msg on behalf of granter's account. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L13-L20 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/generic_authorization.go#L16-L29 - -* `msg` stores Msg type URL. - -### SendAuthorization - -`SendAuthorization` implements the `Authorization` interface for the `cosmos.bank.v1beta1.MsgSend` Msg. It takes a (positive) `SpendLimit` that specifies the maximum amount of tokens the grantee can spend. The `SpendLimit` is updated as the tokens are spent. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/authz.proto#L10-L19 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/bank/types/send_authorization.go#L23-L38 - -* `spend_limit` keeps track of how many coins are left in the authorization. - -### StakeAuthorization - -`StakeAuthorization` implements the `Authorization` interface for messages in the [staking module](https://docs.cosmos.network/v0.44/modules/staking/). It takes an `AuthorizationType` to specify whether you want to authorise delegating, undelegating or redelegating (i.e. these have to be authorised seperately). It also takes a required `MaxTokens` that keeps track of a limit to the amount of tokens that can be delegated/undelegated/redelegated. If left empty, the amount is unlimited. Additionally, this Msg takes an `AllowList` or a `DenyList`, which allows you to select which validators you allow or deny grantees to stake with. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/authz.proto#L10-L33 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/staking/types/authz.go#L15-L35 - -## Gas - -In order to prevent DoS attacks, granting `StakeAuthorization`s with `x/authz` incurs gas. `StakeAuthorization` allows you to authorize another account to delegate, undelegate, or redelegate to validators. The authorizer can define a list of validators they allow or deny delegations to. The Cosmos SDK iterates over these lists and charge 10 gas for each validator in both of the lists. - -Since the state maintaining a list for granter, grantee pair with same expiration, we are iterating over the list to remove the grant (incase of any revoke of paritcular `msgType`) from the list and we are charging 20 gas per iteration. diff --git a/x/authz/spec/02_state.md b/x/authz/spec/02_state.md deleted file mode 100644 index d4725b62c7ad..000000000000 --- a/x/authz/spec/02_state.md +++ /dev/null @@ -1,27 +0,0 @@ - - -# State - -## Grant - -Grants are identified by combining granter address (the address bytes of the granter), grantee address (the address bytes of the grantee) and Authorization type (its type URL). Hence we only allow one grant for the (granter, grantee, Authorization) triple. - -* Grant: `0x01 | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes | msgType_bytes -> ProtocolBuffer(AuthorizationGrant)` - -The grant object encapsulates an `Authorization` type and an expiration timestamp: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/authz.proto#L22-L30 - -## GrantQueue - -We are maintaining a queue for authz pruning. Whenever a grant is created, an item will be added to `GrantQueue` with a key of expiration, granter, grantee. - -* GrantQueue: `0x02 | expiration_bytes | granter_address_len (1 byte) | granter_address_bytes | grantee_address_len (1 byte) | grantee_address_bytes -> ProtocalBuffer(GrantQueueItem)` - -The `expiration_bytes` are the expiration date in UTC with the format `"2006-01-02T15:04:05.000000000"`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/authz/keeper/keys.go#L78-L93 - -The `GrantQueueItem` object contains the list of type urls between granter and grantee that expire at the time indicated in the key. diff --git a/x/authz/spec/03_messages.md b/x/authz/spec/03_messages.md deleted file mode 100644 index 2e62b6d1ddae..000000000000 --- a/x/authz/spec/03_messages.md +++ /dev/null @@ -1,46 +0,0 @@ - - -# Messages - -In this section we describe the processing of messages for the authz module. - -## MsgGrant - -An authorization grant is created using the `MsgGrant` message. -If there is already a grant for the `(granter, grantee, Authorization)` triple, then the new grant overwrites the previous one. To update or extend an existing grant, a new grant with the same `(granter, grantee, Authorization)` triple should be created. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L32-L41 - -The message handling should fail if: - -* both granter and grantee have the same address. -* provided `Expiration` time is less than current unix timestamp (but a grant will be created if no `expiration` time is provided since `expiration` is optional). -* provided `Grant.Authorization` is not implemented. -* `Authorization.MsgTypeURL()` is not defined in the router (there is no defined handler in the app router to handle that Msg types). - -## MsgRevoke - -A grant can be removed with the `MsgRevoke` message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L66-L72 - -The message handling should fail if: - -* both granter and grantee have the same address. -* provided `MsgTypeUrl` is empty. - -NOTE: The `MsgExec` message removes a grant if the grant has expired. - -## MsgExec - -When a grantee wants to execute a transaction on behalf of a granter, they must send `MsgExec`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/authz/v1beta1/tx.proto#L51-L59 - -The message handling should fail if: - -* provided `Authorization` is not implemented. -* grantee doesn't have permission to run the transaction. -* if granted authorization is expired. diff --git a/x/authz/spec/04_events.md b/x/authz/spec/04_events.md deleted file mode 100644 index 1729b49a7dc7..000000000000 --- a/x/authz/spec/04_events.md +++ /dev/null @@ -1,7 +0,0 @@ - - -# Events - -The authz module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main/cosmos.authz.v1beta1#cosmos.authz.v1beta1.EventGrant). diff --git a/x/authz/spec/05_client.md b/x/authz/spec/05_client.md deleted file mode 100644 index f2ca6cc94690..000000000000 --- a/x/authz/spec/05_client.md +++ /dev/null @@ -1,172 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `authz` module using the CLI. - -### Query - -The `query` commands allow users to query `authz` state. - -```bash -simd query authz --help -``` - -#### grants - -The `grants` command allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. - -```bash -simd query authz grants [granter-addr] [grantee-addr] [msg-type-url]? [flags] -``` - -Example: - -```bash -simd query authz grants cosmos1.. cosmos1.. /cosmos.bank.v1beta1.MsgSend -``` - -Example Output: - -```bash -grants: -- authorization: - '@type': /cosmos.bank.v1beta1.SendAuthorization - spend_limit: - - amount: "100" - denom: stake - expiration: "2022-01-01T00:00:00Z" -pagination: null -``` - -### Transactions - -The `tx` commands allow users to interact with the `authz` module. - -```bash -simd tx authz --help -``` - -#### exec - -The `exec` command allows a grantee to execute a transaction on behalf of granter. - -```bash - simd tx authz exec [tx-json-file] --from [grantee] [flags] -``` - -Example: - -```bash -simd tx authz exec tx.json --from=cosmos1.. -``` - -#### grant - -The `grant` command allows a granter to grant an authorization to a grantee. - -```bash -simd tx authz grant --from [flags] -``` - -Example: - -```bash -simd tx authz grant cosmos1.. send --spend-limit=100stake --from=cosmos1.. -``` - -#### revoke - -The `revoke` command allows a granter to revoke an authorization from a grantee. - -```bash -simd tx authz revoke [grantee] [msg-type-url] --from=[granter] [flags] -``` - -Example: - -```bash -simd tx authz revoke cosmos1.. /cosmos.bank.v1beta1.MsgSend --from=cosmos1.. -``` - -## gRPC - -A user can query the `authz` module using gRPC endpoints. - -### Grants - -The `Grants` endpoint allows users to query grants for a granter-grantee pair. If the message type URL is set, it selects grants only for that message type. - -```bash -cosmos.authz.v1beta1.Query/Grants -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"granter":"cosmos1..","grantee":"cosmos1..","msg_type_url":"/cosmos.bank.v1beta1.MsgSend"}' \ - localhost:9090 \ - cosmos.authz.v1beta1.Query/Grants -``` - -Example Output: - -```bash -{ - "grants": [ - { - "authorization": { - "@type": "/cosmos.bank.v1beta1.SendAuthorization", - "spendLimit": [ - { - "denom":"stake", - "amount":"100" - } - ] - }, - "expiration": "2022-01-01T00:00:00Z" - } - ] -} -``` - -## REST - -A user can query the `authz` module using REST endpoints. - -```bash -/cosmos/authz/v1beta1/grants -``` - -Example: - -```bash -curl "localhost:1317/cosmos/authz/v1beta1/grants?granter=cosmos1..&grantee=cosmos1..&msg_type_url=/cosmos.bank.v1beta1.MsgSend" -``` - -Example Output: - -```bash -{ - "grants": [ - { - "authorization": { - "@type": "/cosmos.bank.v1beta1.SendAuthorization", - "spend_limit": [ - { - "denom": "stake", - "amount": "100" - } - ] - }, - "expiration": "2022-01-01T00:00:00Z" - } - ], - "pagination": null -} -``` diff --git a/x/authz/spec/README.md b/x/authz/spec/README.md deleted file mode 100644 index ac73d76dba3a..000000000000 --- a/x/authz/spec/README.md +++ /dev/null @@ -1,30 +0,0 @@ - - -# `authz` - -## Contents - -## Abstract - -`x/authz` is an implementation of a Cosmos SDK module, per [ADR 30](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-030-authz-module.md), that allows -granting arbitrary privileges from one account (the granter) to another account (the grantee). Authorizations must be granted for a particular Msg service method one by one using an implementation of the `Authorization` interface. - -1. **[Concept](01_concepts.md)** - * [Authorization and Grant](01_concepts.md#Authorization-and-Grant) - * [Built-in Authorizations](01_concepts.md#Built-in-Authorizations) - * [Gas](01_concepts.md#gas) -2. **[State](02_state.md)** -3. **[Messages](03_messages.md)** - * [MsgGrant](03_messages.md#MsgGrant) - * [MsgRevoke](03_messages.md#MsgRevoke) - * [MsgExec](03_messages.md#MsgExec) -4. **[Events](04_events.md)** -5. **[Client](05_client.md)** - * [CLI](05_client.md#cli) - * [gRPC](05_client.md#grpc) - * [REST](05_client.md#rest) diff --git a/x/bank/README.md b/x/bank/README.md index 6c1412840a0f..31645d4825b6 100644 --- a/x/bank/README.md +++ b/x/bank/README.md @@ -1,7 +1,941 @@ -# Bank +# `x/bank` -* [Bank](spec/README.md) - Token transfer functionalities. +## Abstract + +This document specifies the bank module of the Cosmos SDK. + +The bank module is responsible for handling multi-asset coin transfers between +accounts and tracking special-case pseudo-transfers which must work differently +with particular kinds of accounts (notably delegating/undelegating for vesting +accounts). It exposes several interfaces with varying capabilities for secure +interaction with other modules which must alter user balances. + +In addition, the bank module tracks and provides query support for the total +supply of all assets used in the application. + +This module is used in the Cosmos Hub. + +## Contents + +* [Supply](#supply) + * [Total Supply](#total-supply) +* [Module Accounts](#module-accounts) + * [Permissions](#permissions) +* [State](#state) +* [Params](#params) +* [Keepers](#keepers) +* [Messages](#messages) +* [Events](#events) + * [Message Events](#message-events) + * [Keeper Events](#keeper-events) +* [Parameters](#parameters) + * [SendEnabled](#sendenabled) + * [DefaultSendEnabled](#defaultsendenabled) +* [Client](#client) + * [CLI](#cli) + * [Query](#query) + * [Transactions](#transactions) +* [gRPC](#grpc) + +## Supply + +The `supply` functionality: + +* passively tracks the total supply of coins within a chain, +* provides a pattern for modules to hold/interact with `Coins`, and +* introduces the invariant check to verify a chain's total supply. + +### Total Supply + +The total `Supply` of the network is equal to the sum of all coins from the +account. The total supply is updated every time a `Coin` is minted (eg: as part +of the inflation mechanism) or burned (eg: due to slashing or if a governance +proposal is vetoed). + +## Module Accounts + +The supply functionality introduces a new type of `auth.Account` which can be used by +modules to allocate tokens and in special cases mint or burn tokens. At a base +level these module accounts are capable of sending/receiving tokens to and from +`auth.Account`s and other module accounts. This design replaces previous +alternative designs where, to hold tokens, modules would burn the incoming +tokens from the sender account, and then track those tokens internally. Later, +in order to send tokens, the module would need to effectively mint tokens +within a destination account. The new design removes duplicate logic between +modules to perform this accounting. + +The `ModuleAccount` interface is defined as follows: + +```go +type ModuleAccount interface { + auth.Account // same methods as the Account interface + + GetName() string // name of the module; used to obtain the address + GetPermissions() []string // permissions of module account + HasPermission(string) bool +} +``` + +> **WARNING!** +> Any module or message handler that allows either direct or indirect sending of funds must explicitly guarantee those funds cannot be sent to module accounts (unless allowed). + +The supply `Keeper` also introduces new wrapper functions for the auth `Keeper` +and the bank `Keeper` that are related to `ModuleAccount`s in order to be able +to: + +* Get and set `ModuleAccount`s by providing the `Name`. +* Send coins from and to other `ModuleAccount`s or standard `Account`s + (`BaseAccount` or `VestingAccount`) by passing only the `Name`. +* `Mint` or `Burn` coins for a `ModuleAccount` (restricted to its permissions). + +### Permissions + +Each `ModuleAccount` has a different set of permissions that provide different +object capabilities to perform certain actions. Permissions need to be +registered upon the creation of the supply `Keeper` so that every time a +`ModuleAccount` calls the allowed functions, the `Keeper` can lookup the +permissions to that specific account and perform or not perform the action. + +The available permissions are: + +* `Minter`: allows for a module to mint a specific amount of coins. +* `Burner`: allows for a module to burn a specific amount of coins. +* `Staking`: allows for a module to delegate and undelegate a specific amount of coins. + + + +## State + +The `x/bank` module keeps state of the following primary objects: + +1. Account balances +2. Denomination metadata +3. The total supply of all balances +4. Information on which denominations are allowed to be sent. + +In addition, the `x/bank` module keeps the following indexes to manage the +aforementioned state: + +* Supply Index: `0x0 | byte(denom) -> byte(amount)` +* Denom Metadata Index: `0x1 | byte(denom) -> ProtocolBuffer(Metadata)` +* Balances Index: `0x2 | byte(address length) | []byte(address) | []byte(balance.Denom) -> ProtocolBuffer(balance)` +* Reverse Denomination to Address Index: `0x03 | byte(denom) | 0x00 | []byte(address) -> 0` + +## Params + +The bank module stores it's params in state with the prefix of `0x05`, +it can be updated with governance or the address with authority. + +* Params: `0x05 | ProtocolBuffer(Params)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc3/proto/cosmos/bank/v1beta1/bank.proto#L11-L16 + + + +## Keepers + +The bank module provides these exported keeper interfaces that can be +passed to other modules that read or update account balances. Modules +should use the least-permissive interface that provides the functionality they +require. + +Best practices dictate careful review of `bank` module code to ensure that +permissions are limited in the way that you expect. + +### Denied Addresses + +The `x/bank` module accepts a map of addresses that are considered blocklisted +from directly and explicitly receiving funds through means such as `MsgSend` and +`MsgMultiSend` and direct API calls like `SendCoinsFromModuleToAccount`. + +Typically, these addresses are module accounts. If these addresses receive funds +outside the expected rules of the state machine, invariants are likely to be +broken and could result in a halted network. + +By providing the `x/bank` module with a blocklisted set of addresses, an error occurs for the operation if a user or client attempts to directly or indirectly send funds to a blocklisted account, for example, by using [IBC](https://ibc.cosmos.network). + +### Common Types + +#### Input + +An input of a multiparty transfer + +```protobuf +// Input models transaction input. +message Input { + string address = 1; + repeated cosmos.base.v1beta1.Coin coins = 2; +} +``` + +#### Output + +An output of a multiparty transfer. + +```protobuf +// Output models transaction outputs. +message Output { + string address = 1; + repeated cosmos.base.v1beta1.Coin coins = 2; +} +``` + +### BaseKeeper + +The base keeper provides full-permission access: the ability to arbitrary modify any account's balance and mint or burn coins. + +Restricted permission to mint per module could be achieved by using baseKeeper with `WithMintCoinsRestriction` to give specific restrictions to mint (e.g. only minting certain denom). + +```go +// Keeper defines a module interface that facilitates the transfer of coins +// between accounts. +type Keeper interface { + SendKeeper + WithMintCoinsRestriction(MintingRestrictionFn) BaseKeeper + + InitGenesis(sdk.Context, *types.GenesisState) + ExportGenesis(sdk.Context) *types.GenesisState + + GetSupply(ctx sdk.Context, denom string) sdk.Coin + HasSupply(ctx sdk.Context, denom string) bool + GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) + IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) + GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) + HasDenomMetaData(ctx sdk.Context, denom string) bool + SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) + IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) + + SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error + + DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error + UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error + + // GetAuthority gets the address capable of executing governance proposal messages. Usually the gov module account. + GetAuthority() string + + types.QueryServer +} +``` + +### SendKeeper + +The send keeper provides access to account balances and the ability to transfer coins between +accounts. The send keeper does not alter the total supply (mint or burn coins). + +```go +// SendKeeper defines a module interface that facilitates the transfer of coins +// between accounts without the possibility of creating coins. +type SendKeeper interface { + ViewKeeper + + InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error + SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error + + GetParams(ctx sdk.Context) types.Params + SetParams(ctx sdk.Context, params types.Params) error + + IsSendEnabledDenom(ctx sdk.Context, denom string) bool + SetSendEnabled(ctx sdk.Context, denom string, value bool) + SetAllSendEnabled(ctx sdk.Context, sendEnableds []*types.SendEnabled) + DeleteSendEnabled(ctx sdk.Context, denom string) + IterateSendEnabledEntries(ctx sdk.Context, cb func(denom string, sendEnabled bool) (stop bool)) + GetAllSendEnabledEntries(ctx sdk.Context) []types.SendEnabled + + IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool + IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error + + BlockedAddr(addr sdk.AccAddress) bool +} +``` + +### ViewKeeper + +The view keeper provides read-only access to account balances. The view keeper does not have balance alteration functionality. All balance lookups are `O(1)`. + +```go +// ViewKeeper defines a module interface that facilitates read only access to +// account balances. +type ViewKeeper interface { + ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error + HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool + + GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + GetAccountsBalances(ctx sdk.Context) []types.Balance + GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + SpendableCoin(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin + + IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) + IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) +} +``` + + + +## Messages + +### MsgSend + +Send coins from one address to another. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L21-L32 + +The message will fail under the following conditions: + +* The coins do not have sending enabled +* The `to` address is restricted + +### MsgMultiSend + +Send coins from and to a series of different address. If any of the receiving addresses do not correspond to an existing account, a new account is created. ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L37-L45 + +The message will fail under the following conditions: + +* Any of the coins do not have sending enabled +* Any of the `to` addresses are restricted +* Any of the coins are locked +* The inputs and outputs do not correctly correspond to one another + +### MsgUpdateParams + +The `bank` module params can be updated through `MsgUpdateParams`, which can be done using governance proposal. The signer will always be the `gov` module account address. + ++++ https://github.com/cosmos/cosmos-sdk/blob/e167855c9b99c4e58c1455533c6f88af5ff78ae1/proto/cosmos/bank/v1beta1/tx.proto#L56-L69 + +The message handling can fail if: + +* signer is not the gov module account address. + + + +## Events + +The bank module emits the following events: + +### Message Events + +#### MsgSend + +| Type | Attribute Key | Attribute Value | +| -------- | ------------- | ------------------ | +| transfer | recipient | {recipientAddress} | +| transfer | amount | {amount} | +| message | module | bank | +| message | action | send | +| message | sender | {senderAddress} | + +#### MsgMultiSend + +| Type | Attribute Key | Attribute Value | +| -------- | ------------- | ------------------ | +| transfer | recipient | {recipientAddress} | +| transfer | amount | {amount} | +| message | module | bank | +| message | action | multisend | +| message | sender | {senderAddress} | + +### Keeper Events + +In addition to message events, the bank keeper will produce events when the following methods are called (or any method which ends up calling them) + +#### MintCoins + +```json +{ + "type": "coinbase", + "attributes": [ + { + "key": "minter", + "value": "{{sdk.AccAddress of the module minting coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being minted}}", + "index": true + } + ] +} +``` + +```json +{ + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "{{sdk.AccAddress of the module minting coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being received}}", + "index": true + } + ] +} +``` + +#### BurnCoins + +```json +{ + "type": "burn", + "attributes": [ + { + "key": "burner", + "value": "{{sdk.AccAddress of the module burning coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being burned}}", + "index": true + } + ] +} +``` + +```json +{ + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "{{sdk.AccAddress of the module burning coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being burned}}", + "index": true + } + ] +} +``` + +#### addCoins + +```json +{ + "type": "coin_received", + "attributes": [ + { + "key": "receiver", + "value": "{{sdk.AccAddress of the address beneficiary of the coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being received}}", + "index": true + } + ] +} +``` + +#### subUnlockedCoins/DelegateCoins + +```json +{ + "type": "coin_spent", + "attributes": [ + { + "key": "spender", + "value": "{{sdk.AccAddress of the address which is spending coins}}", + "index": true + }, + { + "key": "amount", + "value": "{{sdk.Coins being spent}}", + "index": true + } + ] +} +``` + + + +## Parameters + +The bank module contains the following parameters + +### SendEnabled + +The SendEnabled parameter is now deprecated and not to be use. It is replaced +with state store records. + + +### DefaultSendEnabled + +The default send enabled value controls send transfer capability for all +coin denominations unless specifically included in the array of `SendEnabled` +parameters. + + + +## Client + +### CLI + +A user can query and interact with the `bank` module using the CLI. + +### Query + +The `query` commands allow users to query `bank` state. + +```sh +simd query bank --help +``` + +#### balances + +The `balances` command allows users to query account balances by address. + +```sh +simd query bank balances [address] [flags] +``` + +Example: + +```sh +simd query bank balances cosmos1.. +``` + +Example Output: + +```yml +balances: +- amount: "1000000000" + denom: stake +pagination: + next_key: null + total: "0" +``` + +#### denom-metadata + +The `denom-metadata` command allows users to query metadata for coin denominations. A user can query metadata for a single denomination using the `--denom` flag or all denominations without it. + +```sh +simd query bank denom-metadata [flags] +``` + +Example: + +```sh +simd query bank denom-metadata --denom stake +``` + +Example Output: + +```yml +metadata: + base: stake + denom_units: + - aliases: + - STAKE + denom: stake + description: native staking token of simulation app + display: stake + name: SimApp Token + symbol: STK +``` + +#### total + +The `total` command allows users to query the total supply of coins. A user can query the total supply for a single coin using the `--denom` flag or all coins without it. + +```sh +simd query bank total [flags] +``` + +Example: + +```sh +simd query bank total --denom stake +``` + +Example Output: + +```yml +amount: "10000000000" +denom: stake +``` + +#### send-enabled + +The `send-enabled` command allows users to query for all or some SendEnabled entries. + +```sh +simd query bank send-enabled [denom1 ...] [flags] +``` + +Example: + +```sh +simd query bank send-enabled +``` + +Example output: + +```yml +send_enabled: +- denom: foocoin + enabled: true +- denom: barcoin +pagination: + next-key: null + total: 2 +``` + +### Transactions + +The `tx` commands allow users to interact with the `bank` module. + +```sh +simd tx bank --help +``` + +#### send + +The `send` command allows users to send funds from one account to another. + +```sh +simd tx bank send [from_key_or_address] [to_address] [amount] [flags] +``` + +Example: + +```sh +simd tx bank send cosmos1.. cosmos1.. 100stake +``` + +## gRPC + +A user can query the `bank` module using gRPC endpoints. + +### Balance + +The `Balance` endpoint allows users to query account balance by address for a given denomination. + +```sh +cosmos.bank.v1beta1.Query/Balance +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"address":"cosmos1..","denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/Balance +``` + +Example Output: + +```json +{ + "balance": { + "denom": "stake", + "amount": "1000000000" + } +} +``` + +### AllBalances + +The `AllBalances` endpoint allows users to query account balance by address for all denominations. + +```sh +cosmos.bank.v1beta1.Query/AllBalances +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/AllBalances +``` + +Example Output: + +```json +{ + "balances": [ + { + "denom": "stake", + "amount": "1000000000" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DenomMetadata + +The `DenomMetadata` endpoint allows users to query metadata for a single coin denomination. + +```sh +cosmos.bank.v1beta1.Query/DenomMetadata +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomMetadata +``` + +Example Output: + +```json +{ + "metadata": { + "description": "native staking token of simulation app", + "denomUnits": [ + { + "denom": "stake", + "aliases": [ + "STAKE" + ] + } + ], + "base": "stake", + "display": "stake", + "name": "SimApp Token", + "symbol": "STK" + } +} +``` + +### DenomsMetadata + +The `DenomsMetadata` endpoint allows users to query metadata for all coin denominations. + +```sh +cosmos.bank.v1beta1.Query/DenomsMetadata +``` + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomsMetadata +``` + +Example Output: + +```json +{ + "metadatas": [ + { + "description": "native staking token of simulation app", + "denomUnits": [ + { + "denom": "stake", + "aliases": [ + "STAKE" + ] + } + ], + "base": "stake", + "display": "stake", + "name": "SimApp Token", + "symbol": "STK" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DenomOwners + +The `DenomOwners` endpoint allows users to query metadata for a single coin denomination. + +```sh +cosmos.bank.v1beta1.Query/DenomOwners +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/DenomOwners +``` + +Example Output: + +```json +{ + "denomOwners": [ + { + "address": "cosmos1..", + "balance": { + "denom": "stake", + "amount": "5000000000" + } + }, + { + "address": "cosmos1..", + "balance": { + "denom": "stake", + "amount": "5000000000" + } + }, + ], + "pagination": { + "total": "2" + } +} +``` + +### TotalSupply + +The `TotalSupply` endpoint allows users to query the total supply of all coins. + +```sh +cosmos.bank.v1beta1.Query/TotalSupply +``` + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/TotalSupply +``` + +Example Output: + +```json +{ + "supply": [ + { + "denom": "stake", + "amount": "10000000000" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### SupplyOf + +The `SupplyOf` endpoint allows users to query the total supply of a single coin. + +```sh +cosmos.bank.v1beta1.Query/SupplyOf +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"denom":"stake"}' \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/SupplyOf +``` + +Example Output: + +```json +{ + "amount": { + "denom": "stake", + "amount": "10000000000" + } +} +``` + +### Params + +The `Params` endpoint allows users to query the parameters of the `bank` module. + +```sh +cosmos.bank.v1beta1.Query/Params +``` + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/Params +``` + +Example Output: + +```json +{ + "params": { + "defaultSendEnabled": true + } +} +``` + +### SendEnabled + +The `SendEnabled` enpoints allows users to query the SendEnabled entries of the `bank` module. + +Any denominations NOT returned, use the `Params.DefaultSendEnabled` value. + +```sh +cosmos.bank.v1beta1.Query/SendEnabled +``` + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.bank.v1beta1.Query/SendEnabled +``` + +Example Output: + +```json +{ + "send_enabled": [ + { + "denom": "foocoin", + "enabled": true + }, + { + "denom": "barcoin" + } + ], + "pagination": { + "next-key": null, + "total": 2 + } +} +``` diff --git a/x/bank/spec/01_state.md b/x/bank/spec/01_state.md deleted file mode 100644 index 10e9902d8e4f..000000000000 --- a/x/bank/spec/01_state.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# State - -The `x/bank` module keeps state of the following primary objects: - -1. Account balances -2. Denomination metadata -3. The total supply of all balances -4. Information on which denominations are allowed to be sent. - -In addition, the `x/bank` module keeps the following indexes to manage the -aforementioned state: - -* Supply Index: `0x0 | byte(denom) -> byte(amount)` -* Denom Metadata Index: `0x1 | byte(denom) -> ProtocolBuffer(Metadata)` -* Balances Index: `0x2 | byte(address length) | []byte(address) | []byte(balance.Denom) -> ProtocolBuffer(balance)` -* Reverse Denomination to Address Index: `0x03 | byte(denom) | 0x00 | []byte(address) -> 0` - -## Params - -The bank module stores it's params in state with the prefix of `0x05`, -it can be updated with governance or the address with authority. - -* Params: `0x05 | ProtocolBuffer(Params)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc3/proto/cosmos/bank/v1beta1/bank.proto#L11-L16 diff --git a/x/bank/spec/02_keepers.md b/x/bank/spec/02_keepers.md deleted file mode 100644 index 7ccd03675eb7..000000000000 --- a/x/bank/spec/02_keepers.md +++ /dev/null @@ -1,148 +0,0 @@ - - -# Keepers - -The bank module provides these exported keeper interfaces that can be -passed to other modules that read or update account balances. Modules -should use the least-permissive interface that provides the functionality they -require. - -Best practices dictate careful review of `bank` module code to ensure that -permissions are limited in the way that you expect. - -## Blocklisting Addresses - -The `x/bank` module accepts a map of addresses that are considered blocklisted -from directly and explicitly receiving funds through means such as `MsgSend` and -`MsgMultiSend` and direct API calls like `SendCoinsFromModuleToAccount`. - -Typically, these addresses are module accounts. If these addresses receive funds -outside the expected rules of the state machine, invariants are likely to be -broken and could result in a halted network. - -By providing the `x/bank` module with a blocklisted set of addresses, an error occurs for the operation if a user or client attempts to directly or indirectly send funds to a blocklisted account, for example, by using [IBC](https://ibc.cosmos.network). - -## Common Types - -### Input - -An input of a multiparty transfer - -```protobuf -// Input models transaction input. -message Input { - string address = 1; - repeated cosmos.base.v1beta1.Coin coins = 2; -} -``` - -### Output - -An output of a multiparty transfer. - -```protobuf -// Output models transaction outputs. -message Output { - string address = 1; - repeated cosmos.base.v1beta1.Coin coins = 2; -} -``` - -## BaseKeeper - -The base keeper provides full-permission access: the ability to arbitrary modify any account's balance and mint or burn coins. - -Restricted permission to mint per module could be achieved by using baseKeeper with `WithMintCoinsRestriction` to give specific restrictions to mint (e.g. only minting certain denom). - -```go -// Keeper defines a module interface that facilitates the transfer of coins -// between accounts. -type Keeper interface { - SendKeeper - WithMintCoinsRestriction(MintingRestrictionFn) BaseKeeper - - InitGenesis(sdk.Context, *types.GenesisState) - ExportGenesis(sdk.Context) *types.GenesisState - - GetSupply(ctx sdk.Context, denom string) sdk.Coin - HasSupply(ctx sdk.Context, denom string) bool - GetPaginatedTotalSupply(ctx sdk.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) - IterateTotalSupply(ctx sdk.Context, cb func(sdk.Coin) bool) - GetDenomMetaData(ctx sdk.Context, denom string) (types.Metadata, bool) - HasDenomMetaData(ctx sdk.Context, denom string) bool - SetDenomMetaData(ctx sdk.Context, denomMetaData types.Metadata) - IterateAllDenomMetaData(ctx sdk.Context, cb func(types.Metadata) bool) - - SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error - SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error - SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - DelegateCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error - UndelegateCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error - MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error - - DelegateCoins(ctx sdk.Context, delegatorAddr, moduleAccAddr sdk.AccAddress, amt sdk.Coins) error - UndelegateCoins(ctx sdk.Context, moduleAccAddr, delegatorAddr sdk.AccAddress, amt sdk.Coins) error - - // GetAuthority gets the address capable of executing governance proposal messages. Usually the gov module account. - GetAuthority() string - - types.QueryServer -} -``` - -## SendKeeper - -The send keeper provides access to account balances and the ability to transfer coins between -accounts. The send keeper does not alter the total supply (mint or burn coins). - -```go -// SendKeeper defines a module interface that facilitates the transfer of coins -// between accounts without the possibility of creating coins. -type SendKeeper interface { - ViewKeeper - - InputOutputCoins(ctx sdk.Context, inputs []types.Input, outputs []types.Output) error - SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error - - GetParams(ctx sdk.Context) types.Params - SetParams(ctx sdk.Context, params types.Params) error - - IsSendEnabledDenom(ctx sdk.Context, denom string) bool - SetSendEnabled(ctx sdk.Context, denom string, value bool) - SetAllSendEnabled(ctx sdk.Context, sendEnableds []*types.SendEnabled) - DeleteSendEnabled(ctx sdk.Context, denom string) - IterateSendEnabledEntries(ctx sdk.Context, cb func(denom string, sendEnabled bool) (stop bool)) - GetAllSendEnabledEntries(ctx sdk.Context) []types.SendEnabled - - IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool - IsSendEnabledCoins(ctx sdk.Context, coins ...sdk.Coin) error - - BlockedAddr(addr sdk.AccAddress) bool -} -``` - -## ViewKeeper - -The view keeper provides read-only access to account balances. The view keeper does not have balance alteration functionality. All balance lookups are `O(1)`. - -```go -// ViewKeeper defines a module interface that facilitates read only access to -// account balances. -type ViewKeeper interface { - ValidateBalance(ctx sdk.Context, addr sdk.AccAddress) error - HasBalance(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coin) bool - - GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - GetAccountsBalances(ctx sdk.Context) []types.Balance - GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - SpendableCoin(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - - IterateAccountBalances(ctx sdk.Context, addr sdk.AccAddress, cb func(coin sdk.Coin) (stop bool)) - IterateAllBalances(ctx sdk.Context, cb func(address sdk.AccAddress, coin sdk.Coin) (stop bool)) -} -``` diff --git a/x/bank/spec/03_messages.md b/x/bank/spec/03_messages.md deleted file mode 100644 index 8f07f88ecbe6..000000000000 --- a/x/bank/spec/03_messages.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Messages - -## MsgSend - -Send coins from one address to another. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L21-L32 - -The message will fail under the following conditions: - -* The coins do not have sending enabled -* The `to` address is restricted - -## MsgMultiSend - -Send coins from and to a series of different address. If any of the receiving addresses do not correspond to an existing account, a new account is created. -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/bank/v1beta1/tx.proto#L37-L45 - -The message will fail under the following conditions: - -* Any of the coins do not have sending enabled -* Any of the `to` addresses are restricted -* Any of the coins are locked -* The inputs and outputs do not correctly correspond to one another - -## MsgUpdateParams - -The `bank` module params can be updated through `MsgUpdateParams`, which can be done using governance proposal. The signer will always be the `gov` module account address. - -+++ https://github.com/cosmos/cosmos-sdk/blob/e167855c9b99c4e58c1455533c6f88af5ff78ae1/proto/cosmos/bank/v1beta1/tx.proto#L56-L69 - -The message handling can fail if: - -* signer is not the gov module account address. diff --git a/x/bank/spec/04_events.md b/x/bank/spec/04_events.md deleted file mode 100644 index e71b820571ab..000000000000 --- a/x/bank/spec/04_events.md +++ /dev/null @@ -1,149 +0,0 @@ - - -# Events - -The bank module emits the following events: - -## Handlers - -### MsgSend - -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| transfer | recipient | {recipientAddress} | -| transfer | amount | {amount} | -| message | module | bank | -| message | action | send | -| message | sender | {senderAddress} | - -### MsgMultiSend - -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| transfer | recipient | {recipientAddress} | -| transfer | amount | {amount} | -| message | module | bank | -| message | action | multisend | -| message | sender | {senderAddress} | - -## Keeper events - -In addition to handlers events, the bank keeper will produce events when the following methods are called (or any method which ends up calling them) - -### MintCoins - -```json -{ - "type": "coinbase", - "attributes": [ - { - "key": "minter", - "value": "{{sdk.AccAddress of the module minting coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being minted}}", - "index": true - } - ] -} -``` - -```json -{ - "type": "coin_received", - "attributes": [ - { - "key": "receiver", - "value": "{{sdk.AccAddress of the module minting coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being received}}", - "index": true - } - ] -} -``` - -### BurnCoins - -```json -{ - "type": "burn", - "attributes": [ - { - "key": "burner", - "value": "{{sdk.AccAddress of the module burning coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being burned}}", - "index": true - } - ] -} -``` - -```json -{ - "type": "coin_spent", - "attributes": [ - { - "key": "spender", - "value": "{{sdk.AccAddress of the module burning coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being burned}}", - "index": true - } - ] -} -``` - -### addCoins - -```json -{ - "type": "coin_received", - "attributes": [ - { - "key": "receiver", - "value": "{{sdk.AccAddress of the address beneficiary of the coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being received}}", - "index": true - } - ] -} -``` - -### subUnlockedCoins/DelegateCoins - -```json -{ - "type": "coin_spent", - "attributes": [ - { - "key": "spender", - "value": "{{sdk.AccAddress of the address which is spending coins}}", - "index": true - }, - { - "key": "amount", - "value": "{{sdk.Coins being spent}}", - "index": true - } - ] -} -``` diff --git a/x/bank/spec/05_params.md b/x/bank/spec/05_params.md deleted file mode 100644 index d7a74a29bf2e..000000000000 --- a/x/bank/spec/05_params.md +++ /dev/null @@ -1,24 +0,0 @@ - - -# Parameters - -The bank module contains the following parameters: - -| Key | Type | Example | -| ------------------ | ------------- |--------------| -| SendEnabled | []SendEnabled | (deprecated) | -| DefaultSendEnabled | bool | true | - -## SendEnabled - -The SendEnabled parameter is now deprecated and not to be use. It is replaced -with state store records. - - -## DefaultSendEnabled - -The default send enabled value controls send transfer capability for all -coin denominations unless specifically included in the array of `SendEnabled` -parameters. diff --git a/x/bank/spec/06_client.md b/x/bank/spec/06_client.md deleted file mode 100644 index 28e128768ac5..000000000000 --- a/x/bank/spec/06_client.md +++ /dev/null @@ -1,454 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `bank` module using the CLI. - -### Query - -The `query` commands allow users to query `bank` state. - -```sh -simd query bank --help -``` - -#### balances - -The `balances` command allows users to query account balances by address. - -```sh -simd query bank balances [address] [flags] -``` - -Example: - -```sh -simd query bank balances cosmos1.. -``` - -Example Output: - -```yml -balances: -- amount: "1000000000" - denom: stake -pagination: - next_key: null - total: "0" -``` - -#### denom-metadata - -The `denom-metadata` command allows users to query metadata for coin denominations. A user can query metadata for a single denomination using the `--denom` flag or all denominations without it. - -```sh -simd query bank denom-metadata [flags] -``` - -Example: - -```sh -simd query bank denom-metadata --denom stake -``` - -Example Output: - -```yml -metadata: - base: stake - denom_units: - - aliases: - - STAKE - denom: stake - description: native staking token of simulation app - display: stake - name: SimApp Token - symbol: STK -``` - -#### total - -The `total` command allows users to query the total supply of coins. A user can query the total supply for a single coin using the `--denom` flag or all coins without it. - -```sh -simd query bank total [flags] -``` - -Example: - -```sh -simd query bank total --denom stake -``` - -Example Output: - -```yml -amount: "10000000000" -denom: stake -``` - -#### send-enabled - -The `send-enabled` command allows users to query for all or some SendEnabled entries. - -```sh -simd query bank send-enabled [denom1 ...] [flags] -``` - -Example: - -```sh -simd query bank send-enabled -``` - -Example output: - -```yml -send_enabled: -- denom: foocoin - enabled: true -- denom: barcoin -pagination: - next-key: null - total: 2 -``` - -### Transactions - -The `tx` commands allow users to interact with the `bank` module. - -```sh -simd tx bank --help -``` - -#### send - -The `send` command allows users to send funds from one account to another. - -```sh -simd tx bank send [from_key_or_address] [to_address] [amount] [flags] -``` - -Example: - -```sh -simd tx bank send cosmos1.. cosmos1.. 100stake -``` - -## gRPC - -A user can query the `bank` module using gRPC endpoints. - -### Balance - -The `Balance` endpoint allows users to query account balance by address for a given denomination. - -```sh -cosmos.bank.v1beta1.Query/Balance -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"address":"cosmos1..","denom":"stake"}' \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/Balance -``` - -Example Output: - -```json -{ - "balance": { - "denom": "stake", - "amount": "1000000000" - } -} -``` - -### AllBalances - -The `AllBalances` endpoint allows users to query account balance by address for all denominations. - -```sh -cosmos.bank.v1beta1.Query/AllBalances -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/AllBalances -``` - -Example Output: - -```json -{ - "balances": [ - { - "denom": "stake", - "amount": "1000000000" - } - ], - "pagination": { - "total": "1" - } -} -``` - -### DenomMetadata - -The `DenomMetadata` endpoint allows users to query metadata for a single coin denomination. - -```sh -cosmos.bank.v1beta1.Query/DenomMetadata -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"denom":"stake"}' \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/DenomMetadata -``` - -Example Output: - -```json -{ - "metadata": { - "description": "native staking token of simulation app", - "denomUnits": [ - { - "denom": "stake", - "aliases": [ - "STAKE" - ] - } - ], - "base": "stake", - "display": "stake", - "name": "SimApp Token", - "symbol": "STK" - } -} -``` - -### DenomsMetadata - -The `DenomsMetadata` endpoint allows users to query metadata for all coin denominations. - -```sh -cosmos.bank.v1beta1.Query/DenomsMetadata -``` - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/DenomsMetadata -``` - -Example Output: - -```json -{ - "metadatas": [ - { - "description": "native staking token of simulation app", - "denomUnits": [ - { - "denom": "stake", - "aliases": [ - "STAKE" - ] - } - ], - "base": "stake", - "display": "stake", - "name": "SimApp Token", - "symbol": "STK" - } - ], - "pagination": { - "total": "1" - } -} -``` - -### DenomOwners - -The `DenomOwners` endpoint allows users to query metadata for a single coin denomination. - -```sh -cosmos.bank.v1beta1.Query/DenomOwners -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"denom":"stake"}' \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/DenomOwners -``` - -Example Output: - -```json -{ - "denomOwners": [ - { - "address": "cosmos1..", - "balance": { - "denom": "stake", - "amount": "5000000000" - } - }, - { - "address": "cosmos1..", - "balance": { - "denom": "stake", - "amount": "5000000000" - } - }, - ], - "pagination": { - "total": "2" - } -} -``` - -### TotalSupply - -The `TotalSupply` endpoint allows users to query the total supply of all coins. - -```sh -cosmos.bank.v1beta1.Query/TotalSupply -``` - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/TotalSupply -``` - -Example Output: - -```json -{ - "supply": [ - { - "denom": "stake", - "amount": "10000000000" - } - ], - "pagination": { - "total": "1" - } -} -``` - -### SupplyOf - -The `SupplyOf` endpoint allows users to query the total supply of a single coin. - -```sh -cosmos.bank.v1beta1.Query/SupplyOf -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"denom":"stake"}' \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/SupplyOf -``` - -Example Output: - -```json -{ - "amount": { - "denom": "stake", - "amount": "10000000000" - } -} -``` - -### Params - -The `Params` endpoint allows users to query the parameters of the `bank` module. - -```sh -cosmos.bank.v1beta1.Query/Params -``` - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/Params -``` - -Example Output: - -```json -{ - "params": { - "defaultSendEnabled": true - } -} -``` - -### SendEnabled - -The `SendEnabled` enpoints allows users to query the SendEnabled entries of the `bank` module. - -Any denominations NOT returned, use the `Params.DefaultSendEnabled` value. - -```sh -cosmos.bank.v1beta1.Query/SendEnabled -``` - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.bank.v1beta1.Query/SendEnabled -``` - -Example Output: - -```json -{ - "send_enabled": [ - { - "denom": "foocoin", - "enabled": true - }, - { - "denom": "barcoin" - } - ], - "pagination": { - "next-key": null, - "total": 2 - } -} -``` \ No newline at end of file diff --git a/x/bank/spec/README.md b/x/bank/spec/README.md deleted file mode 100644 index ce0d9e8e0cf0..000000000000 --- a/x/bank/spec/README.md +++ /dev/null @@ -1,106 +0,0 @@ - - -# `x/bank` - -## Abstract - -This document specifies the bank module of the Cosmos SDK. - -The bank module is responsible for handling multi-asset coin transfers between -accounts and tracking special-case pseudo-transfers which must work differently -with particular kinds of accounts (notably delegating/undelegating for vesting -accounts). It exposes several interfaces with varying capabilities for secure -interaction with other modules which must alter user balances. - -In addition, the bank module tracks and provides query support for the total -supply of all assets used in the application. - -This module will be used in the Cosmos Hub. - -## Supply - -The `supply` functionality: - -* passively tracks the total supply of coins within a chain, -* provides a pattern for modules to hold/interact with `Coins`, and -* introduces the invariant check to verify a chain's total supply. - -### Total Supply - -The total `Supply` of the network is equal to the sum of all coins from the -account. The total supply is updated every time a `Coin` is minted (eg: as part -of the inflation mechanism) or burned (eg: due to slashing or if a governance -proposal is vetoed). - -## Module Accounts - -The supply functionality introduces a new type of `auth.Account` which can be used by -modules to allocate tokens and in special cases mint or burn tokens. At a base -level these module accounts are capable of sending/receiving tokens to and from -`auth.Account`s and other module accounts. This design replaces previous -alternative designs where, to hold tokens, modules would burn the incoming -tokens from the sender account, and then track those tokens internally. Later, -in order to send tokens, the module would need to effectively mint tokens -within a destination account. The new design removes duplicate logic between -modules to perform this accounting. - -The `ModuleAccount` interface is defined as follows: - -```go -type ModuleAccount interface { - auth.Account // same methods as the Account interface - - GetName() string // name of the module; used to obtain the address - GetPermissions() []string // permissions of module account - HasPermission(string) bool -} -``` - -> **WARNING!** -> Any module or message handler that allows either direct or indirect sending of funds must explicitly guarantee those funds cannot be sent to module accounts (unless allowed). - -The supply `Keeper` also introduces new wrapper functions for the auth `Keeper` -and the bank `Keeper` that are related to `ModuleAccount`s in order to be able -to: - -* Get and set `ModuleAccount`s by providing the `Name`. -* Send coins from and to other `ModuleAccount`s or standard `Account`s - (`BaseAccount` or `VestingAccount`) by passing only the `Name`. -* `Mint` or `Burn` coins for a `ModuleAccount` (restricted to its permissions). - -### Permissions - -Each `ModuleAccount` has a different set of permissions that provide different -object capabilities to perform certain actions. Permissions need to be -registered upon the creation of the supply `Keeper` so that every time a -`ModuleAccount` calls the allowed functions, the `Keeper` can lookup the -permissions to that specific account and perform or not perform the action. - -The available permissions are: - -* `Minter`: allows for a module to mint a specific amount of coins. -* `Burner`: allows for a module to burn a specific amount of coins. -* `Staking`: allows for a module to delegate and undelegate a specific amount of coins. - -## Contents - -1. **[State](01_state.md)** -2. **[Keepers](02_keepers.md)** - * [Common Types](02_keepers.md#common-types) - * [BaseKeeper](02_keepers.md#basekeeper) - * [SendKeeper](02_keepers.md#sendkeeper) - * [ViewKeeper](02_keepers.md#viewkeeper) -3. **[Messages](03_messages.md)** - * [MsgSend](03_messages.md#msgsend) - * [MsgMultiSend](03_messages.md#msgmultisend) -4. **[Events](04_events.md)** - * [Handlers](04_events.md#handlers) -5. **[Parameters](05_params.md)** -6. **[Client](06_client.md)** - * [CLI](06_client.md#cli) - * [gRPC](06_client.md#grpc) diff --git a/x/capability/README.md b/x/capability/README.md index 258df71fbf7a..3a8d00e0f957 100644 --- a/x/capability/README.md +++ b/x/capability/README.md @@ -1,7 +1,141 @@ -# Capability +# `x/capability` -* [Capability](spec/README.md) - Object capability implementation. +## Overview + +`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-003-dynamic-capability-store.md), +that allows for provisioning, tracking, and authenticating multi-owner capabilities +at runtime. + +The keeper maintains two states: persistent and ephemeral in-memory. The persistent +store maintains a globally unique auto-incrementing index and a mapping from +capability index to a set of capability owners that are defined as a module and +capability name tuple. The in-memory ephemeral state keeps track of the actual +capabilities, represented as addresses in local memory, with both forward and reverse indexes. +The forward index maps module name and capability tuples to the capability name. The +reverse index maps between the module and capability name and the capability itself. + +The keeper allows the creation of "scoped" sub-keepers which are tied to a particular +module by name. Scoped keepers must be created at application initialization and +passed to modules, which can then use them to claim capabilities they receive and +retrieve capabilities which they own by name, in addition to creating new capabilities +& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope, +so a module cannot interfere with or inspect capabilities owned by other modules. + +The keeper provides no other core functionality that can be found in other modules +like queriers, REST and CLI handlers, and genesis state. + +## Initialization + +During application initialization, the keeper must be instantiated with a persistent +store key and an in-memory store key. + +```go +type App struct { + // ... + + capabilityKeeper *capability.Keeper +} + +func NewApp(...) *App { + // ... + + app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey) +} +``` + +After the keeper is created, it can be used to create scoped sub-keepers which +are passed to other modules that can create, authenticate, and claim capabilities. +After all the necessary scoped keepers are created and the state is loaded, the +main capability keeper must be sealed to prevent further scoped keepers from +being created. + +```go +func NewApp(...) *App { + // ... + + // Creating a scoped keeper + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) + + // Seal the capability keeper to prevent any further modules from creating scoped + // sub-keepers. + app.capabilityKeeper.Seal() + + return app +} +``` + +## Contents + +* [Concepts](#concepts) + * [Capabilities](#capabilities) + * [Stores](#stores) +* [State](#state) + * [In persisted KV store](#in-persisted-kv-store) + * [In-memory KV store](#in-memory-kv-store) + + + +# Concepts + +## Capabilities + +Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` +which creates a new unique, unforgeable object-capability reference. The newly +created capability is automatically persisted; the calling module need not call +`ClaimCapability`. Calling `NewCapability` will create the capability with the +calling module and name as a tuple to be treated the capabilities first owner. + +Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` +allows a module to claim a capability key which it has received from another +module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST +be called if a module which receives a capability wishes to access it by name in +the future. Again, capabilities are multi-owner, so if multiple modules have a +single Capability reference, they will all own it. If a module receives a capability +from another module but does not call `ClaimCapability`, it may use it in the executing +transaction but will not be able to access it afterwards. + +`AuthenticateCapability` can be called by any module to check that a capability +does in fact correspond to a particular name (the name can be un-trusted user input) +with which the calling module previously associated it. + +`GetCapability` allows a module to fetch a capability which it has previously +claimed by name. The module is not allowed to retrieve capabilities which it does +not own. + +## Stores + +* MemStore +* KeyStore + + + +# State + +## In persisted KV store + +1. Global unique capability index +2. Capability owners + +Indexes: + +* Unique index: `[]byte("index") -> []byte(currentGlobalIndex)` +* Capability Index: `[]byte("capability_index") | []byte(index) -> ProtocolBuffer(CapabilityOwners)` + +## In-memory KV store + +1. Initialized flag +2. Mapping between the module and capability tuple and the capability name +3. Mapping between the module and capability name and its index + +Indexes: + +* Initialized flag: `[]byte("mem_initialized")` +* RevCapabilityKey: `[]byte(moduleName + "/rev/" + capabilityName) -> []byte(index)` +* FwdCapabilityKey: `[]byte(moduleName + "/fwd/" + capabilityPointerAddress) -> []byte(capabilityName)` diff --git a/x/capability/spec/01_concepts.md b/x/capability/spec/01_concepts.md deleted file mode 100644 index 93ecb6354ac7..000000000000 --- a/x/capability/spec/01_concepts.md +++ /dev/null @@ -1,35 +0,0 @@ - - -# Concepts - -## Capabilities - -Capabilities are multi-owner. A scoped keeper can create a capability via `NewCapability` -which creates a new unique, unforgeable object-capability reference. The newly -created capability is automatically persisted; the calling module need not call -`ClaimCapability`. Calling `NewCapability` will create the capability with the -calling module and name as a tuple to be treated the capabilities first owner. - -Capabilities can be claimed by other modules which add them as owners. `ClaimCapability` -allows a module to claim a capability key which it has received from another -module so that future `GetCapability` calls will succeed. `ClaimCapability` MUST -be called if a module which receives a capability wishes to access it by name in -the future. Again, capabilities are multi-owner, so if multiple modules have a -single Capability reference, they will all own it. If a module receives a capability -from another module but does not call `ClaimCapability`, it may use it in the executing -transaction but will not be able to access it afterwards. - -`AuthenticateCapability` can be called by any module to check that a capability -does in fact correspond to a particular name (the name can be un-trusted user input) -with which the calling module previously associated it. - -`GetCapability` allows a module to fetch a capability which it has previously -claimed by name. The module is not allowed to retrieve capabilities which it does -not own. - -## Stores - -* MemStore -* KeyStore diff --git a/x/capability/spec/02_state.md b/x/capability/spec/02_state.md deleted file mode 100644 index 3ab713bdb90d..000000000000 --- a/x/capability/spec/02_state.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# State -## In persisted KV store - -1. Global unique capability index -2. Capability owners - -Indexes: - -* Unique index: `[]byte("index") -> []byte(currentGlobalIndex)` -* Capability Index: `[]byte("capability_index") | []byte(index) -> ProtocolBuffer(CapabilityOwners)` - -## In-memory KV store - -1. Initialized flag -2. Mapping between the module and capability tuple and the capability name -3. Mapping between the module and capability name and its index - -Indexes: - -* Initialized flag: `[]byte("mem_initialized")` -* RevCapabilityKey: `[]byte(moduleName + "/rev/" + capabilityName) -> []byte(index)` -* FwdCapabilityKey: `[]byte(moduleName + "/fwd/" + capabilityPointerAddress) -> []byte(capabilityName)` diff --git a/x/capability/spec/README.md b/x/capability/spec/README.md deleted file mode 100644 index 96a2dcbd9726..000000000000 --- a/x/capability/spec/README.md +++ /dev/null @@ -1,77 +0,0 @@ - - -# `capability` - -## Overview - -`x/capability` is an implementation of a Cosmos SDK module, per [ADR 003](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-003-dynamic-capability-store.md), -that allows for provisioning, tracking, and authenticating multi-owner capabilities -at runtime. - -The keeper maintains two states: persistent and ephemeral in-memory. The persistent -store maintains a globally unique auto-incrementing index and a mapping from -capability index to a set of capability owners that are defined as a module and -capability name tuple. The in-memory ephemeral state keeps track of the actual -capabilities, represented as addresses in local memory, with both forward and reverse indexes. -The forward index maps module name and capability tuples to the capability name. The -reverse index maps between the module and capability name and the capability itself. - -The keeper allows the creation of "scoped" sub-keepers which are tied to a particular -module by name. Scoped keepers must be created at application initialization and -passed to modules, which can then use them to claim capabilities they receive and -retrieve capabilities which they own by name, in addition to creating new capabilities -& authenticating capabilities passed by other modules. A scoped keeper cannot escape its scope, -so a module cannot interfere with or inspect capabilities owned by other modules. - -The keeper provides no other core functionality that can be found in other modules -like queriers, REST and CLI handlers, and genesis state. - -## Initialization - -During application initialization, the keeper must be instantiated with a persistent -store key and an in-memory store key. - -```go -type App struct { - // ... - - capabilityKeeper *capability.Keeper -} - -func NewApp(...) *App { - // ... - - app.capabilityKeeper = capability.NewKeeper(codec, persistentStoreKey, memStoreKey) -} -``` - -After the keeper is created, it can be used to create scoped sub-keepers which -are passed to other modules that can create, authenticate, and claim capabilities. -After all the necessary scoped keepers are created and the state is loaded, the -main capability keeper must be sealed to prevent further scoped keepers from -being created. - -```go -func NewApp(...) *App { - // ... - - // Creating a scoped keeper - scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibchost.ModuleName) - - // Seal the capability keeper to prevent any further modules from creating scoped - // sub-keepers. - app.capabilityKeeper.Seal() - - return app -} -``` - -## Contents - -1. **[Concepts](01_concepts.md)** -1. **[State](02_state.md)** diff --git a/x/crisis/README.md b/x/crisis/README.md index e67297b0852e..03650f4c16aa 100644 --- a/x/crisis/README.md +++ b/x/crisis/README.md @@ -1,7 +1,119 @@ -# Crisis +# `x/crisis` -* [Crisis](spec/README.md) - Halting the blockchain under certain circumstances (e.g. if an invariant is broken). +## Overview + +The crisis module halts the blockchain under the circumstance that a blockchain +invariant is broken. Invariants can be registered with the application during the +application initialization process. + +## Contents + +* [State](#state) +* [Messages](#messages) +* [Events](#events) +* [Parameters](#parameters) +* [Client](#client) + * [CLI](#cli) + + + +# State + +## ConstantFee + +Due to the anticipated large gas cost requirement to verify an invariant (and +potential to exceed the maximum allowable block gas limit) a constant fee is +used instead of the standard gas consumption method. The constant fee is +intended to be larger than the anticipated gas cost of running the invariant +with the standard gas consumption method. + +The ConstantFee param is stored in the module params state with the prefix of `0x01`, +it can be updated with governance or the address with authority. + +* Params: `mint/params -> legacy_amino(sdk.Coin)` + + + +# Messages + +In this section we describe the processing of the crisis messages and the +corresponding updates to the state. + +## MsgVerifyInvariant + +Blockchain invariants can be checked using the `MsgVerifyInvariant` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/crisis/v1beta1/tx.proto#L16-L26 + +This message is expected to fail if: + +* the sender does not have enough coins for the constant fee +* the invariant route is not registered + +This message checks the invariant provided, and if the invariant is broken it +panics, halting the blockchain. If the invariant is broken, the constant fee is +never deducted as the transaction is never committed to a block (equivalent to +being refunded). However, if the invariant is not broken, the constant fee will +not be refunded. + + + +# Events + +The crisis module emits the following events: + +## Handlers + +### MsgVerifyInvariance + +| Type | Attribute Key | Attribute Value | +|-----------|---------------|------------------| +| invariant | route | {invariantRoute} | +| message | module | crisis | +| message | action | verify_invariant | +| message | sender | {senderAddress} | + +# Parameters + +The crisis module contains the following parameters: + +| Key | Type | Example | +|-------------|---------------|-----------------------------------| +| ConstantFee | object (coin) | {"denom":"uatom","amount":"1000"} | + + + +# Client + +## CLI + +A user can query and interact with the `crisis` module using the CLI. + +### Transactions + +The `tx` commands allow users to interact with the `crisis` module. + +```bash +simd tx crisis --help +``` + +#### invariant-broken + +The `invariant-broken` command submits proof when an invariant was broken to halt the chain + +```bash +simd tx crisis invariant-broken [module-name] [invariant-route] [flags] +``` + +Example: + +```bash +simd tx crisis invariant-broken bank total-supply --from=[keyname or address] +``` diff --git a/x/crisis/spec/01_state.md b/x/crisis/spec/01_state.md deleted file mode 100644 index 65fb0d611942..000000000000 --- a/x/crisis/spec/01_state.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# State - -## ConstantFee - -Due to the anticipated large gas cost requirement to verify an invariant (and -potential to exceed the maximum allowable block gas limit) a constant fee is -used instead of the standard gas consumption method. The constant fee is -intended to be larger than the anticipated gas cost of running the invariant -with the standard gas consumption method. - -The ConstantFee param is stored in the module params state with the prefix of `0x01`, -it can be updated with governance or the address with authority. - -* Params: `mint/params -> legacy_amino(sdk.Coin)` diff --git a/x/crisis/spec/02_messages.md b/x/crisis/spec/02_messages.md deleted file mode 100644 index cab3ff82375c..000000000000 --- a/x/crisis/spec/02_messages.md +++ /dev/null @@ -1,25 +0,0 @@ - - -# Messages - -In this section we describe the processing of the crisis messages and the -corresponding updates to the state. - -## MsgVerifyInvariant - -Blockchain invariants can be checked using the `MsgVerifyInvariant` message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/crisis/v1beta1/tx.proto#L16-L26 - -This message is expected to fail if: - -* the sender does not have enough coins for the constant fee -* the invariant route is not registered - -This message checks the invariant provided, and if the invariant is broken it -panics, halting the blockchain. If the invariant is broken, the constant fee is -never deducted as the transaction is never committed to a block (equivalent to -being refunded). However, if the invariant is not broken, the constant fee will -not be refunded. diff --git a/x/crisis/spec/03_events.md b/x/crisis/spec/03_events.md deleted file mode 100644 index 5aef2078ebf9..000000000000 --- a/x/crisis/spec/03_events.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# Events - -The crisis module emits the following events: - -## Handlers - -### MsgVerifyInvariance - -| Type | Attribute Key | Attribute Value | -|-----------|---------------|------------------| -| invariant | route | {invariantRoute} | -| message | module | crisis | -| message | action | verify_invariant | -| message | sender | {senderAddress} | diff --git a/x/crisis/spec/04_params.md b/x/crisis/spec/04_params.md deleted file mode 100644 index 0d046adaa5e3..000000000000 --- a/x/crisis/spec/04_params.md +++ /dev/null @@ -1,11 +0,0 @@ - - -# Parameters - -The crisis module contains the following parameters: - -| Key | Type | Example | -|-------------|---------------|-----------------------------------| -| ConstantFee | object (coin) | {"denom":"uatom","amount":"1000"} | diff --git a/x/crisis/spec/05_client.md b/x/crisis/spec/05_client.md deleted file mode 100644 index 5f95955a65eb..000000000000 --- a/x/crisis/spec/05_client.md +++ /dev/null @@ -1,31 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `crisis` module using the CLI. - -### Transactions - -The `tx` commands allow users to interact with the `crisis` module. - -```bash -simd tx crisis --help -``` - -#### invariant-broken - -The `invariant-broken` command submits proof when an invariant was broken to halt the chain - -```bash -simd tx crisis invariant-broken [module-name] [invariant-route] [flags] -``` - -Example: - -```bash -simd tx crisis invariant-broken bank total-supply --from=[keyname or address] -``` diff --git a/x/crisis/spec/README.md b/x/crisis/spec/README.md deleted file mode 100644 index 79d688b4168f..000000000000 --- a/x/crisis/spec/README.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# `crisis` - -## Overview - -The crisis module halts the blockchain under the circumstance that a blockchain -invariant is broken. Invariants can be registered with the application during the -application initialization process. - -## Contents - -1. **[State](01_state.md)** - * [ConstantFee](01_state.md#constantfee) -2. **[Messages](02_messages.md)** - * [MsgVerifyInvariant](02_messages.md#msgverifyinvariant) -3. **[Events](03_events.md)** - * [Handlers](03_events.md#handlers) -4. **[Parameters](04_params.md)** -5. **[Client](05_client.md)** - * [CLI](05_client.md#cli) diff --git a/x/distribution/README.md b/x/distribution/README.md index 2c542da71611..006c7f66153a 100644 --- a/x/distribution/README.md +++ b/x/distribution/README.md @@ -1,7 +1,997 @@ -# Distribution +# `x/distribution` -* [Distribution](spec/README.md) - Fee distribution, and staking token provision distribution. +## Overview + +This _simple_ distribution mechanism describes a functional way to passively +distribute rewards between validators and delegators. Note that this mechanism does +not distribute funds in as precisely as active reward distribution mechanisms and +will therefore be upgraded in the future. + +The mechanism operates as follows. Collected rewards are pooled globally and +divided out passively to validators and delegators. Each validator has the +opportunity to charge commission to the delegators on the rewards collected on +behalf of the delegators. Fees are collected directly into a global reward pool +and validator proposer-reward pool. Due to the nature of passive accounting, +whenever changes to parameters which affect the rate of reward distribution +occurs, withdrawal of rewards must also occur. + +* Whenever withdrawing, one must withdraw the maximum amount they are entitled + to, leaving nothing in the pool. +* Whenever bonding, unbonding, or re-delegating tokens to an existing account, a + full withdrawal of the rewards must occur (as the rules for lazy accounting + change). +* Whenever a validator chooses to change the commission on rewards, all accumulated + commission rewards must be simultaneously withdrawn. + +The above scenarios are covered in `hooks.md`. + +The distribution mechanism outlined herein is used to lazily distribute the +following rewards between validators and associated delegators: + +* multi-token fees to be socially distributed +* inflated staked asset provisions +* validator commission on all rewards earned by their delegators stake + +Fees are pooled within a global pool. The mechanisms used allow for validators +and delegators to independently and lazily withdraw their rewards. + +## Shortcomings + +As a part of the lazy computations, each delegator holds an accumulation term +specific to each validator which is used to estimate what their approximate +fair portion of tokens held in the global fee pool is owed to them. + +```text +entitlement = delegator-accumulation / all-delegators-accumulation +``` + +Under the circumstance that there was constant and equal flow of incoming +reward tokens every block, this distribution mechanism would be equal to the +active distribution (distribute individually to all delegators each block). +However, this is unrealistic so deviations from the active distribution will +occur based on fluctuations of incoming reward tokens as well as timing of +reward withdrawal by other delegators. + +If you happen to know that incoming rewards are about to significantly increase, +you are incentivized to not withdraw until after this event, increasing the +worth of your existing _accum_. See [#2764](https://github.com/cosmos/cosmos-sdk/issues/2764) +for further details. + +## Effect on Staking + +Charging commission on Atom provisions while also allowing for Atom-provisions +to be auto-bonded (distributed directly to the validators bonded stake) is +problematic within BPoS. Fundamentally, these two mechanisms are mutually +exclusive. If both commission and auto-bonding mechanisms are simultaneously +applied to the staking-token then the distribution of staking-tokens between +any validator and its delegators will change with each block. This then +necessitates a calculation for each delegation records for each block - +which is considered computationally expensive. + +In conclusion, we can only have Atom commission and unbonded atoms +provisions or bonded atom provisions with no Atom commission, and we elect to +implement the former. Stakeholders wishing to rebond their provisions may elect +to set up a script to periodically withdraw and rebond rewards. + +## Contents + +* [Concepts](#concepts) +* [State](#state) + * [FeePool](#feepool) + * [Validator Distribution](#validator-distribution) + * [Delegation Distribution](#delegation-distribution) + * [Params](#params) +* [Begin Block](#begin-block) +* [Messages](#messages) +* [Hooks](#hooks) +* [Events](#events) +* [Parameters](#parameters) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + + + +# Concepts + +In Proof of Stake (PoS) blockchains, rewards gained from transaction fees are paid to validators. The fee distribution module fairly distributes the rewards to the validators' constituent delegators. + +Rewards are calculated per period. The period is updated each time a validator's delegation changes, for example, when the validator receives a new delegation. +The rewards for a single validator can then be calculated by taking the total rewards for the period before the delegation started, minus the current total rewards. +To learn more, see the [F1 Fee Distribution paper](/docs/spec/fee_distribution/f1_fee_distr.pdf). + +The commission to the validator is paid when the validator is removed or when the validator requests a withdrawal. +The commission is calculated and incremented at every `BeginBlock` operation to update accumulated fee amounts. + +The rewards to a delegator are distributed when the delegation is changed or removed, or a withdrawal is requested. +Before rewards are distributed, all slashes to the validator that occurred during the current delegation are applied. + +## Reference Counting in F1 Fee Distribution + +In F1 fee distribution, the rewards a delegator receives are calculated when their delegation is withdrawn. This calculation must read the terms of the summation of rewards divided by the share of tokens from the period which they ended when they delegated, and the final period that was created for the withdrawal. + +Additionally, as slashes change the amount of tokens a delegation will have (but we calculate this lazily, +only when a delegator un-delegates), we must calculate rewards in separate periods before / after any slashes +which occurred in between when a delegator delegated and when they withdrew their rewards. Thus slashes, like +delegations, reference the period which was ended by the slash event. + +All stored historical rewards records for periods which are no longer referenced by any delegations +or any slashes can thus be safely removed, as they will never be read (future delegations and future +slashes will always reference future periods). This is implemented by tracking a `ReferenceCount` +along with each historical reward storage entry. Each time a new object (delegation or slash) +is created which might need to reference the historical record, the reference count is incremented. +Each time one object which previously needed to reference the historical record is deleted, the reference +count is decremented. If the reference count hits zero, the historical record is deleted. + + + +# State + +## FeePool + +All globally tracked parameters for distribution are stored within +`FeePool`. Rewards are collected and added to the reward pool and +distributed to validators/delegators from here. + +Note that the reward pool holds decimal coins (`DecCoins`) to allow +for fractions of coins to be received from operations like inflation. +When coins are distributed from the pool they are truncated back to +`sdk.Coins` which are non-decimal. + +* FeePool: `0x00 -> ProtocolBuffer(FeePool)` + +```go +// coins with decimal +type DecCoins []DecCoin + +type DecCoin struct { + Amount sdk.Dec + Denom string +} +``` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L92-L96 + +## Validator Distribution + +Validator distribution information for the relevant validator is updated each time: + +1. delegation amount to a validator is updated, +2. any delegator withdraws from a validator, or +3. the validator withdraws its commission. + +* ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)` + +```go +type ValidatorDistInfo struct { + OperatorAddress sdk.AccAddress + SelfBondRewards sdk.DecCoins + ValidatorCommission types.ValidatorAccumulatedCommission +} +``` + +## Delegation Distribution + +Each delegation distribution only needs to record the height at which it last +withdrew fees. Because a delegation must withdraw fees each time it's +properties change (aka bonded tokens etc.) its properties will remain constant +and the delegator's _accumulation_ factor can be calculated passively knowing +only the height of the last withdrawal and its current properties. + +* DelegationDistInfo: `0x02 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(delegatorDist)` + +```go +type DelegationDistInfo struct { + WithdrawalHeight int64 // last time this delegation withdrew rewards +} +``` + +## Params + +The distribution module stores it's params in state with the prefix of `0x09`, +it can be updated with governance or the address with authority. + +* Params: `0x09 | ProtocolBuffer(Params)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L11-L30 + + + +# Begin Block + +At each `BeginBlock`, all fees received in the previous block are transferred to +the distribution `ModuleAccount` account. When a delegator or validator +withdraws their rewards, they are taken out of the `ModuleAccount`. During begin +block, the different claims on the fees collected are updated as follows: + +* The reserve community tax is charged. +* The remainder is distributed proportionally by voting power to all bonded validators + +## The Distribution Scheme + +See [params](07_params.md) for description of parameters. + +Let `fees` be the total fees collected in the previous block, including +inflationary rewards to the stake. All fees are collected in a specific module +account during the block. During `BeginBlock`, they are sent to the +`"distribution"` `ModuleAccount`. No other sending of tokens occurs. Instead, the +rewards each account is entitled to are stored, and withdrawals can be triggered +through the messages `FundCommunityPool`, `WithdrawValidatorCommission` and +`WithdrawDelegatorReward`. + +### Reward to the Community Pool + +The community pool gets `community_tax * fees`, plus any remaining dust after +validators get their rewards that are always rounded down to the nearest +integer value. + +### Reward To the Validators + +The proposer receives no extra rewards. All fees are distributed among all the +bonded validators, including the proposer, in proportion to their consensus power. + +```text +powFrac = validator power / total bonded validator power +voteMul = 1 - community_tax +``` + +All validators receive `fees * voteMul * powFrac`. + +### Rewards to Delegators + +Each validator's rewards are distributed to its delegators. The validator also +has a self-delegation that is treated like a regular delegation in +distribution calculations. + +The validator sets a commission rate. The commission rate is flexible, but each +validator sets a maximum rate and a maximum daily increase. These maximums cannot be exceeded and protect delegators from sudden increases of validator commission rates to prevent validators from taking all of the rewards. + +The outstanding rewards that the operator is entitled to are stored in +`ValidatorAccumulatedCommission`, while the rewards the delegators are entitled +to are stored in `ValidatorCurrentRewards`. The [F1 fee distribution +scheme](01_concepts.md) is used to calculate the rewards per delegator as they +withdraw or update their delegation, and is thus not handled in `BeginBlock`. + +### Example Distribution + +For this example distribution, the underlying consensus engine selects block proposers in +proportion to their power relative to the entire bonded power. + +All validators are equally performant at including pre-commits in their proposed +blocks. Then hold `(pre_commits included) / (total bonded validator power)` +constant so that the amortized block reward for the validator is `( validator power / total bonded power) * (1 - community tax rate)` of +the total rewards. Consequently, the reward for a single delegator is: + +```text +(delegator proportion of the validator power / validator power) * (validator power / total bonded power) + * (1 - community tax rate) * (1 - validator commission rate) += (delegator proportion of the validator power / total bonded power) * (1 - +community tax rate) * (1 - validator commission rate) +``` + + + +# Messages + +## MsgSetWithdrawAddress + +By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message. +Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`. + +The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization. + +Response: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L31-L41 + +```go +func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error + if k.blockedAddrs[withdrawAddr.String()] { + fail with "`{withdrawAddr}` is not allowed to receive external funds" + } + + if !k.GetWithdrawAddrEnabled(ctx) { + fail with `ErrSetWithdrawAddrDisabled` + } + + k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr) +``` + +## MsgWithdrawDelegatorReward + +A delegator can withdraw its rewards. +Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value. +The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address. +Any remainder (truncated decimals) are sent to the community pool. +The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented. +The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. + +In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator. +In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way. +Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`. +Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`. +However, these calculated rewards don't account for slashing. + +Taking the slashes into account requires iteration. +Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`. +If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows: + +```go +stake := initial stake +rewards := 0 +previous := A +for P in P1, ..., PN`: + rewards = (R(P) - previous) * stake + stake = stake * F(P) + previous = P +rewards = rewards + (R(B) - R(PN)) * stake +``` + +The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step. +The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors. + +Response: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L46-L56 + +## WithdrawValidatorCommission + +The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission. +The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw. +The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. +Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later. + +## FundCommunityPool + +This message sends coins directly from the sender to the community pool. + +The transaction fails if the amount cannot be transferred from the sender to the distribution module account. + +```go +func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { + if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { + return err + } + + feePool := k.GetFeePool(ctx) + feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...) + k.SetFeePool(ctx, feePool) + + return nil +} +``` + +## Common distribution operations + +These operations take place during many different messages. + +### Initialize delegation + +Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized. +Initializing a delegation increments the validator period and keeps track of the starting period of the delegation. + +```go +// initialize starting info for a new delegation +func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) { + // period has already been incremented - we want to store the period ended by this delegation action + previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1 + + // increment reference count for the period we're going to track + k.incrementReferenceCount(ctx, val, previousPeriod) + + validator := k.stakingKeeper.Validator(ctx, val) + delegation := k.stakingKeeper.Delegation(ctx, del, val) + + // calculate delegation stake in tokens + // we don't store directly, so multiply delegation shares * (tokens per share) + // note: necessary to truncate so we don't allow withdrawing more rewards than owed + stake := validator.TokensFromSharesTruncated(delegation.GetShares()) + k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight()))) +} +``` + +## MsgUpdateParams + +Distribution module params can be updated through `MsgUpdateParams`, which can be done using governance proposal and the signer will always be gov module account address. + ++++ https://github.com/cosmos/cosmos-sdk/blob/8822ef2695a1eb8cb30b7432f58f631c73951f1d/proto/cosmos/distribution/v1beta1/tx.proto#L106-L119 + +The message handling can fail if: + +* signer is not the gov module account address. + + + +# Hooks + +Available hooks that can be called by and from this module. + +## Create or modify delegation distribution + +* triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate` + +### Before + +* The delegation rewards are withdrawn to the withdraw address of the delegator. + The rewards include the current period and exclude the starting period. +* The validator period is incremented. + The validator period is incremented because the validator's power and share distribution might have changed. +* The reference count for the delegator's starting period is decremented. + +### After + +The starting height of the delegation is set to the previous period. +Because of the `Before`-hook, this period is the last period for which the delegator was rewarded. + +## Validator created + +* triggered-by: `staking.MsgCreateValidator` + +When a validator is created, the following validator variables are initialized: + +* Historical rewards +* Current accumulated rewards +* Accumulated commission +* Total outstanding rewards +* Period + +By default, all values are set to a `0`, except period, which is set to `1`. + +## Validator removed + +* triggered-by: `staking.RemoveValidator` + +Outstanding commission is sent to the validator's self-delegation withdrawal address. +Remaining delegator rewards get sent to the community fee pool. + +Note: The validator gets removed only when it has no remaining delegations. +At that time, all outstanding delegator rewards will have been withdrawn. +Any remaining rewards are dust amounts. + +## Validator is slashed + +* triggered-by: `staking.Slash` + +* The current validator period reference count is incremented. + The reference count is incremented because the slash event has created a reference to it. +* The validator period is incremented. +* The slash event is stored for later use. + The slash event will be referenced when calculating delegator rewards. + + + +# Events + +The distribution module emits the following events: + +## BeginBlocker + +| Type | Attribute Key | Attribute Value | +|-----------------|---------------|--------------------| +| proposer_reward | validator | {validatorAddress} | +| proposer_reward | reward | {proposerReward} | +| commission | amount | {commissionAmount} | +| commission | validator | {validatorAddress} | +| rewards | amount | {rewardAmount} | +| rewards | validator | {validatorAddress} | + +## Handlers + +### MsgSetWithdrawAddress + +| Type | Attribute Key | Attribute Value | +|----------------------|------------------|----------------------| +| set_withdraw_address | withdraw_address | {withdrawAddress} | +| message | module | distribution | +| message | action | set_withdraw_address | +| message | sender | {senderAddress} | + +### MsgWithdrawDelegatorReward + +| Type | Attribute Key | Attribute Value | +|---------|---------------|---------------------------| +| withdraw_rewards | amount | {rewardAmount} | +| withdraw_rewards | validator | {validatorAddress} | +| message | module | distribution | +| message | action | withdraw_delegator_reward | +| message | sender | {senderAddress} | + +### MsgWithdrawValidatorCommission + +| Type | Attribute Key | Attribute Value | +|------------|---------------|-------------------------------| +| withdraw_commission | amount | {commissionAmount} | +| message | module | distribution | +| message | action | withdraw_validator_commission | +| message | sender | {senderAddress} | + + + +# Parameters + +The distribution module contains the following parameters: + +| Key | Type | Example | +| ------------------- | ------------ | -------------------------- | +| communitytax | string (dec) | "0.020000000000000000" [0] | +| baseproposerreward | string (dec) | "0.010000000000000000" [0] | +| bonusproposerreward | string (dec) | "0.040000000000000000" [0] | +| withdrawaddrenabled | bool | true | + +* [0] `communitytax`, `baseproposerreward` and `bonusproposerreward` must be + positive and their sum cannot exceed 1.00. + + + +# Client + +## CLI + +A user can query and interact with the `distribution` module using the CLI. + +### Query + +The `query` commands allow users to query `distribution` state. + +```sh +simd query distribution --help +``` + +#### commission + +The `commission` command allows users to query validator commission rewards by address. + +```sh +simd query distribution commission [address] [flags] +``` + +Example: + +```sh +simd query distribution commission cosmosvaloper1.. +``` + +Example Output: + +```yml +commission: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### community-pool + +The `community-pool` command allows users to query all coin balances within the community pool. + +```sh +simd query distribution community-pool [flags] +``` + +Example: + +```sh +simd query distribution community-pool +``` + +Example Output: + +```yml +pool: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### params + +The `params` command allows users to query the parameters of the `distribution` module. + +```sh +simd query distribution params [flags] +``` + +Example: + +```sh +simd query distribution params +``` + +Example Output: + +```yml +base_proposer_reward: "0.010000000000000000" +bonus_proposer_reward: "0.040000000000000000" +community_tax: "0.020000000000000000" +withdraw_addr_enabled: true +``` + +#### rewards + +The `rewards` command allows users to query delegator rewards. Users can optionally include the validator address to query rewards earned from a specific validator. + +```sh +simd query distribution rewards [delegator-addr] [validator-addr] [flags] +``` + +Example: + +```sh +simd query distribution rewards cosmos1.. +``` + +Example Output: + +```yml +rewards: +- reward: + - amount: "1000000.000000000000000000" + denom: stake + validator_address: cosmosvaloper1.. +total: +- amount: "1000000.000000000000000000" + denom: stake +``` + +#### slashes + +The `slashes` command allows users to query all slashes for a given block range. + +```sh +simd query distribution slashes [validator] [start-height] [end-height] [flags] +``` + +Example: + +```sh +simd query distribution slashes cosmosvaloper1.. 1 1000 +``` + +Example Output: + +```yml +pagination: + next_key: null + total: "0" +slashes: +- validator_period: 20, + fraction: "0.009999999999999999" +``` + +#### validator-outstanding-rewards + +The `validator-outstanding-rewards` command allows users to query all outstanding (un-withdrawn) rewards for a validator and all their delegations. + +```sh +simd query distribution validator-outstanding-rewards [validator] [flags] +``` + +Example: + +```sh +simd query distribution validator-outstanding-rewards cosmosvaloper1.. +``` + +Example Output: + +```yml +rewards: +- amount: "1000000.000000000000000000" + denom: stake +``` + +### Transactions + +The `tx` commands allow users to interact with the `distribution` module. + +```sh +simd tx distribution --help +``` + +#### fund-community-pool + +The `fund-community-pool` command allows users to send funds to the community pool. + +```sh +simd tx distribution fund-community-pool [amount] [flags] +``` + +Example: + +```sh +simd tx distribution fund-community-pool 100stake --from cosmos1.. +``` + +#### set-withdraw-addr + +The `set-withdraw-addr` command allows users to set the withdraw address for rewards associated with a delegator address. + +```sh +simd tx distribution set-withdraw-addr [withdraw-addr] [flags] +``` + +Example: + +```sh +simd tx distribution set-withdraw-addr cosmos1.. --from cosmos1.. +``` + +#### withdraw-all-rewards + +The `withdraw-all-rewards` command allows users to withdraw all rewards for a delegator. + +```sh +simd tx distribution withdraw-all-rewards [flags] +``` + +Example: + +```sh +simd tx distribution withdraw-all-rewards --from cosmos1.. +``` + +#### withdraw-rewards + +The `withdraw-rewards` command allows users to withdraw all rewards from a given delegation address, +and optionally withdraw validator commission if the delegation address given is a validator operator and the user proves the `--commision` flag. + +```sh +simd tx distribution withdraw-rewards [validator-addr] [flags] +``` + +Example: + +```sh +simd tx distribution withdraw-rewards cosmosvaloper1.. --from cosmos1.. --commision +``` + +## gRPC + +A user can query the `distribution` module using gRPC endpoints. + +### Params + +The `Params` endpoint allows users to query parameters of the `distribution` module. + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/Params +``` + +Example Output: + +```json +{ + "params": { + "communityTax": "20000000000000000", + "baseProposerReward": "10000000000000000", + "bonusProposerReward": "40000000000000000", + "withdrawAddrEnabled": true + } +} +``` + +### ValidatorOutstandingRewards + +The `ValidatorOutstandingRewards` endpoint allows users to query rewards of a validator address. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards +``` + +Example Output: + +```json +{ + "rewards": { + "rewards": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } +} +``` + +### ValidatorCommission + +The `ValidatorCommission` endpoint allows users to query accumulated commission for a validator. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorCommission +``` + +Example Output: + +```json +{ + "commission": { + "commission": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } +} +``` + +### ValidatorSlashes + +The `ValidatorSlashes` endpoint allows users to query slash events of a validator. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/ValidatorSlashes +``` + +Example Output: + +```json +{ + "slashes": [ + { + "validator_period": "20", + "fraction": "0.009999999999999999" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### DelegationRewards + +The `DelegationRewards` endpoint allows users to query the total rewards accrued by a delegation. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1..","validator_address":"cosmosvalop1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegationRewards +``` + +Example Output: + +```json +{ + "rewards": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] +} +``` + +### DelegationTotalRewards + +The `DelegationTotalRewards` endpoint allows users to query the total rewards accrued by each validator. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegationTotalRewards +``` + +Example Output: + +```json +{ + "rewards": [ + { + "validatorAddress": "cosmosvaloper1..", + "reward": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] + } + ], + "total": [ + { + "denom": "stake", + "amount": "1000000000000000" + } + ] +} +``` + +### DelegatorValidators + +The `DelegatorValidators` endpoint allows users to query all validators for given delegator. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegatorValidators +``` + +Example Output: + +```json +{ + "validators": [ + "cosmosvaloper1.." + ] +} +``` + +### DelegatorWithdrawAddress + +The `DelegatorWithdrawAddress` endpoint allows users to query the withdraw address of a delegator. + +Example: + +```sh +grpcurl -plaintext \ + -d '{"delegator_address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress +``` + +Example Output: + +```json +{ + "withdrawAddress": "cosmos1.." +} +``` + +### CommunityPool + +The `CommunityPool` endpoint allows users to query the community pool coins. + +Example: + +```sh +grpcurl -plaintext \ + localhost:9090 \ + cosmos.distribution.v1beta1.Query/CommunityPool +``` + +Example Output: + +```json +{ + "pool": [ + { + "denom": "stake", + "amount": "1000000000000000000" + } + ] +} +``` diff --git a/x/distribution/spec/01_concepts.md b/x/distribution/spec/01_concepts.md deleted file mode 100644 index 6bef259f1642..000000000000 --- a/x/distribution/spec/01_concepts.md +++ /dev/null @@ -1,34 +0,0 @@ - - -# Concepts - -In Proof of Stake (PoS) blockchains, rewards gained from transaction fees are paid to validators. The fee distribution module fairly distributes the rewards to the validators' constituent delegators. - -Rewards are calculated per period. The period is updated each time a validator's delegation changes, for example, when the validator receives a new delegation. -The rewards for a single validator can then be calculated by taking the total rewards for the period before the delegation started, minus the current total rewards. -To learn more, see the [F1 Fee Distribution paper](/docs/spec/fee_distribution/f1_fee_distr.pdf). - -The commission to the validator is paid when the validator is removed or when the validator requests a withdrawal. -The commission is calculated and incremented at every `BeginBlock` operation to update accumulated fee amounts. - -The rewards to a delegator are distributed when the delegation is changed or removed, or a withdrawal is requested. -Before rewards are distributed, all slashes to the validator that occurred during the current delegation are applied. - -## Reference Counting in F1 Fee Distribution - -In F1 fee distribution, the rewards a delegator receives are calculated when their delegation is withdrawn. This calculation must read the terms of the summation of rewards divided by the share of tokens from the period which they ended when they delegated, and the final period that was created for the withdrawal. - -Additionally, as slashes change the amount of tokens a delegation will have (but we calculate this lazily, -only when a delegator un-delegates), we must calculate rewards in separate periods before / after any slashes -which occurred in between when a delegator delegated and when they withdrew their rewards. Thus slashes, like -delegations, reference the period which was ended by the slash event. - -All stored historical rewards records for periods which are no longer referenced by any delegations -or any slashes can thus be safely removed, as they will never be read (future delegations and future -slashes will always reference future periods). This is implemented by tracking a `ReferenceCount` -along with each historical reward storage entry. Each time a new object (delegation or slash) -is created which might need to reference the historical record, the reference count is incremented. -Each time one object which previously needed to reference the historical record is deleted, the reference -count is decremented. If the reference count hits zero, the historical record is deleted. diff --git a/x/distribution/spec/02_state.md b/x/distribution/spec/02_state.md deleted file mode 100644 index c43844fd43ff..000000000000 --- a/x/distribution/spec/02_state.md +++ /dev/null @@ -1,73 +0,0 @@ - - -# State - -## FeePool - -All globally tracked parameters for distribution are stored within -`FeePool`. Rewards are collected and added to the reward pool and -distributed to validators/delegators from here. - -Note that the reward pool holds decimal coins (`DecCoins`) to allow -for fractions of coins to be received from operations like inflation. -When coins are distributed from the pool they are truncated back to -`sdk.Coins` which are non-decimal. - -* FeePool: `0x00 -> ProtocolBuffer(FeePool)` - -```go -// coins with decimal -type DecCoins []DecCoin - -type DecCoin struct { - Amount sdk.Dec - Denom string -} -``` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L92-L96 - -## Validator Distribution - -Validator distribution information for the relevant validator is updated each time: - -1. delegation amount to a validator is updated, -2. any delegator withdraws from a validator, or -3. the validator withdraws its commission. - -* ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)` - -```go -type ValidatorDistInfo struct { - OperatorAddress sdk.AccAddress - SelfBondRewards sdk.DecCoins - ValidatorCommission types.ValidatorAccumulatedCommission -} -``` - -## Delegation Distribution - -Each delegation distribution only needs to record the height at which it last -withdrew fees. Because a delegation must withdraw fees each time it's -properties change (aka bonded tokens etc.) its properties will remain constant -and the delegator's _accumulation_ factor can be calculated passively knowing -only the height of the last withdrawal and its current properties. - -* DelegationDistInfo: `0x02 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(delegatorDist)` - -```go -type DelegationDistInfo struct { - WithdrawalHeight int64 // last time this delegation withdrew rewards -} -``` - -## Params - -The distribution module stores it's params in state with the prefix of `0x09`, -it can be updated with governance or the address with authority. - -* Params: `0x09 | ProtocolBuffer(Params)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/distribution.proto#L11-L30 diff --git a/x/distribution/spec/03_begin_block.md b/x/distribution/spec/03_begin_block.md deleted file mode 100644 index 98315cb0caa3..000000000000 --- a/x/distribution/spec/03_begin_block.md +++ /dev/null @@ -1,75 +0,0 @@ - - -# Begin Block - -At each `BeginBlock`, all fees received in the previous block are transferred to -the distribution `ModuleAccount` account. When a delegator or validator -withdraws their rewards, they are taken out of the `ModuleAccount`. During begin -block, the different claims on the fees collected are updated as follows: - -* The reserve community tax is charged. -* The remainder is distributed proportionally by voting power to all bonded validators - -## The Distribution Scheme - -See [params](07_params.md) for description of parameters. - -Let `fees` be the total fees collected in the previous block, including -inflationary rewards to the stake. All fees are collected in a specific module -account during the block. During `BeginBlock`, they are sent to the -`"distribution"` `ModuleAccount`. No other sending of tokens occurs. Instead, the -rewards each account is entitled to are stored, and withdrawals can be triggered -through the messages `FundCommunityPool`, `WithdrawValidatorCommission` and -`WithdrawDelegatorReward`. - -### Reward to the Community Pool - -The community pool gets `community_tax * fees`, plus any remaining dust after -validators get their rewards that are always rounded down to the nearest -integer value. - -### Reward To the Validators - -The proposer receives no extra rewards. All fees are distributed among all the -bonded validators, including the proposer, in proportion to their consensus power. - -```text -powFrac = validator power / total bonded validator power -voteMul = 1 - community_tax -``` - -All validators receive `fees * voteMul * powFrac`. - -### Rewards to Delegators - -Each validator's rewards are distributed to its delegators. The validator also -has a self-delegation that is treated like a regular delegation in -distribution calculations. - -The validator sets a commission rate. The commission rate is flexible, but each -validator sets a maximum rate and a maximum daily increase. These maximums cannot be exceeded and protect delegators from sudden increases of validator commission rates to prevent validators from taking all of the rewards. - -The outstanding rewards that the operator is entitled to are stored in -`ValidatorAccumulatedCommission`, while the rewards the delegators are entitled -to are stored in `ValidatorCurrentRewards`. The [F1 fee distribution -scheme](01_concepts.md) is used to calculate the rewards per delegator as they -withdraw or update their delegation, and is thus not handled in `BeginBlock`. - -### Example Distribution - -For this example distribution, the underlying consensus engine selects block proposers in -proportion to their power relative to the entire bonded power. - -All validators are equally performant at including pre-commits in their proposed -blocks. Then hold `(pre_commits included) / (total bonded validator power)` -constant so that the amortized block reward for the validator is `( validator power / total bonded power) * (1 - community tax rate)` of -the total rewards. Consequently, the reward for a single delegator is: - -```text -(delegator proportion of the validator power / validator power) * (validator power / total bonded power) - * (1 - community tax rate) * (1 - validator commission rate) -= (delegator proportion of the validator power / total bonded power) * (1 - -community tax rate) * (1 - validator commission rate) -``` diff --git a/x/distribution/spec/04_messages.md b/x/distribution/spec/04_messages.md deleted file mode 100644 index d7e7f314428f..000000000000 --- a/x/distribution/spec/04_messages.md +++ /dev/null @@ -1,132 +0,0 @@ - - -# Messages - -## MsgSetWithdrawAddress - -By default, the withdraw address is the delegator address. To change its withdraw address, a delegator must send a `MsgSetWithdrawAddress` message. -Changing the withdraw address is possible only if the parameter `WithdrawAddrEnabled` is set to `true`. - -The withdraw address cannot be any of the module accounts. These accounts are blocked from being withdraw addresses by being added to the distribution keeper's `blockedAddrs` array at initialization. - -Response: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L31-L41 - -```go -func (k Keeper) SetWithdrawAddr(ctx sdk.Context, delegatorAddr sdk.AccAddress, withdrawAddr sdk.AccAddress) error - if k.blockedAddrs[withdrawAddr.String()] { - fail with "`{withdrawAddr}` is not allowed to receive external funds" - } - - if !k.GetWithdrawAddrEnabled(ctx) { - fail with `ErrSetWithdrawAddrDisabled` - } - - k.SetDelegatorWithdrawAddr(ctx, delegatorAddr, withdrawAddr) -``` - -## MsgWithdrawDelegatorReward - -A delegator can withdraw its rewards. -Internally in the distribution module, this transaction simultaneously removes the previous delegation with associated rewards, the same as if the delegator simply started a new delegation of the same value. -The rewards are sent immediately from the distribution `ModuleAccount` to the withdraw address. -Any remainder (truncated decimals) are sent to the community pool. -The starting height of the delegation is set to the current validator period, and the reference count for the previous period is decremented. -The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. - -In the F1 distribution, the total rewards are calculated per validator period, and a delegator receives a piece of those rewards in proportion to their stake in the validator. -In basic F1, the total rewards that all the delegators are entitled to between to periods is calculated the following way. -Let `R(X)` be the total accumulated rewards up to period `X` divided by the tokens staked at that time. The delegator allocation is `R(X) * delegator_stake`. -Then the rewards for all the delegators for staking between periods `A` and `B` are `(R(B) - R(A)) * total stake`. -However, these calculated rewards don't account for slashing. - -Taking the slashes into account requires iteration. -Let `F(X)` be the fraction a validator is to be slashed for a slashing event that happened at period `X`. -If the validator was slashed at periods `P1, ..., PN`, where `A < P1`, `PN < B`, the distribution module calculates the individual delegator's rewards, `T(A, B)`, as follows: - -```go -stake := initial stake -rewards := 0 -previous := A -for P in P1, ..., PN`: - rewards = (R(P) - previous) * stake - stake = stake * F(P) - previous = P -rewards = rewards + (R(B) - R(PN)) * stake -``` - -The historical rewards are calculated retroactively by playing back all the slashes and then attenuating the delegator's stake at each step. -The final calculated stake is equivalent to the actual staked coins in the delegation with a margin of error due to rounding errors. - -Response: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/distribution/v1beta1/tx.proto#L46-L56 - -## WithdrawValidatorCommission - -The validator can send the WithdrawValidatorCommission message to withdraw their accumulated commission. -The commission is calculated in every block during `BeginBlock`, so no iteration is required to withdraw. -The amount withdrawn is deducted from the `ValidatorOutstandingRewards` variable for the validator. -Only integer amounts can be sent. If the accumulated awards have decimals, the amount is truncated before the withdrawal is sent, and the remainder is left to be withdrawn later. - -## FundCommunityPool - -This message sends coins directly from the sender to the community pool. - -The transaction fails if the amount cannot be transferred from the sender to the distribution module account. - -```go -func (k Keeper) FundCommunityPool(ctx sdk.Context, amount sdk.Coins, sender sdk.AccAddress) error { - if err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount); err != nil { - return err - } - - feePool := k.GetFeePool(ctx) - feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(amount...)...) - k.SetFeePool(ctx, feePool) - - return nil -} -``` - -## Common distribution operations - -These operations take place during many different messages. - -### Initialize delegation - -Each time a delegation is changed, the rewards are withdrawn and the delegation is reinitialized. -Initializing a delegation increments the validator period and keeps track of the starting period of the delegation. - -```go -// initialize starting info for a new delegation -func (k Keeper) initializeDelegation(ctx sdk.Context, val sdk.ValAddress, del sdk.AccAddress) { - // period has already been incremented - we want to store the period ended by this delegation action - previousPeriod := k.GetValidatorCurrentRewards(ctx, val).Period - 1 - - // increment reference count for the period we're going to track - k.incrementReferenceCount(ctx, val, previousPeriod) - - validator := k.stakingKeeper.Validator(ctx, val) - delegation := k.stakingKeeper.Delegation(ctx, del, val) - - // calculate delegation stake in tokens - // we don't store directly, so multiply delegation shares * (tokens per share) - // note: necessary to truncate so we don't allow withdrawing more rewards than owed - stake := validator.TokensFromSharesTruncated(delegation.GetShares()) - k.SetDelegatorStartingInfo(ctx, val, del, types.NewDelegatorStartingInfo(previousPeriod, stake, uint64(ctx.BlockHeight()))) -} -``` - -## MsgUpdateParams - -Distribution module params can be updated through `MsgUpdateParams`, which can be done using governance proposal and the signer will always be gov module account address. - -+++ https://github.com/cosmos/cosmos-sdk/blob/8822ef2695a1eb8cb30b7432f58f631c73951f1d/proto/cosmos/distribution/v1beta1/tx.proto#L106-L119 - -The message handling can fail if: - -* signer is not the gov module account address. diff --git a/x/distribution/spec/05_hooks.md b/x/distribution/spec/05_hooks.md deleted file mode 100644 index a1702ef73b0b..000000000000 --- a/x/distribution/spec/05_hooks.md +++ /dev/null @@ -1,59 +0,0 @@ - - -# Hooks - -Available hooks that can be called by and from this module. - -## Create or modify delegation distribution - -* triggered-by: `staking.MsgDelegate`, `staking.MsgBeginRedelegate`, `staking.MsgUndelegate` - -### Before - -* The delegation rewards are withdrawn to the withdraw address of the delegator. - The rewards include the current period and exclude the starting period. -* The validator period is incremented. - The validator period is incremented because the validator's power and share distribution might have changed. -* The reference count for the delegator's starting period is decremented. - -### After - -The starting height of the delegation is set to the previous period. -Because of the `Before`-hook, this period is the last period for which the delegator was rewarded. - -## Validator created - -* triggered-by: `staking.MsgCreateValidator` - -When a validator is created, the following validator variables are initialized: - -* Historical rewards -* Current accumulated rewards -* Accumulated commission -* Total outstanding rewards -* Period - -By default, all values are set to a `0`, except period, which is set to `1`. - -## Validator removed - -* triggered-by: `staking.RemoveValidator` - -Outstanding commission is sent to the validator's self-delegation withdrawal address. -Remaining delegator rewards get sent to the community fee pool. - -Note: The validator gets removed only when it has no remaining delegations. -At that time, all outstanding delegator rewards will have been withdrawn. -Any remaining rewards are dust amounts. - -## Validator is slashed - -* triggered-by: `staking.Slash` - -* The current validator period reference count is incremented. - The reference count is incremented because the slash event has created a reference to it. -* The validator period is incremented. -* The slash event is stored for later use. - The slash event will be referenced when calculating delegator rewards. diff --git a/x/distribution/spec/06_events.md b/x/distribution/spec/06_events.md deleted file mode 100644 index 7e70f0beb4c5..000000000000 --- a/x/distribution/spec/06_events.md +++ /dev/null @@ -1,48 +0,0 @@ - - -# Events - -The distribution module emits the following events: - -## BeginBlocker - -| Type | Attribute Key | Attribute Value | -|-----------------|---------------|--------------------| -| proposer_reward | validator | {validatorAddress} | -| proposer_reward | reward | {proposerReward} | -| commission | amount | {commissionAmount} | -| commission | validator | {validatorAddress} | -| rewards | amount | {rewardAmount} | -| rewards | validator | {validatorAddress} | - -## Handlers - -### MsgSetWithdrawAddress - -| Type | Attribute Key | Attribute Value | -|----------------------|------------------|----------------------| -| set_withdraw_address | withdraw_address | {withdrawAddress} | -| message | module | distribution | -| message | action | set_withdraw_address | -| message | sender | {senderAddress} | - -### MsgWithdrawDelegatorReward - -| Type | Attribute Key | Attribute Value | -|---------|---------------|---------------------------| -| withdraw_rewards | amount | {rewardAmount} | -| withdraw_rewards | validator | {validatorAddress} | -| message | module | distribution | -| message | action | withdraw_delegator_reward | -| message | sender | {senderAddress} | - -### MsgWithdrawValidatorCommission - -| Type | Attribute Key | Attribute Value | -|------------|---------------|-------------------------------| -| withdraw_commission | amount | {commissionAmount} | -| message | module | distribution | -| message | action | withdraw_validator_commission | -| message | sender | {senderAddress} | diff --git a/x/distribution/spec/07_params.md b/x/distribution/spec/07_params.md deleted file mode 100644 index 4cee94c9d14a..000000000000 --- a/x/distribution/spec/07_params.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# Parameters - -The distribution module contains the following parameters: - -| Key | Type | Example | -| ------------------- | ------------ | -------------------------- | -| communitytax | string (dec) | "0.020000000000000000" [0] | -| baseproposerreward | string (dec) | "0.010000000000000000" [0] | -| bonusproposerreward | string (dec) | "0.040000000000000000" [0] | -| withdrawaddrenabled | bool | true | - -* [0] `communitytax`, `baseproposerreward` and `bonusproposerreward` must be - positive and their sum cannot exceed 1.00. diff --git a/x/distribution/spec/08_client.md b/x/distribution/spec/08_client.md deleted file mode 100644 index 8e547ba46926..000000000000 --- a/x/distribution/spec/08_client.md +++ /dev/null @@ -1,469 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `distribution` module using the CLI. - -### Query - -The `query` commands allow users to query `distribution` state. - -```sh -simd query distribution --help -``` - -#### commission - -The `commission` command allows users to query validator commission rewards by address. - -```sh -simd query distribution commission [address] [flags] -``` - -Example: - -```sh -simd query distribution commission cosmosvaloper1.. -``` - -Example Output: - -```yml -commission: -- amount: "1000000.000000000000000000" - denom: stake -``` - -#### community-pool - -The `community-pool` command allows users to query all coin balances within the community pool. - -```sh -simd query distribution community-pool [flags] -``` - -Example: - -```sh -simd query distribution community-pool -``` - -Example Output: - -```yml -pool: -- amount: "1000000.000000000000000000" - denom: stake -``` - -#### params - -The `params` command allows users to query the parameters of the `distribution` module. - -```sh -simd query distribution params [flags] -``` - -Example: - -```sh -simd query distribution params -``` - -Example Output: - -```yml -base_proposer_reward: "0.010000000000000000" -bonus_proposer_reward: "0.040000000000000000" -community_tax: "0.020000000000000000" -withdraw_addr_enabled: true -``` - -#### rewards - -The `rewards` command allows users to query delegator rewards. Users can optionally include the validator address to query rewards earned from a specific validator. - -```sh -simd query distribution rewards [delegator-addr] [validator-addr] [flags] -``` - -Example: - -```sh -simd query distribution rewards cosmos1.. -``` - -Example Output: - -```yml -rewards: -- reward: - - amount: "1000000.000000000000000000" - denom: stake - validator_address: cosmosvaloper1.. -total: -- amount: "1000000.000000000000000000" - denom: stake -``` - -#### slashes - -The `slashes` command allows users to query all slashes for a given block range. - -```sh -simd query distribution slashes [validator] [start-height] [end-height] [flags] -``` - -Example: - -```sh -simd query distribution slashes cosmosvaloper1.. 1 1000 -``` - -Example Output: - -```yml -pagination: - next_key: null - total: "0" -slashes: -- validator_period: 20, - fraction: "0.009999999999999999" -``` - -#### validator-outstanding-rewards - -The `validator-outstanding-rewards` command allows users to query all outstanding (un-withdrawn) rewards for a validator and all their delegations. - -```sh -simd query distribution validator-outstanding-rewards [validator] [flags] -``` - -Example: - -```sh -simd query distribution validator-outstanding-rewards cosmosvaloper1.. -``` - -Example Output: - -```yml -rewards: -- amount: "1000000.000000000000000000" - denom: stake -``` - -### Transactions - -The `tx` commands allow users to interact with the `distribution` module. - -```sh -simd tx distribution --help -``` - -#### fund-community-pool - -The `fund-community-pool` command allows users to send funds to the community pool. - -```sh -simd tx distribution fund-community-pool [amount] [flags] -``` - -Example: - -```sh -simd tx distribution fund-community-pool 100stake --from cosmos1.. -``` - -#### set-withdraw-addr - -The `set-withdraw-addr` command allows users to set the withdraw address for rewards associated with a delegator address. - -```sh -simd tx distribution set-withdraw-addr [withdraw-addr] [flags] -``` - -Example: - -```sh -simd tx distribution set-withdraw-addr cosmos1.. --from cosmos1.. -``` - -#### withdraw-all-rewards - -The `withdraw-all-rewards` command allows users to withdraw all rewards for a delegator. - -```sh -simd tx distribution withdraw-all-rewards [flags] -``` - -Example: - -```sh -simd tx distribution withdraw-all-rewards --from cosmos1.. -``` - -#### withdraw-rewards - -The `withdraw-rewards` command allows users to withdraw all rewards from a given delegation address, -and optionally withdraw validator commission if the delegation address given is a validator operator and the user proves the `--commision` flag. - -```sh -simd tx distribution withdraw-rewards [validator-addr] [flags] -``` - -Example: - -```sh -simd tx distribution withdraw-rewards cosmosvaloper1.. --from cosmos1.. --commision -``` - -## gRPC - -A user can query the `distribution` module using gRPC endpoints. - -### Params - -The `Params` endpoint allows users to query parameters of the `distribution` module. - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/Params -``` - -Example Output: - -```json -{ - "params": { - "communityTax": "20000000000000000", - "baseProposerReward": "10000000000000000", - "bonusProposerReward": "40000000000000000", - "withdrawAddrEnabled": true - } -} -``` - -### ValidatorOutstandingRewards - -The `ValidatorOutstandingRewards` endpoint allows users to query rewards of a validator address. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"validator_address":"cosmosvalop1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards -``` - -Example Output: - -```json -{ - "rewards": { - "rewards": [ - { - "denom": "stake", - "amount": "1000000000000000" - } - ] - } -} -``` - -### ValidatorCommission - -The `ValidatorCommission` endpoint allows users to query accumulated commission for a validator. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"validator_address":"cosmosvalop1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/ValidatorCommission -``` - -Example Output: - -```json -{ - "commission": { - "commission": [ - { - "denom": "stake", - "amount": "1000000000000000" - } - ] - } -} -``` - -### ValidatorSlashes - -The `ValidatorSlashes` endpoint allows users to query slash events of a validator. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"validator_address":"cosmosvalop1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/ValidatorSlashes -``` - -Example Output: - -```json -{ - "slashes": [ - { - "validator_period": "20", - "fraction": "0.009999999999999999" - } - ], - "pagination": { - "total": "1" - } -} -``` - -### DelegationRewards - -The `DelegationRewards` endpoint allows users to query the total rewards accrued by a delegation. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"delegator_address":"cosmos1..","validator_address":"cosmosvalop1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/DelegationRewards -``` - -Example Output: - -```json -{ - "rewards": [ - { - "denom": "stake", - "amount": "1000000000000000" - } - ] -} -``` - -### DelegationTotalRewards - -The `DelegationTotalRewards` endpoint allows users to query the total rewards accrued by each validator. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"delegator_address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/DelegationTotalRewards -``` - -Example Output: - -```json -{ - "rewards": [ - { - "validatorAddress": "cosmosvaloper1..", - "reward": [ - { - "denom": "stake", - "amount": "1000000000000000" - } - ] - } - ], - "total": [ - { - "denom": "stake", - "amount": "1000000000000000" - } - ] -} -``` - -### DelegatorValidators - -The `DelegatorValidators` endpoint allows users to query all validators for given delegator. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"delegator_address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/DelegatorValidators -``` - -Example Output: - -```json -{ - "validators": [ - "cosmosvaloper1.." - ] -} -``` - -### DelegatorWithdrawAddress - -The `DelegatorWithdrawAddress` endpoint allows users to query the withdraw address of a delegator. - -Example: - -```sh -grpcurl -plaintext \ - -d '{"delegator_address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/DelegatorWithdrawAddress -``` - -Example Output: - -```json -{ - "withdrawAddress": "cosmos1.." -} -``` - -### CommunityPool - -The `CommunityPool` endpoint allows users to query the community pool coins. - -Example: - -```sh -grpcurl -plaintext \ - localhost:9090 \ - cosmos.distribution.v1beta1.Query/CommunityPool -``` - -Example Output: - -```json -{ - "pool": [ - { - "denom": "stake", - "amount": "1000000000000000000" - } - ] -} -``` diff --git a/x/distribution/spec/README.md b/x/distribution/spec/README.md deleted file mode 100644 index deab94e61849..000000000000 --- a/x/distribution/spec/README.md +++ /dev/null @@ -1,104 +0,0 @@ - - -# `distribution` - -## Overview - -This _simple_ distribution mechanism describes a functional way to passively -distribute rewards between validators and delegators. Note that this mechanism does -not distribute funds in as precisely as active reward distribution mechanisms and -will therefore be upgraded in the future. - -The mechanism operates as follows. Collected rewards are pooled globally and -divided out passively to validators and delegators. Each validator has the -opportunity to charge commission to the delegators on the rewards collected on -behalf of the delegators. Fees are collected directly into a global reward pool -and validator proposer-reward pool. Due to the nature of passive accounting, -whenever changes to parameters which affect the rate of reward distribution -occurs, withdrawal of rewards must also occur. - -* Whenever withdrawing, one must withdraw the maximum amount they are entitled - to, leaving nothing in the pool. -* Whenever bonding, unbonding, or re-delegating tokens to an existing account, a - full withdrawal of the rewards must occur (as the rules for lazy accounting - change). -* Whenever a validator chooses to change the commission on rewards, all accumulated - commission rewards must be simultaneously withdrawn. - -The above scenarios are covered in `hooks.md`. - -The distribution mechanism outlined herein is used to lazily distribute the -following rewards between validators and associated delegators: - -* multi-token fees to be socially distributed -* inflated staked asset provisions -* validator commission on all rewards earned by their delegators stake - -Fees are pooled within a global pool. The mechanisms used allow for validators -and delegators to independently and lazily withdraw their rewards. - -## Shortcomings - -As a part of the lazy computations, each delegator holds an accumulation term -specific to each validator which is used to estimate what their approximate -fair portion of tokens held in the global fee pool is owed to them. - -```text -entitlement = delegator-accumulation / all-delegators-accumulation -``` - -Under the circumstance that there was constant and equal flow of incoming -reward tokens every block, this distribution mechanism would be equal to the -active distribution (distribute individually to all delegators each block). -However, this is unrealistic so deviations from the active distribution will -occur based on fluctuations of incoming reward tokens as well as timing of -reward withdrawal by other delegators. - -If you happen to know that incoming rewards are about to significantly increase, -you are incentivized to not withdraw until after this event, increasing the -worth of your existing _accum_. See [#2764](https://github.com/cosmos/cosmos-sdk/issues/2764) -for further details. - -## Effect on Staking - -Charging commission on Atom provisions while also allowing for Atom-provisions -to be auto-bonded (distributed directly to the validators bonded stake) is -problematic within BPoS. Fundamentally, these two mechanisms are mutually -exclusive. If both commission and auto-bonding mechanisms are simultaneously -applied to the staking-token then the distribution of staking-tokens between -any validator and its delegators will change with each block. This then -necessitates a calculation for each delegation records for each block - -which is considered computationally expensive. - -In conclusion, we can only have Atom commission and unbonded atoms -provisions or bonded atom provisions with no Atom commission, and we elect to -implement the former. Stakeholders wishing to rebond their provisions may elect -to set up a script to periodically withdraw and rebond rewards. - -## Contents - -1. **[Concepts](01_concepts.md)** - * [Reference Counting in F1 Fee Distribution](01_concepts.md#reference-counting-in-f1-fee-distribution) -2. **[State](02_state.md)** -3. **[Begin Block](03_begin_block.md)** -4. **[Messages](04_messages.md)** - * [MsgSetWithdrawAddress](04_messages.md#msgsetwithdrawaddress) - * [MsgWithdrawDelegatorReward](04_messages.md#msgwithdrawdelegatorreward) - * [Withdraw Validator Rewards All](04_messages.md#withdraw-validator-rewards-all) - * [Common calculations](04_messages.md#common-calculations-) -5. **[Hooks](05_hooks.md)** - * [Create or modify delegation distribution](05_hooks.md#create-or-modify-delegation-distribution) - * [Commission rate change](05_hooks.md#commission-rate-change) - * [Change in Validator State](05_hooks.md#change-in-validator-state) -6. **[Events](06_events.md)** - * [BeginBlocker](06_events.md#beginblocker) - * [Handlers](06_events.md#handlers) -7. **[Parameters](07_params.md)** -8. **[Client](08_client.md)** - * [CLI](08_client.md#cli) - * [gRPC](08_client.md#grpc) diff --git a/x/epoching/README.md b/x/epoching/README.md index a7fbf3df82da..7302c4f102a3 100644 --- a/x/epoching/README.md +++ b/x/epoching/README.md @@ -1,7 +1,94 @@ -# Epoching +# `x/epoching` -* [Epoching](epoching/spec/README.md) - Allows modules to queue messages for execution at a certain block height. +## Abstract + +The epoching module allows modules to queue messages for execution at a certain block height. Each module will have its own instance of the epoching module, this allows each module to have its own message queue and own duration for epochs. + +## Example + +In this example, we are creating an epochkeeper for a module that will be used by the module to queue messages to be executed at a later point in time. + +```go +type Keeper struct { + storeKey sdk.StoreKey + cdc codec.BinaryMarshaler + epochKeeper epochkeeper.Keeper +} + +// NewKeeper creates a new staking Keeper instance +func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + epochKeeper: epochkeeper.NewKeeper(cdc, key), + } +} +``` + +### Contents + +* [State](#state) + + + +# State + +## Messages queue + +Messages are queued to run at the end of each epoch. Queued messages have an epoch number and for each epoch number, the queues are iterated over and each message is executed. + +### Message queues + +Each module has one unique message queue that is specific to that module. + +## Actions + +A module will add a message that implements the `sdk.Msg` interface. These message will be executed at a later time (end of the next epoch). + +```go +type Msg interface { + proto.Message + + // Return the message type. + // Must be alphanumeric or empty. + Route() string + + // Returns a human-readable string for the message, intended for utilization + // within tags + Type() string + + // ValidateBasic does a simple validation check that + // doesn't require access to any other information. + ValidateBasic() error + + // Get the canonical byte representation of the Msg. + GetSignBytes() []byte + + // Signers returns the addrs of signers that must sign. + // CONTRACT: All signatures must be present to be valid. + // CONTRACT: Returns addrs in some deterministic order. + GetSigners() []AccAddress + } +``` + +## Buffered Messages Export / Import + +For now, the `x/epoching` module is implemented to export all buffered messages without epoch numbers. When state is imported, buffered messages are stored on current epoch to run at the end of current epoch. + +## Genesis Transactions + +We execute epoch after execution of genesis transactions to see the changes instantly before node start. + +## Execution on epochs + +* Try executing the message for the epoch +* If success, make changes as it is +* If failure, try making revert extra actions done on handlers (e.g. EpochDelegationPool deposit) +* If revert fail, panic diff --git a/x/epoching/spec/01_state.md b/x/epoching/spec/01_state.md deleted file mode 100644 index 9f8672aa3a29..000000000000 --- a/x/epoching/spec/01_state.md +++ /dev/null @@ -1,58 +0,0 @@ - - -# State - -## Messages queue - -Messages are queued to run at the end of each epoch. Queued messages have an epoch number and for each epoch number, the queues are iterated over and each message is executed. - -### Message queues - -Each module has one unique message queue that is specific to that module. - -## Actions - -A module will add a message that implements the `sdk.Msg` interface. These message will be executed at a later time (end of the next epoch). - -```go -type Msg interface { - proto.Message - - // Return the message type. - // Must be alphanumeric or empty. - Route() string - - // Returns a human-readable string for the message, intended for utilization - // within tags - Type() string - - // ValidateBasic does a simple validation check that - // doesn't require access to any other information. - ValidateBasic() error - - // Get the canonical byte representation of the Msg. - GetSignBytes() []byte - - // Signers returns the addrs of signers that must sign. - // CONTRACT: All signatures must be present to be valid. - // CONTRACT: Returns addrs in some deterministic order. - GetSigners() []AccAddress - } -``` - -## Buffered Messages Export / Import - -For now, the `x/epoching` module is implemented to export all buffered messages without epoch numbers. When state is imported, buffered messages are stored on current epoch to run at the end of current epoch. - -## Genesis Transactions - -We execute epoch after execution of genesis transactions to see the changes instantly before node start. - -## Execution on epochs - -* Try executing the message for the epoch -* If success, make changes as it is -* If failure, try making revert extra actions done on handlers (e.g. EpochDelegationPool deposit) -* If revert fail, panic diff --git a/x/epoching/spec/03_to_improve.md b/x/epoching/spec/03_to_improve.md deleted file mode 100644 index 7215629769d0..000000000000 --- a/x/epoching/spec/03_to_improve.md +++ /dev/null @@ -1,44 +0,0 @@ - - -# Changes to make - -## Validator self-unbonding (which exceed minimum self delegation) could be required to start instantly - -Cases that trigger unbonding process - -* Validator undelegate can unbond more tokens than his minimum_self_delegation and it will automatically turn the validator into unbonding -In this case, unbonding should start instantly. -* Validator miss blocks and get slashed -* Validator get slashed for double sign - -**Note:** When a validator begins the unbonding process, it could be required to turn the validator into unbonding state instantly. - This is different than a specific delegator beginning to unbond. A validator beginning to unbond means that it's not in the set any more. - A delegator unbonding from a validator removes their delegation from the validator. - -## Pending development - -```go -// Changes to make -// β€” Implement correct next epoch time calculation -// β€” For validator self undelegation, it could be required to do start on end blocker -// β€” Implement TODOs on the PR #46 -// Implement CLI commands for querying -// β€” BufferedValidators -// β€” BufferedMsgCreateValidatorQueue, BufferedMsgEditValidatorQueue -// β€” BufferedMsgUnjailQueue, BufferedMsgDelegateQueue, BufferedMsgRedelegationQueue, BufferedMsgUndelegateQueue -// Write epoch related tests with new scenarios -// β€” Simulation test is important for finding bugs [Ask Dev for questions) -// β€” Can easily add a simulator check to make sure all delegation amounts in queue add up to the same amount that’s in the EpochUnbondedPool -// β€” I’d like it added as an invariant test for the simulator -// β€” the simulator should check that the sum of all the queued delegations always equals the amount kept track in the data -// β€” Staking/Slashing/Distribution module params are being modified by governance based on vote result instantly. We should test the effect. -// β€” β€” Should test to see what would happen if max_validators is changed though, in the middle of an epoch -// β€” we should define some new invariants that help check that everything is working smoothly with these new changes for 3 modules e.g. https://github.com/cosmos/cosmos-sdk/blob/main/x/staking/keeper/invariants.go -// β€” β€” Within Epoch, ValidationPower = ValidationPower - SlashAmount -// β€” β€” When epoch actions queue is empty, EpochDelegationPool balance should be zero -// β€” we should count all the delegation changes that happen during the epoch, and then make sure that the resulting change at the end of the epoch is actually correct -// β€” If the validator that I delegated to double signs at block 16, I should still get slashed instantly because even though I asked to unbond at 14, they still used my power at block 16, I should only be not liable for slashes once my power is stopped being used -// β€” On the converse of this, I should still be getting rewards while my power is being used. I shouldn’t stop receiving rewards until block 20 -``` diff --git a/x/epoching/spec/README.md b/x/epoching/spec/README.md deleted file mode 100644 index 8dcd4b9b70cb..000000000000 --- a/x/epoching/spec/README.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# `x/epoching` - -## Abstract - -The epoching module allows modules to queue messages for execution at a certain block height. Each module will have its own instance of the epoching module, this allows each module to have its own message queue and own duration for epochs. - -## Example - -In this example, we are creating an epochkeeper for a module that will be used by the module to queue messages to be executed at a later point in time. - -```go -type Keeper struct { - storeKey sdk.StoreKey - cdc codec.BinaryMarshaler - epochKeeper epochkeeper.Keeper -} - -// NewKeeper creates a new staking Keeper instance -func NewKeeper(cdc codec.BinaryMarshaler, key sdk.StoreKey) Keeper { - return Keeper{ - storeKey: key, - cdc: cdc, - epochKeeper: epochkeeper.NewKeeper(cdc, key), - } -} -``` - -### Contents - -1. **[State](01_state.md)** diff --git a/x/evidence/README.md b/x/evidence/README.md index 7cdd2926c66c..bdec9cc1701a 100644 --- a/x/evidence/README.md +++ b/x/evidence/README.md @@ -1,7 +1,554 @@ -# Evidence +# `x/evidence` -* [Evidence](spec/README.md) - Evidence handling for double signing, misbehaviour, etc. +* [Concepts](#concepts) +* [State](#state) +* [Messages](#messages) +* [Events](#events) +* [Parameters](#parameters) +* [BeginBlock](#beginblock) +* [Client](#client) + * [CLI](#cli) + * [REST](#rest) + * [gRPC](#grpc) + +## Abstract + +`x/evidence` is an implementation of a Cosmos SDK module, per [ADR 009](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-009-evidence-module.md), +that allows for the submission and handling of arbitrary evidence of misbehavior such +as equivocation and counterfactual signing. + +The evidence module differs from standard evidence handling which typically expects the +underlying consensus engine, e.g. Tendermint, to automatically submit evidence when +it is discovered by allowing clients and foreign chains to submit more complex evidence +directly. + +All concrete evidence types must implement the `Evidence` interface contract. Submitted +`Evidence` is first routed through the evidence module's `Router` in which it attempts +to find a corresponding registered `Handler` for that specific `Evidence` type. +Each `Evidence` type must have a `Handler` registered with the evidence module's +keeper in order for it to be successfully routed and executed. + +Each corresponding handler must also fulfill the `Handler` interface contract. The +`Handler` for a given `Evidence` type can perform any arbitrary state transitions +such as slashing, jailing, and tombstoning. + + + +# Concepts + +## Evidence + +Any concrete type of evidence submitted to the `x/evidence` module must fulfill the +`Evidence` contract outlined below. Not all concrete types of evidence will fulfill +this contract in the same way and some data may be entirely irrelevant to certain +types of evidence. An additional `ValidatorEvidence`, which extends `Evidence`, +has also been created to define a contract for evidence against malicious validators. + +```go +// Evidence defines the contract which concrete evidence types of misbehavior +// must implement. +type Evidence interface { + proto.Message + + Route() string + Type() string + String() string + Hash() tmbytes.HexBytes + ValidateBasic() error + + // Height at which the infraction occurred + GetHeight() int64 +} + +// ValidatorEvidence extends Evidence interface to define contract +// for evidence against malicious validators +type ValidatorEvidence interface { + Evidence + + // The consensus address of the malicious validator at time of infraction + GetConsensusAddress() sdk.ConsAddress + + // The total power of the malicious validator at time of infraction + GetValidatorPower() int64 + + // The total validator set power at time of infraction + GetTotalPower() int64 +} +``` + +## Registration & Handling + +The `x/evidence` module must first know about all types of evidence it is expected +to handle. This is accomplished by registering the `Route` method in the `Evidence` +contract with what is known as a `Router` (defined below). The `Router` accepts +`Evidence` and attempts to find the corresponding `Handler` for the `Evidence` +via the `Route` method. + +```go +type Router interface { + AddRoute(r string, h Handler) Router + HasRoute(r string) bool + GetRoute(path string) Handler + Seal() + Sealed() bool +} +``` + +The `Handler` (defined below) is responsible for executing the entirety of the +business logic for handling `Evidence`. This typically includes validating the +evidence, both stateless checks via `ValidateBasic` and stateful checks via any +keepers provided to the `Handler`. In addition, the `Handler` may also perform +capabilities such as slashing and jailing a validator. All `Evidence` handled +by the `Handler` should be persisted. + +```go +// Handler defines an agnostic Evidence handler. The handler is responsible +// for executing all corresponding business logic necessary for verifying the +// evidence as valid. In addition, the Handler may execute any necessary +// slashing and potential jailing. +type Handler func(sdk.Context, Evidence) error +``` + + + +# State + +Currently the `x/evidence` module only stores valid submitted `Evidence` in state. +The evidence state is also stored and exported in the `x/evidence` module's `GenesisState`. + +```protobuf +// GenesisState defines the evidence module's genesis state. +message GenesisState { + // evidence defines all the evidence at genesis. + repeated google.protobuf.Any evidence = 1; +} + +``` + +All `Evidence` is retrieved and stored via a prefix `KVStore` using prefix `0x00` (`KeyPrefixEvidence`). + + + +# Messages + +## MsgSubmitEvidence + +Evidence is submitted through a `MsgSubmitEvidence` message: + +```protobuf +// MsgSubmitEvidence represents a message that supports submitting arbitrary +// Evidence of misbehavior such as equivocation or counterfactual signing. +message MsgSubmitEvidence { + string submitter = 1; + google.protobuf.Any evidence = 2; +} +``` + +Note, the `Evidence` of a `MsgSubmitEvidence` message must have a corresponding +`Handler` registered with the `x/evidence` module's `Router` in order to be processed +and routed correctly. + +Given the `Evidence` is registered with a corresponding `Handler`, it is processed +as follows: + +```go +func SubmitEvidence(ctx Context, evidence Evidence) error { + if _, ok := GetEvidence(ctx, evidence.Hash()); ok { + return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String()) + } + if !router.HasRoute(evidence.Route()) { + return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route()) + } + + handler := router.GetRoute(evidence.Route()) + if err := handler(ctx, evidence); err != nil { + return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error()) + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSubmitEvidence, + sdk.NewAttribute(types.AttributeKeyEvidenceHash, evidence.Hash().String()), + ), + ) + + SetEvidence(ctx, evidence) + return nil +} +``` + +First, there must not already exist valid submitted `Evidence` of the exact same +type. Secondly, the `Evidence` is routed to the `Handler` and executed. Finally, +if there is no error in handling the `Evidence`, an event is emitted and it is persisted to state. + + + +# Events + +The `x/evidence` module emits the following events: + +## Handlers + +### MsgSubmitEvidence + +| Type | Attribute Key | Attribute Value | +| --------------- | ------------- | --------------- | +| submit_evidence | evidence_hash | {evidenceHash} | +| message | module | evidence | +| message | sender | {senderAddress} | +| message | action | submit_evidence | + + + +# Parameters + +The evidence module does not contain any parameters. + + + +# BeginBlock + +## Evidence Handling + +Tendermint blocks can include +[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly. + +### Equivocation + +The Cosmos SDK handles two types of evidence inside the ABCI `BeginBlock`: + +* `DuplicateVoteEvidence`, +* `LightClientAttackEvidence`. + +The evidence module handles these two evidence types the same way. First, the Cosmos SDK converts the Tendermint concrete evidence type to an SDK `Evidence` interface using `Equivocation` as the concrete type. + +```proto +// Equivocation implements the Evidence interface. +message Equivocation { + int64 height = 1; + google.protobuf.Timestamp time = 2; + int64 power = 3; + string consensus_address = 4; +} +``` + +For some `Equivocation` submitted in `block` to be valid, it must satisfy: + +`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` + +Where: + +* `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` +* `block.Timestamp` is the current block timestamp. + +If valid `Equivocation` evidence is included in a block, the validator's stake is +reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module +of what their stake was when the infraction occurred, rather than when the evidence was discovered. +We want to "follow the stake", i.e., the stake that contributed to the infraction +should be slashed, even if it has since been redelegated or started unbonding. + +In addition, the validator is permanently jailed and tombstoned to make it impossible for that +validator to ever re-enter the validator set. + +The `Equivocation` evidence is handled as follows: + +```go +func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) { + logger := k.Logger(ctx) + consAddr := evidence.GetConsensusAddress() + + if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { + // Ignore evidence that cannot be handled. + // + // NOTE: We used to panic with: + // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, + // but this couples the expectations of the app to both Tendermint and + // the simulator. Both are expected to provide the full range of + // allowable but none of the disallowed evidence types. Instead of + // getting this coordination right, it is easier to relax the + // constraints and ignore evidence that cannot be handled. + return + } + + // calculate the age of the evidence + infractionHeight := evidence.GetHeight() + infractionTime := evidence.GetTime() + ageDuration := ctx.BlockHeader().Time.Sub(infractionTime) + ageBlocks := ctx.BlockHeader().Height - infractionHeight + + // Reject evidence if the double-sign is too old. Evidence is considered stale + // if the difference in time and number of blocks is greater than the allowed + // parameters defined. + cp := ctx.ConsensusParams() + if cp != nil && cp.Evidence != nil { + if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks { + logger.Info( + "ignored equivocation; evidence too old", + "validator", consAddr, + "infraction_height", infractionHeight, + "max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks, + "infraction_time", infractionTime, + "max_age_duration", cp.Evidence.MaxAgeDuration, + ) + return + } + } + + validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) + if validator == nil || validator.IsUnbonded() { + // Defensive: Simulation doesn't take unbonding periods into account, and + // Tendermint might break this assumption at some point. + return + } + + if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { + panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) + } + + // ignore if the validator is already tombstoned + if k.slashingKeeper.IsTombstoned(ctx, consAddr) { + logger.Info( + "ignored equivocation; validator already tombstoned", + "validator", consAddr, + "infraction_height", infractionHeight, + "infraction_time", infractionTime, + ) + return + } + + logger.Info( + "confirmed equivocation", + "validator", consAddr, + "infraction_height", infractionHeight, + "infraction_time", infractionTime, + ) + + // We need to retrieve the stake distribution which signed the block, so we + // subtract ValidatorUpdateDelay from the evidence height. + // Note, that this *can* result in a negative "distributionHeight", up to + // -ValidatorUpdateDelay, i.e. at the end of the + // pre-genesis block (none) = at the beginning of the genesis block. + // That's fine since this is just used to filter unbonding delegations & redelegations. + distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay + + // Slash validator. The `power` is the int64 power of the validator as provided + // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via + // ABCI, and now received as evidence. The fraction is passed in to separately + // to slash unbonding and rebonding delegations. + k.slashingKeeper.Slash( + ctx, + consAddr, + k.slashingKeeper.SlashFractionDoubleSign(ctx), + evidence.GetValidatorPower(), distributionHeight, + ) + + // Jail the validator if not already jailed. This will begin unbonding the + // validator if not already unbonding (tombstoned). + if !validator.IsJailed() { + k.slashingKeeper.Jail(ctx, consAddr) + } + + k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) + k.slashingKeeper.Tombstone(ctx, consAddr) +} +``` + +**Note:** The slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module +that emits informative events and finally delegates calls to the `x/staking` module. See documentation +on slashing and jailing in [State Transitions](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md). + +# Client + +## CLI + +A user can query and interact with the `evidence` module using the CLI. + +### Query + +The `query` commands allows users to query `evidence` state. + +```bash +simd query evidence --help +``` + +### evidence + +The `evidence` command allows users to list all evidence or evidence by hash. + +Usage: + +```bash +simd query evidence [flags] +``` + +To query evidence by hash + +Example: + +```bash +simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" +``` + +Example Output: + +```bash +evidence: + consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h + height: 11 + power: 100 + time: "2021-10-20T16:08:38.194017624Z" +``` + +To get all evidence + +Example: + +```bash +simd query evidence +``` + +Example Output: + +```bash +evidence: + consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h + height: 11 + power: 100 + time: "2021-10-20T16:08:38.194017624Z" +pagination: + next_key: null + total: "1" +``` + +## REST + +A user can query the `evidence` module using REST endpoints. + +### Evidence + +Get evidence by hash + +```bash +/cosmos/evidence/v1beta1/evidence/{evidence_hash} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" +``` + +Example Output: + +```bash +{ + "evidence": { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } +} +``` + +### All evidence + +Get all evidence + +```bash +/cosmos/evidence/v1beta1/evidence +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence" +``` + +Example Output: + +```bash +{ + "evidence": [ + { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } + ], + "pagination": { + "total": "1" + } +} +``` + +## gRPC + +A user can query the `evidence` module using gRPC endpoints. + +### Evidence + +Get evidence by hash + +```bash +cosmos.evidence.v1beta1.Query/Evidence +``` + +Example: + +```bash +grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence +``` + +Example Output: + +```bash +{ + "evidence": { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } +} +``` + +### All evidence + +Get all evidence + +```bash +cosmos.evidence.v1beta1.Query/AllEvidence +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence +``` + +Example Output: + +```bash +{ + "evidence": [ + { + "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", + "height": "11", + "power": "100", + "time": "2021-10-20T16:08:38.194017624Z" + } + ], + "pagination": { + "total": "1" + } +} +``` diff --git a/x/evidence/spec/01_concepts.md b/x/evidence/spec/01_concepts.md deleted file mode 100644 index 926a573bb1b4..000000000000 --- a/x/evidence/spec/01_concepts.md +++ /dev/null @@ -1,78 +0,0 @@ - - -# Concepts - -## Evidence - -Any concrete type of evidence submitted to the `x/evidence` module must fulfill the -`Evidence` contract outlined below. Not all concrete types of evidence will fulfill -this contract in the same way and some data may be entirely irrelevant to certain -types of evidence. An additional `ValidatorEvidence`, which extends `Evidence`, -has also been created to define a contract for evidence against malicious validators. - -```go -// Evidence defines the contract which concrete evidence types of misbehavior -// must implement. -type Evidence interface { - proto.Message - - Route() string - Type() string - String() string - Hash() tmbytes.HexBytes - ValidateBasic() error - - // Height at which the infraction occurred - GetHeight() int64 -} - -// ValidatorEvidence extends Evidence interface to define contract -// for evidence against malicious validators -type ValidatorEvidence interface { - Evidence - - // The consensus address of the malicious validator at time of infraction - GetConsensusAddress() sdk.ConsAddress - - // The total power of the malicious validator at time of infraction - GetValidatorPower() int64 - - // The total validator set power at time of infraction - GetTotalPower() int64 -} -``` - -## Registration & Handling - -The `x/evidence` module must first know about all types of evidence it is expected -to handle. This is accomplished by registering the `Route` method in the `Evidence` -contract with what is known as a `Router` (defined below). The `Router` accepts -`Evidence` and attempts to find the corresponding `Handler` for the `Evidence` -via the `Route` method. - -```go -type Router interface { - AddRoute(r string, h Handler) Router - HasRoute(r string) bool - GetRoute(path string) Handler - Seal() - Sealed() bool -} -``` - -The `Handler` (defined below) is responsible for executing the entirety of the -business logic for handling `Evidence`. This typically includes validating the -evidence, both stateless checks via `ValidateBasic` and stateful checks via any -keepers provided to the `Handler`. In addition, the `Handler` may also perform -capabilities such as slashing and jailing a validator. All `Evidence` handled -by the `Handler` should be persisted. - -```go -// Handler defines an agnostic Evidence handler. The handler is responsible -// for executing all corresponding business logic necessary for verifying the -// evidence as valid. In addition, the Handler may execute any necessary -// slashing and potential jailing. -type Handler func(sdk.Context, Evidence) error -``` diff --git a/x/evidence/spec/02_state.md b/x/evidence/spec/02_state.md deleted file mode 100644 index 00d8d05bedff..000000000000 --- a/x/evidence/spec/02_state.md +++ /dev/null @@ -1,19 +0,0 @@ - - -# State - -Currently the `x/evidence` module only stores valid submitted `Evidence` in state. -The evidence state is also stored and exported in the `x/evidence` module's `GenesisState`. - -```protobuf -// GenesisState defines the evidence module's genesis state. -message GenesisState { - // evidence defines all the evidence at genesis. - repeated google.protobuf.Any evidence = 1; -} - -``` - -All `Evidence` is retrieved and stored via a prefix `KVStore` using prefix `0x00` (`KeyPrefixEvidence`). diff --git a/x/evidence/spec/03_messages.md b/x/evidence/spec/03_messages.md deleted file mode 100644 index cd902ec99c60..000000000000 --- a/x/evidence/spec/03_messages.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# Messages - -## MsgSubmitEvidence - -Evidence is submitted through a `MsgSubmitEvidence` message: - -```protobuf -// MsgSubmitEvidence represents a message that supports submitting arbitrary -// Evidence of misbehavior such as equivocation or counterfactual signing. -message MsgSubmitEvidence { - string submitter = 1; - google.protobuf.Any evidence = 2; -} -``` - -Note, the `Evidence` of a `MsgSubmitEvidence` message must have a corresponding -`Handler` registered with the `x/evidence` module's `Router` in order to be processed -and routed correctly. - -Given the `Evidence` is registered with a corresponding `Handler`, it is processed -as follows: - -```go -func SubmitEvidence(ctx Context, evidence Evidence) error { - if _, ok := GetEvidence(ctx, evidence.Hash()); ok { - return sdkerrors.Wrap(types.ErrEvidenceExists, evidence.Hash().String()) - } - if !router.HasRoute(evidence.Route()) { - return sdkerrors.Wrap(types.ErrNoEvidenceHandlerExists, evidence.Route()) - } - - handler := router.GetRoute(evidence.Route()) - if err := handler(ctx, evidence); err != nil { - return sdkerrors.Wrap(types.ErrInvalidEvidence, err.Error()) - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeSubmitEvidence, - sdk.NewAttribute(types.AttributeKeyEvidenceHash, evidence.Hash().String()), - ), - ) - - SetEvidence(ctx, evidence) - return nil -} -``` - -First, there must not already exist valid submitted `Evidence` of the exact same -type. Secondly, the `Evidence` is routed to the `Handler` and executed. Finally, -if there is no error in handling the `Evidence`, an event is emitted and it is persisted to state. diff --git a/x/evidence/spec/04_events.md b/x/evidence/spec/04_events.md deleted file mode 100644 index 35fd77b3f5ac..000000000000 --- a/x/evidence/spec/04_events.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# Events - -The `x/evidence` module emits the following events: - -## Handlers - -### MsgSubmitEvidence - -| Type | Attribute Key | Attribute Value | -| --------------- | ------------- | --------------- | -| submit_evidence | evidence_hash | {evidenceHash} | -| message | module | evidence | -| message | sender | {senderAddress} | -| message | action | submit_evidence | diff --git a/x/evidence/spec/05_params.md b/x/evidence/spec/05_params.md deleted file mode 100644 index 4c48b540afdd..000000000000 --- a/x/evidence/spec/05_params.md +++ /dev/null @@ -1,7 +0,0 @@ - - -# Parameters - -The evidence module does not contain any parameters. diff --git a/x/evidence/spec/06_begin_block.md b/x/evidence/spec/06_begin_block.md deleted file mode 100644 index 1c335d1e46b8..000000000000 --- a/x/evidence/spec/06_begin_block.md +++ /dev/null @@ -1,154 +0,0 @@ - - -# BeginBlock - -## Evidence Handling - -Tendermint blocks can include -[Evidence](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly. - -### Equivocation - -The Cosmos SDK handles two types of evidence inside the ABCI `BeginBlock`: - -* `DuplicateVoteEvidence`, -* `LightClientAttackEvidence`. - -The evidence module handles these two evidence types the same way. First, the Cosmos SDK converts the Tendermint concrete evidence type to an SDK `Evidence` interface using `Equivocation` as the concrete type. - -```proto -// Equivocation implements the Evidence interface. -message Equivocation { - int64 height = 1; - google.protobuf.Timestamp time = 2; - int64 power = 3; - string consensus_address = 4; -} -``` - -For some `Equivocation` submitted in `block` to be valid, it must satisfy: - -`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` - -Where: - -* `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` -* `block.Timestamp` is the current block timestamp. - -If valid `Equivocation` evidence is included in a block, the validator's stake is -reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module -of what their stake was when the infraction occurred, rather than when the evidence was discovered. -We want to "follow the stake", i.e., the stake that contributed to the infraction -should be slashed, even if it has since been redelegated or started unbonding. - -In addition, the validator is permanently jailed and tombstoned to make it impossible for that -validator to ever re-enter the validator set. - -The `Equivocation` evidence is handled as follows: - -```go -func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) { - logger := k.Logger(ctx) - consAddr := evidence.GetConsensusAddress() - - if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { - // Ignore evidence that cannot be handled. - // - // NOTE: We used to panic with: - // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, - // but this couples the expectations of the app to both Tendermint and - // the simulator. Both are expected to provide the full range of - // allowable but none of the disallowed evidence types. Instead of - // getting this coordination right, it is easier to relax the - // constraints and ignore evidence that cannot be handled. - return - } - - // calculate the age of the evidence - infractionHeight := evidence.GetHeight() - infractionTime := evidence.GetTime() - ageDuration := ctx.BlockHeader().Time.Sub(infractionTime) - ageBlocks := ctx.BlockHeader().Height - infractionHeight - - // Reject evidence if the double-sign is too old. Evidence is considered stale - // if the difference in time and number of blocks is greater than the allowed - // parameters defined. - cp := ctx.ConsensusParams() - if cp != nil && cp.Evidence != nil { - if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks { - logger.Info( - "ignored equivocation; evidence too old", - "validator", consAddr, - "infraction_height", infractionHeight, - "max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks, - "infraction_time", infractionTime, - "max_age_duration", cp.Evidence.MaxAgeDuration, - ) - return - } - } - - validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) - if validator == nil || validator.IsUnbonded() { - // Defensive: Simulation doesn't take unbonding periods into account, and - // Tendermint might break this assumption at some point. - return - } - - if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { - panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) - } - - // ignore if the validator is already tombstoned - if k.slashingKeeper.IsTombstoned(ctx, consAddr) { - logger.Info( - "ignored equivocation; validator already tombstoned", - "validator", consAddr, - "infraction_height", infractionHeight, - "infraction_time", infractionTime, - ) - return - } - - logger.Info( - "confirmed equivocation", - "validator", consAddr, - "infraction_height", infractionHeight, - "infraction_time", infractionTime, - ) - - // We need to retrieve the stake distribution which signed the block, so we - // subtract ValidatorUpdateDelay from the evidence height. - // Note, that this *can* result in a negative "distributionHeight", up to - // -ValidatorUpdateDelay, i.e. at the end of the - // pre-genesis block (none) = at the beginning of the genesis block. - // That's fine since this is just used to filter unbonding delegations & redelegations. - distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay - - // Slash validator. The `power` is the int64 power of the validator as provided - // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via - // ABCI, and now received as evidence. The fraction is passed in to separately - // to slash unbonding and rebonding delegations. - k.slashingKeeper.Slash( - ctx, - consAddr, - k.slashingKeeper.SlashFractionDoubleSign(ctx), - evidence.GetValidatorPower(), distributionHeight, - ) - - // Jail the validator if not already jailed. This will begin unbonding the - // validator if not already unbonding (tombstoned). - if !validator.IsJailed() { - k.slashingKeeper.Jail(ctx, consAddr) - } - - k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) - k.slashingKeeper.Tombstone(ctx, consAddr) -} -``` - -**Note:** The slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module -that emits informative events and finally delegates calls to the `x/staking` module. See documentation -on slashing and jailing in [State Transitions](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md). diff --git a/x/evidence/spec/07_client.md b/x/evidence/spec/07_client.md deleted file mode 100644 index 52a4b34f70fe..000000000000 --- a/x/evidence/spec/07_client.md +++ /dev/null @@ -1,188 +0,0 @@ -# Client - -## CLI - -A user can query and interact with the `evidence` module using the CLI. - -### Query - -The `query` commands allows users to query `evidence` state. - -```bash -simd query evidence --help -``` - -### evidence - -The `evidence` command allows users to list all evidence or evidence by hash. - -Usage: - -```bash -simd query evidence [flags] -``` - -To query evidence by hash - -Example: - -```bash -simd query evidence "DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" -``` - -Example Output: - -```bash -evidence: - consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h - height: 11 - power: 100 - time: "2021-10-20T16:08:38.194017624Z" -``` - -To get all evidence - -Example: - -```bash -simd query evidence -``` - -Example Output: - -```bash -evidence: - consensus_address: cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h - height: 11 - power: 100 - time: "2021-10-20T16:08:38.194017624Z" -pagination: - next_key: null - total: "1" -``` - -## REST - -A user can query the `evidence` module using REST endpoints. - -### Evidence - -Get evidence by hash - -```bash -/cosmos/evidence/v1beta1/evidence/{evidence_hash} -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence/DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660" -``` - -Example Output: - -```bash -{ - "evidence": { - "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", - "height": "11", - "power": "100", - "time": "2021-10-20T16:08:38.194017624Z" - } -} -``` - -### All evidence - -Get all evidence - -```bash -/cosmos/evidence/v1beta1/evidence -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/evidence/v1beta1/evidence" -``` - -Example Output: - -```bash -{ - "evidence": [ - { - "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", - "height": "11", - "power": "100", - "time": "2021-10-20T16:08:38.194017624Z" - } - ], - "pagination": { - "total": "1" - } -} -``` - -## gRPC - -A user can query the `evidence` module using gRPC endpoints. - -### Evidence - -Get evidence by hash - -```bash -cosmos.evidence.v1beta1.Query/Evidence -``` - -Example: - -```bash -grpcurl -plaintext -d '{"evidence_hash":"DF0C23E8634E480F84B9D5674A7CDC9816466DEC28A3358F73260F68D28D7660"}' localhost:9090 cosmos.evidence.v1beta1.Query/Evidence -``` - -Example Output: - -```bash -{ - "evidence": { - "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", - "height": "11", - "power": "100", - "time": "2021-10-20T16:08:38.194017624Z" - } -} -``` - -### All evidence - -Get all evidence - -```bash -cosmos.evidence.v1beta1.Query/AllEvidence -``` - -Example: - -```bash -grpcurl -plaintext localhost:9090 cosmos.evidence.v1beta1.Query/AllEvidence -``` - -Example Output: - -```bash -{ - "evidence": [ - { - "consensus_address": "cosmosvalcons1ntk8eualewuprz0gamh8hnvcem2nrcdsgz563h", - "height": "11", - "power": "100", - "time": "2021-10-20T16:08:38.194017624Z" - } - ], - "pagination": { - "total": "1" - } -} -``` diff --git a/x/evidence/spec/README.md b/x/evidence/spec/README.md deleted file mode 100644 index a6b3d92054d1..000000000000 --- a/x/evidence/spec/README.md +++ /dev/null @@ -1,40 +0,0 @@ - - -# `x/evidence` - -## Table of Contents - - - -1. **[Concepts](01_concepts.md)** -2. **[State](02_state.md)** -3. **[Messages](03_messages.md)** -4. **[Events](04_events.md)** -5. **[Params](05_params.md)** -6. **[BeginBlock](06_begin_block.md)** - -## Abstract - -`x/evidence` is an implementation of a Cosmos SDK module, per [ADR 009](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-009-evidence-module.md), -that allows for the submission and handling of arbitrary evidence of misbehavior such -as equivocation and counterfactual signing. - -The evidence module differs from standard evidence handling which typically expects the -underlying consensus engine, e.g. Tendermint, to automatically submit evidence when -it is discovered by allowing clients and foreign chains to submit more complex evidence -directly. - -All concrete evidence types must implement the `Evidence` interface contract. Submitted -`Evidence` is first routed through the evidence module's `Router` in which it attempts -to find a corresponding registered `Handler` for that specific `Evidence` type. -Each `Evidence` type must have a `Handler` registered with the evidence module's -keeper in order for it to be successfully routed and executed. - -Each corresponding handler must also fulfill the `Handler` interface contract. The -`Handler` for a given `Evidence` type can perform any arbitrary state transitions -such as slashing, jailing, and tombstoning. diff --git a/x/feegrant/README.md b/x/feegrant/README.md index 99cde43c0345..5f0b6ed2d960 100644 --- a/x/feegrant/README.md +++ b/x/feegrant/README.md @@ -1,7 +1,377 @@ -# Fee Grant +# `x/feegrant` -* [Fee Grant](spec/README.md) - Grant fee allowances for executing transactions. +## Abstract + +This document specifies the fee grant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-029-fee-grant-module.md). + +This module allows accounts to grant fee allowances and to use fees from their accounts. Grantees can execute any transaction without the need to maintain sufficient fees. + +## Contents + +* [Concepts](#concepts) +* [State](#state) + * [FeeAllowance](#feeallowance) + * [FeeAllowanceQueue](#feeallowancequeue) +* [Messages](#messages) + * [Msg/GrantAllowance](#msggrantallowance) + * [Msg/RevokeAllowance](#msgrevokeallowance) +* [Events](#events) +* [Msg Server](#msg-server) + * [MsgGrantAllowance](#msggrantallowance-1) + * [MsgRevokeAllowance](#msgrevokeallowance-1) + * [Exec fee allowance](#exec-fee-allowance) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + + + +# Concepts + +## Grant + +`Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L76-L77 + +`FeeAllowanceI` looks like: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/fees.go#L9-L32 + +## Fee Allowance types + +There are two types of fee allowances present at the moment: + +* `BasicAllowance` +* `PeriodicAllowance` +* `AllowedMsgAllowance` + +## BasicAllowance + +`BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26 + +* `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available coins from `granter` account address before the expiration. + +* `expiration` specifies an optional time when this allowance expires. If the value is left empty, there is no expiry for the grant. + +* When a grant is created with empty values for `spend_limit` and `expiration`, it is still a valid grant. It won't restrict the `grantee` to use any number of coins from `granter` and it won't have any expiration. The only way to restrict the `grantee` is by revoking the grant. + +## PeriodicAllowance + +`PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L29-L54 + +* `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`. + +* `period` is the specific period of time, after each period passes, `period_can_spend` will be reset. + +* `period_spend_limit` specifies the maximum number of coins that can be spent in the period. + +* `period_can_spend` is the number of coins left to be spent before the period_reset time. + +* `period_reset` keeps track of when a next period reset should happen. + +## AllowedMsgAllowance + +`AllowedMsgAllowance` is a fee allowance, it can be any of `BasicFeeAllowance`, `PeriodicAllowance` but restricted only to the allowed messages mentioned by the granter. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L56-L66 + +* `allowance` is either `BasicAllowance` or `PeriodicAllowance`. + +* `allowed_messages` is array of messages allowed to execute the given allowance. + +## FeeGranter flag + +`feegrant` module introduces a `FeeGranter` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/cmd.go#L236-L246 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/tx/tx.go#L109-L109 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/auth/tx/builder.go#L270-L279 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/tx/v1beta1/tx.proto#L196-L217 + +Example cmd: + +```go +./simd tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake" +``` + +## Granted Fee Deductions + +Fees are deducted from grants in the `x/auth` ante handler. To learn more about how ante handlers work, read the [Auth Module AnteHandlers Guide](../../auth/spec/03_antehandlers.md). + +## Gas + +In order to prevent DoS attacks, using a filtered `x/feegrant` incurs gas. The SDK must assure that the `grantee`'s transactions all conform to the filter set by the `granter`. The SDK does this by iterating over the allowed messages in the filter and charging 10 gas per filtered message. The SDK will then iterate over the messages being sent by the `grantee` to ensure the messages adhere to the filter, also charging 10 gas per message. The SDK will stop iterating and fail the transaction if it finds a message that does not conform to the filter. + +**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance. + +## Pruning + +A queue in the state maintained with the prefix of expiration of the grants and checks them on EndBlock with the current block time for every block to prune. + + + +# State + +## FeeAllowance + +Fee Allowances are identified by combining `Grantee` (the account address of fee allowance grantee) with the `Granter` (the account address of fee allowance granter). + +Fee allowance grants are stored in the state as follows: + +* Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/feegrant.pb.go#L221-L229 + +## FeeAllowanceQueue + +Fee Allowances queue items are identified by combining the `FeeAllowancePrefixQueue` (i.e., 0x01), `expiration`, `grantee` (the account address of fee allowance grantee), `granter` (the account address of fee allowance granter). Endblocker checks `FeeAllowanceQueue` state for the expired grants and prunes them from `FeeAllowance` if there are any found. + +Fee allowance queue keys are stored in the state as follows: + +* Grant: `0x01 | expiration_bytes | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> EmptyBytes` + + + +# Messages + +## Msg/GrantAllowance + +A fee allowance grant will be created with the `MsgGrantAllowance` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L23-L36 + +## Msg/RevokeAllowance + +An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L41-L50 + + + +# Events + +The feegrant module emits the following events: + +# Msg Server + +## MsgGrantAllowance + +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ---------------- | +| message | action | set_feegrant | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | + +## MsgRevokeAllowance + +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ---------------- | +| message | action | revoke_feegrant | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | + +## Exec fee allowance + +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ---------------- | +| message | action | use_feegrant | +| message | granter | {granterAddress} | +| message | grantee | {granteeAddress} | + + + +# Client + +## CLI + +A user can query and interact with the `feegrant` module using the CLI. + +### Query + +The `query` commands allow users to query `feegrant` state. + +```sh +simd query feegrant --help +``` + +#### grant + +The `grant` command allows users to query a grant for a given granter-grantee pair. + +```sh +simd query feegrant grant [granter] [grantee] [flags] +``` + +Example: + +```sh +simd query feegrant grant cosmos1.. cosmos1.. +``` + +Example Output: + +```yml +allowance: + '@type': /cosmos.feegrant.v1beta1.BasicAllowance + expiration: null + spend_limit: + - amount: "100" + denom: stake +grantee: cosmos1.. +granter: cosmos1.. +``` + +#### grants + +The `grants` command allows users to query all grants for a given grantee. + +```sh +simd query feegrant grants [grantee] [flags] +``` + +Example: + +```sh +simd query feegrant grants cosmos1.. +``` + +Example Output: + +```yml +allowances: +- allowance: + '@type': /cosmos.feegrant.v1beta1.BasicAllowance + expiration: null + spend_limit: + - amount: "100" + denom: stake + grantee: cosmos1.. + granter: cosmos1.. +pagination: + next_key: null + total: "0" +``` + +### Transactions + +The `tx` commands allow users to interact with the `feegrant` module. + +```sh +simd tx feegrant --help +``` + +#### grant + +The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit. + +```sh +simd tx feegrant grant [granter] [grantee] [flags] +``` + +Example (one-time spend limit): + +```sh +simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake +``` + +Example (periodic spend limit): + +```sh +simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake +``` + +#### revoke + +The `revoke` command allows users to revoke a granted fee allowance. + +```sh +simd tx feegrant revoke [granter] [grantee] [flags] +``` + +Example: + +```sh +simd tx feegrant revoke cosmos1.. cosmos1.. +``` + +## gRPC + +A user can query the `feegrant` module using gRPC endpoints. + +### Allowance + +The `Allowance` endpoint allows users to query a granted fee allowance. + +```sh +cosmos.feegrant.v1beta1.Query/Allowance +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"grantee":"cosmos1..","granter":"cosmos1.."}' \ + localhost:9090 \ + cosmos.feegrant.v1beta1.Query/Allowance +``` + +Example Output: + +```json +{ + "allowance": { + "granter": "cosmos1..", + "grantee": "cosmos1..", + "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} + } +} +``` + +### Allowances + +The `Allowances` endpoint allows users to query all granted fee allowances for a given grantee. + +```sh +cosmos.feegrant.v1beta1.Query/Allowances +``` + +Example: + +```sh +grpcurl -plaintext \ + -d '{"address":"cosmos1.."}' \ + localhost:9090 \ + cosmos.feegrant.v1beta1.Query/Allowances +``` + +Example Output: + +```json +{ + "allowances": [ + { + "granter": "cosmos1..", + "grantee": "cosmos1..", + "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} + } + ], + "pagination": { + "total": "1" + } +} +``` diff --git a/x/feegrant/spec/01_concepts.md b/x/feegrant/spec/01_concepts.md deleted file mode 100644 index 65ed18e7dbe7..000000000000 --- a/x/feegrant/spec/01_concepts.md +++ /dev/null @@ -1,93 +0,0 @@ - - -# Concepts - -## Grant - -`Grant` is stored in the KVStore to record a grant with full context. Every grant will contain `granter`, `grantee` and what kind of `allowance` is granted. `granter` is an account address who is giving permission to `grantee` (the beneficiary account address) to pay for some or all of `grantee`'s transaction fees. `allowance` defines what kind of fee allowance (`BasicAllowance` or `PeriodicAllowance`, see below) is granted to `grantee`. `allowance` accepts an interface which implements `FeeAllowanceI`, encoded as `Any` type. There can be only one existing fee grant allowed for a `grantee` and `granter`, self grants are not allowed. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L76-L77 - -`FeeAllowanceI` looks like: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/fees.go#L9-L32 - -## Fee Allowance types - -There are two types of fee allowances present at the moment: - -* `BasicAllowance` -* `PeriodicAllowance` -* `AllowedMsgAllowance` - -## BasicAllowance - -`BasicAllowance` is permission for `grantee` to use fee from a `granter`'s account. If any of the `spend_limit` or `expiration` reaches its limit, the grant will be removed from the state. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L13-L26 - -* `spend_limit` is the limit of coins that are allowed to be used from the `granter` account. If it is empty, it assumes there's no spend limit, `grantee` can use any number of available coins from `granter` account address before the expiration. - -* `expiration` specifies an optional time when this allowance expires. If the value is left empty, there is no expiry for the grant. - -* When a grant is created with empty values for `spend_limit` and `expiration`, it is still a valid grant. It won't restrict the `grantee` to use any number of coins from `granter` and it won't have any expiration. The only way to restrict the `grantee` is by revoking the grant. - -## PeriodicAllowance - -`PeriodicAllowance` is a repeating fee allowance for the mentioned period, we can mention when the grant can expire as well as when a period can reset. We can also define the maximum number of coins that can be used in a mentioned period of time. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L29-L54 - -* `basic` is the instance of `BasicAllowance` which is optional for periodic fee allowance. If empty, the grant will have no `expiration` and no `spend_limit`. - -* `period` is the specific period of time, after each period passes, `period_can_spend` will be reset. - -* `period_spend_limit` specifies the maximum number of coins that can be spent in the period. - -* `period_can_spend` is the number of coins left to be spent before the period_reset time. - -* `period_reset` keeps track of when a next period reset should happen. - -## AllowedMsgAllowance - -`AllowedMsgAllowance` is a fee allowance, it can be any of `BasicFeeAllowance`, `PeriodicAllowance` but restricted only to the allowed messages mentioned by the granter. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/feegrant.proto#L56-L66 - -* `allowance` is either `BasicAllowance` or `PeriodicAllowance`. - -* `allowed_messages` is array of messages allowed to execute the given allowance. - -## FeeGranter flag - -`feegrant` module introduces a `FeeGranter` flag for CLI for the sake of executing transactions with fee granter. When this flag is set, `clientCtx` will append the granter account address for transactions generated through CLI. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/cmd.go#L236-L246 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/client/tx/tx.go#L109-L109 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/auth/tx/builder.go#L270-L279 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/tx/v1beta1/tx.proto#L196-L217 - -Example cmd: - -```go -./simd tx gov submit-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --from validator-key --fee-granter=cosmos1xh44hxt7spr67hqaa7nyx5gnutrz5fraw6grxn --chain-id=testnet --fees="10stake" -``` - -## Granted Fee Deductions - -Fees are deducted from grants in the `x/auth` ante handler. To learn more about how ante handlers work, read the [Auth Module AnteHandlers Guide](../../auth/spec/03_antehandlers.md). - -## Gas - -In order to prevent DoS attacks, using a filtered `x/feegrant` incurs gas. The SDK must assure that the `grantee`'s transactions all conform to the filter set by the `granter`. The SDK does this by iterating over the allowed messages in the filter and charging 10 gas per filtered message. The SDK will then iterate over the messages being sent by the `grantee` to ensure the messages adhere to the filter, also charging 10 gas per message. The SDK will stop iterating and fail the transaction if it finds a message that does not conform to the filter. - -**WARNING**: The gas is charged against the granted allowance. Ensure your messages conform to the filter, if any, before sending transactions using your allowance. - -## Pruning - -A queue in the state maintained with the prefix of expiration of the grants and checks them on EndBlock with the current block time for every block to prune. diff --git a/x/feegrant/spec/02_state.md b/x/feegrant/spec/02_state.md deleted file mode 100644 index c4d39c130e23..000000000000 --- a/x/feegrant/spec/02_state.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# State - -## FeeAllowance - -Fee Allowances are identified by combining `Grantee` (the account address of fee allowance grantee) with the `Granter` (the account address of fee allowance granter). - -Fee allowance grants are stored in the state as follows: - -* Grant: `0x00 | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> ProtocolBuffer(Grant)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/feegrant/feegrant.pb.go#L221-L229 - -## FeeAllowanceQueue - -Fee Allowances queue items are identified by combining the `FeeAllowancePrefixQueue` (i.e., 0x01), `expiration`, `grantee` (the account address of fee allowance grantee), `granter` (the account address of fee allowance granter). Endblocker checks `FeeAllowanceQueue` state for the expired grants and prunes them from `FeeAllowance` if there are any found. - -Fee allowance queue keys are stored in the state as follows: - -* Grant: `0x01 | expiration_bytes | grantee_addr_len (1 byte) | grantee_addr_bytes | granter_addr_len (1 byte) | granter_addr_bytes -> EmptyBytes` diff --git a/x/feegrant/spec/03_messages.md b/x/feegrant/spec/03_messages.md deleted file mode 100644 index fd59be7f2cab..000000000000 --- a/x/feegrant/spec/03_messages.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# Messages - -## Msg/GrantAllowance - -A fee allowance grant will be created with the `MsgGrantAllowance` message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L23-L36 - -## Msg/RevokeAllowance - -An allowed grant fee allowance can be removed with the `MsgRevokeAllowance` message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/feegrant/v1beta1/tx.proto#L41-L50 diff --git a/x/feegrant/spec/04_events.md b/x/feegrant/spec/04_events.md deleted file mode 100644 index e443558f7c54..000000000000 --- a/x/feegrant/spec/04_events.md +++ /dev/null @@ -1,33 +0,0 @@ - - -# Events - -The feegrant module emits the following events: - -# Msg Server - -## MsgGrantAllowance - -| Type | Attribute Key | Attribute Value | -| ------- | ------------- | ---------------- | -| message | action | set_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | - -## MsgRevokeAllowance - -| Type | Attribute Key | Attribute Value | -| ------- | ------------- | ---------------- | -| message | action | revoke_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | - -## Exec fee allowance - -| Type | Attribute Key | Attribute Value | -| ------- | ------------- | ---------------- | -| message | action | use_feegrant | -| message | granter | {granterAddress} | -| message | grantee | {granteeAddress} | diff --git a/x/feegrant/spec/05_client.md b/x/feegrant/spec/05_client.md deleted file mode 100644 index 52c1d97268f1..000000000000 --- a/x/feegrant/spec/05_client.md +++ /dev/null @@ -1,184 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `feegrant` module using the CLI. - -### Query - -The `query` commands allow users to query `feegrant` state. - -```sh -simd query feegrant --help -``` - -#### grant - -The `grant` command allows users to query a grant for a given granter-grantee pair. - -```sh -simd query feegrant grant [granter] [grantee] [flags] -``` - -Example: - -```sh -simd query feegrant grant cosmos1.. cosmos1.. -``` - -Example Output: - -```yml -allowance: - '@type': /cosmos.feegrant.v1beta1.BasicAllowance - expiration: null - spend_limit: - - amount: "100" - denom: stake -grantee: cosmos1.. -granter: cosmos1.. -``` - -#### grants - -The `grants` command allows users to query all grants for a given grantee. - -```sh -simd query feegrant grants [grantee] [flags] -``` - -Example: - -```sh -simd query feegrant grants cosmos1.. -``` - -Example Output: - -```yml -allowances: -- allowance: - '@type': /cosmos.feegrant.v1beta1.BasicAllowance - expiration: null - spend_limit: - - amount: "100" - denom: stake - grantee: cosmos1.. - granter: cosmos1.. -pagination: - next_key: null - total: "0" -``` - -### Transactions - -The `tx` commands allow users to interact with the `feegrant` module. - -```sh -simd tx feegrant --help -``` - -#### grant - -The `grant` command allows users to grant fee allowances to another account. The fee allowance can have an expiration date, a total spend limit, and/or a periodic spend limit. - -```sh -simd tx feegrant grant [granter] [grantee] [flags] -``` - -Example (one-time spend limit): - -```sh -simd tx feegrant grant cosmos1.. cosmos1.. --spend-limit 100stake -``` - -Example (periodic spend limit): - -```sh -simd tx feegrant grant cosmos1.. cosmos1.. --period 3600 --period-limit 10stake -``` - -#### revoke - -The `revoke` command allows users to revoke a granted fee allowance. - -```sh -simd tx feegrant revoke [granter] [grantee] [flags] -``` - -Example: - -```sh -simd tx feegrant revoke cosmos1.. cosmos1.. -``` - -## gRPC - -A user can query the `feegrant` module using gRPC endpoints. - -### Allowance - -The `Allowance` endpoint allows users to query a granted fee allowance. - -```sh -cosmos.feegrant.v1beta1.Query/Allowance -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"grantee":"cosmos1..","granter":"cosmos1.."}' \ - localhost:9090 \ - cosmos.feegrant.v1beta1.Query/Allowance -``` - -Example Output: - -```json -{ - "allowance": { - "granter": "cosmos1..", - "grantee": "cosmos1..", - "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} - } -} -``` - -### Allowances - -The `Allowances` endpoint allows users to query all granted fee allowances for a given grantee. - -```sh -cosmos.feegrant.v1beta1.Query/Allowances -``` - -Example: - -```sh -grpcurl -plaintext \ - -d '{"address":"cosmos1.."}' \ - localhost:9090 \ - cosmos.feegrant.v1beta1.Query/Allowances -``` - -Example Output: - -```json -{ - "allowances": [ - { - "granter": "cosmos1..", - "grantee": "cosmos1..", - "allowance": {"@type":"/cosmos.feegrant.v1beta1.BasicAllowance","spendLimit":[{"denom":"stake","amount":"100"}]} - } - ], - "pagination": { - "total": "1" - } -} -``` diff --git a/x/feegrant/spec/README.md b/x/feegrant/spec/README.md deleted file mode 100644 index 8f08a51aeb3a..000000000000 --- a/x/feegrant/spec/README.md +++ /dev/null @@ -1,37 +0,0 @@ - - -# Fee grant - -## Abstract - -This document specifies the fee grant module. For the full ADR, please see [Fee Grant ADR-029](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-029-fee-grant-module.md). - -This module allows accounts to grant fee allowances and to use fees from their accounts. Grantees can execute any transaction without the need to maintain sufficient fees. - -## Contents - -1. **[Concepts](01_concepts.md)** - * [Grant](01_concepts.md#grant) - * [Fee Allowance types](01_concepts.md#fee-allowance-types) - * [BasicAllowance](01_concepts.md#basicallowance) - * [PeriodicAllowance](01_concepts.md#periodicallowance) - * [FeeAccount flag](01_concepts.md#feeaccount-flag) - * [Granted Fee Deductions](01_concepts.md#granted-fee-deductions) - * [Gas](01_concepts.md#gas) -2. **[State](02_state.md)** - * [FeeAllowance](02_state.md#feeallowance) -3. **[Messages](03_messages.md)** - * [Msg/GrantAllowance](03_messages.md#msggrantallowance) - * [Msg/RevokeAllowance](03_messages.md#msgrevokeallowance) -4. **[Events](04_events.md)** - * [MsgGrantAllowance](04_events.md#msggrantallowance) - * [MsgRevokeAllowance](04_events.md#msgrevokeallowance) - * [Exec fee allowance](04_events.md#exec-fee-allowance) -5. **[Client](05_client.md)** - * [CLI](05_client.md#cli) - * [gRPC](05_client.md#grpc) diff --git a/x/gov/README.md b/x/gov/README.md index 66ab133646f0..7a5344dba177 100644 --- a/x/gov/README.md +++ b/x/gov/README.md @@ -1,7 +1,2628 @@ -# Governance +# `x/gov` -* [Governance](spec/README.md) - On-chain proposals and voting. +## Abstract + +This paper specifies the Governance module of the Cosmos-SDK, which was first +described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in +June 2016. + +The module enables Cosmos-SDK based blockchain to support an on-chain governance +system. In this system, holders of the native staking token of the chain can vote +on proposals on a 1 token 1 vote basis. Next is a list of features the module +currently supports: + +* **Proposal submission:** Users can submit proposals with a deposit. Once the +minimum deposit is reached, proposal enters voting period +* **Vote:** Participants can vote on proposals that reached MinDeposit +* **Inheritance and penalties:** Delegators inherit their validator's vote if +they don't vote themselves. +* **Claiming deposit:** Users that deposited on proposals can recover their +deposits if the proposal was accepted OR if the proposal never entered voting period. + +This module will be used in the Cosmos Hub, the first Hub in the Cosmos network. +Features that may be added in the future are described in [Future Improvements](05_future_improvements.md). + +## Contents + +The following specification uses *ATOM* as the native staking token. The module +can be adapted to any Proof-Of-Stake blockchain by replacing *ATOM* with the native +staking token of the chain. + +* [Concepts](#concepts) + * [Proposal submission](#proposal-submission) + * [Right to submit a proposal](#right-to-submit-a-proposal) + * [Proposal Messages](#proposal-messages) + * [Deposit](#deposit) + * [Vote](#vote) + * [Participants](#participants) + * [Voting period](#voting-period) + * [Option set](#option-set) + * [Weighted Votes](#weighted-votes) + * [Quorum](#quorum) + * [Threshold](#threshold) + * [Inheritance](#inheritance) + * [Validator’s punishment for non-voting](#validators-punishment-for-non-voting) + * [Governance address](#governance-address) + * [Software Upgrade](#software-upgrade) +* [State](#state) + * [Proposals](#proposals) + * [Parameters and base types](#parameters-and-base-types) + * [DepositParams](#depositparams) + * [VotingParams](#votingparams) + * [TallyParams](#tallyparams) + * [Deposit](#deposit-1) + * [ValidatorGovInfo](#validatorgovinfo) + * [Stores](#stores) + * [Proposal Processing Queue](#proposal-processing-queue) + * [Legacy Proposal](#legacy-proposal) +* [Messages](#messages) + * [Proposal Submission](#proposal-submission-1) + * [Deposit](#deposit-2) + * [Vote](#vote-1) +* [Events](#events) + * [EndBlocker](#endblocker) + * [Handlers](#handlers) + * [MsgSubmitProposal](#msgsubmitproposal) + * [MsgVote](#msgvote) + * [MsgVoteWeighted](#msgvoteweighted) + * [MsgDeposit](#msgdeposit) +* [Future Improvements](#future-improvements) +* [Parameters](#parameters) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) +* [Metadata](#metadata) + + + +# Concepts + +*Disclaimer: This is work in progress. Mechanisms are susceptible to change.* + +The governance process is divided in a few steps that are outlined below: + +* **Proposal submission:** Proposal is submitted to the blockchain with a + deposit. +* **Vote:** Once deposit reaches a certain value (`MinDeposit`), proposal is + confirmed and vote opens. Bonded Atom holders can then send `TxGovVote` + transactions to vote on the proposal. +* **Execution** After a period of time, the votes are tallied and depending + on the result, the messages in the proposal will be executed. + +## Proposal submission + +### Right to submit a proposal + +Every account can submit proposals by sending a `MsgSubmitProposal` transaction. +Once a proposal is submitted, it is identified by its unique `proposalID`. + +### Proposal Messages + +A proposal includes an array of `sdk.Msg`s which are executed automatically if the +proposal passes. The messages are executed by the governance `ModuleAccount` itself. Modules +such as `x/upgrade`, that want to allow certain messages to be executed by governance +only should add a whitelist within the respective msg server, granting the governance +module the right to execute the message once a quorum has been reached. The governance +module uses the `MsgServiceRouter` to check that these messages are correctly constructed +and have a respective path to execute on but do not perform a full validity check. + +## Deposit + +To prevent spam, proposals must be submitted with a deposit in the coins defined by +the `MinDeposit` param. + +When a proposal is submitted, it has to be accompanied with a deposit that must be +strictly positive, but can be inferior to `MinDeposit`. The submitter doesn't need +to pay for the entire deposit on their own. The newly created proposal is stored in +an *inactive proposal queue* and stays there until its deposit passes the `MinDeposit`. +Other token holders can increase the proposal's deposit by sending a `Deposit` +transaction. If a proposal doesn't pass the `MinDeposit` before the deposit end time +(the time when deposits are no longer accepted), the proposal will be destroyed: the +proposal will be removed from state and the deposit will be burned (see x/gov `EndBlocker`). +When a proposal deposit passes the `MinDeposit` threshold (even during the proposal +submission) before the deposit end time, the proposal will be moved into the +*active proposal queue* and the voting period will begin. + +The deposit is kept in escrow and held by the governance `ModuleAccount` until the +proposal is finalized (passed or rejected). + +### Deposit refund and burn + +When a proposal is finalized, the coins from the deposit are either refunded or burned +according to the final tally of the proposal: + +* If the proposal is approved or rejected but *not* vetoed, each deposit will be + automatically refunded to its respective depositor (transferred from the governance + `ModuleAccount`). +* When the proposal is vetoed with greater than 1/3, deposits will be burned from the + governance `ModuleAccount` and the proposal information along with its deposit + information will be removed from state. +* All refunded or burned deposits are removed from the state. Events are issued when + burning or refunding a deposit. + +## Vote + +### Participants + +*Participants* are users that have the right to vote on proposals. On the +Cosmos Hub, participants are bonded Atom holders. Unbonded Atom holders and +other users do not get the right to participate in governance. However, they +can submit and deposit on proposals. + +Note that some *participants* can be forbidden to vote on a proposal under a +certain validator if: + +* *participant* bonded or unbonded Atoms to said validator after proposal + entered voting period. +* *participant* became validator after proposal entered voting period. + +This does not prevent *participant* to vote with Atoms bonded to other +validators. For example, if a *participant* bonded some Atoms to validator A +before a proposal entered voting period and other Atoms to validator B after +proposal entered voting period, only the vote under validator B will be +forbidden. + +### Voting period + +Once a proposal reaches `MinDeposit`, it immediately enters `Voting period`. We +define `Voting period` as the interval between the moment the vote opens and +the moment the vote closes. `Voting period` should always be shorter than +`Unbonding period` to prevent double voting. The initial value of +`Voting period` is 2 weeks. + +### Option set + +The option set of a proposal refers to the set of choices a participant can +choose from when casting its vote. + +The initial option set includes the following options: + +* `Yes` +* `No` +* `NoWithVeto` +* `Abstain` + +`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option +allows voters to signal that they do not intend to vote in favor or against the +proposal but accept the result of the vote. + +_Note: from the UI, for urgent proposals we should maybe add a β€˜Not Urgent’ +option that casts a `NoWithVeto` vote._ + +### Weighted Votes + +[ADR-037](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md) introduces the weighted vote feature which allows a staker to split their votes into several voting options. For example, it could use 70% of its voting power to vote Yes and 30% of its voting power to vote No. + +Often times the entity owning that address might not be a single individual. For example, a company might have different stakeholders who want to vote differently, and so it makes sense to allow them to split their voting power. Currently, it is not possible for them to do "passthrough voting" and giving their users voting rights over their tokens. However, with this system, exchanges can poll their users for voting preferences, and then vote on-chain proportionally to the results of the poll. + +To represent weighted vote on chain, we use the following Protobuf message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L33-L43 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L136-L150 + +For a weighted vote to be valid, the `options` field must not contain duplicate vote options, and the sum of weights of all options must be equal to 1. + +### Quorum + +Quorum is defined as the minimum percentage of voting power that needs to be +cast on a proposal for the result to be valid. + +### Threshold + +Threshold is defined as the minimum proportion of `Yes` votes (excluding +`Abstain` votes) for the proposal to be accepted. + +Initially, the threshold is set at 50% of `Yes` votes, excluding `Abstain` +votes. A possibility to veto exists if more than 1/3rd of all votes are +`NoWithVeto` votes. Note, both of these values are derived from the `TallyParams` +on-chain parameter, which is modifiable by governance. +This means that proposals are accepted iff: + +* There exist bonded tokens. +* Quorum has been achieved. +* The proportion of `Abstain` votes is inferior to 1/1. +* The proportion of `NoWithVeto` votes is inferior to 1/3, including + `Abstain` votes. +* The proportion of `Yes` votes, excluding `Abstain` votes, at the end of + the voting period is superior to 1/2. + +### Inheritance + +If a delegator does not vote, it will inherit its validator vote. + +* If the delegator votes before its validator, it will not inherit from the + validator's vote. +* If the delegator votes after its validator, it will override its validator + vote with its own. If the proposal is urgent, it is possible + that the vote will close before delegators have a chance to react and + override their validator's vote. This is not a problem, as proposals require more than 2/3rd of the total voting power to pass before the end of the voting period. Because as little as 1/3 + 1 validation power could collude to censor transactions, non-collusion is already assumed for ranges exceeding this threshold. + +### Validator’s punishment for non-voting + +At present, validators are not punished for failing to vote. + +### Governance address + +Later, we may add permissioned keys that could only sign txs from certain modules. For the MVP, the `Governance address` will be the main validator address generated at account creation. This address corresponds to a different PrivKey than the Tendermint PrivKey which is responsible for signing consensus messages. Validators thus do not have to sign governance transactions with the sensitive Tendermint PrivKey. + +## Software Upgrade + +If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade +their software to the new version that was voted. This process is divided into +two steps: + +### Signal + +After a `SoftwareUpgradeProposal` is accepted, validators are expected to +download and install the new version of the software while continuing to run +the previous version. Once a validator has downloaded and installed the +upgrade, it will start signaling to the network that it is ready to switch by +including the proposal's `proposalID` in its *precommits*.(_Note: Confirmation +that we want it in the precommit?_) + +Note: There is only one signal slot per *precommit*. If several +`SoftwareUpgradeProposals` are accepted in a short timeframe, a pipeline will +form and they will be implemented one after the other in the order that they +were accepted. + +### Switch + +Once a block contains more than 2/3rd *precommits* where a common +`SoftwareUpgradeProposal` is signaled, all the nodes (including validator +nodes, non-validating full nodes and light-nodes) are expected to switch to the +new version of the software. + +Validators and full nodes can use an automation tool, such as [Cosmovisor](https://github.com/cosmos/cosmos-sdk/blob/main/cosmovisor/README.md), for automatically switching version of the chain. + + + +# State + +## Proposals + +`Proposal` objects are used to tally votes and generally track the proposal's state. +They contain an array of arbitrary `sdk.Msg`'s which the governance module will attempt +to resolve and then execute if the proposal passes. `Proposal`'s are identified by a +unique id and contains a series of timestamps: `submit_time`, `deposit_end_time`, +`voting_start_time`, `voting_end_time` which track the lifecycle of a proposal + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L42-L59 + +A proposal will generally require more than just a set of messages to explain its +purpose but need some greater justification and allow a means for interested participants +to discuss and debate the proposal. +In most cases, **it is encouraged to have an off-chain system that supports the on-chain governance process**. +To accommodate for this, a proposal contains a special **`metadata`** field, a string, +which can be used to add context to the proposal. The `metadata` field allows custom use for networks, +however, it is expected that the field contains a URL or some form of CID using a system such as +[IPFS](https://docs.ipfs.io/concepts/content-addressing/). To support the case of +interoperability across networks, the SDK recommends that the `metadata` represents +the following `JSON` template: + +```json +{ + "title": "...", + "description": "...", + "forum": "...", // a link to the discussion platform (i.e. Discord) + "other": "..." // any extra data that doesn't correspond to the other fields +} +``` + +This makes it far easier for clients to support multiple networks. + +The metadata has a maximum length that is chosen by the app developer, and +passed into the gov keeper as a config. The default maximum length in the SDK is 255 characters. + +### Writing a module that uses governance + +There are many aspects of a chain, or of the individual modules that you may want to +use governance to perform such as changing various parameters. This is very simple +to do. First, write out your message types and `MsgServer` implementation. Add an +`authority` field to the keeper which will be populated in the constructor with the +governance module account: `govKeeper.GetGovernanceAccount().GetAddress()`. Then for +the methods in the `msg_server.go`, perform a check on the message that the signer +matches `authority`. This will prevent any user from executing that message. + +## Parameters and base types + +`Parameters` define the rules according to which votes are run. There can only +be one active parameter set at any given time. If governance wants to change a +parameter set, either to modify a value or add/remove a parameter field, a new +parameter set has to be created and the previous one rendered inactive. + +### DepositParams + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L102-L112 + +### VotingParams + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L114-L118 + +### TallyParams + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L120-L132 + +Parameters are stored in a global `GlobalParams` KVStore. + +Additionally, we introduce some basic types: + +```go +type Vote byte + +const ( + VoteYes = 0x1 + VoteNo = 0x2 + VoteNoWithVeto = 0x3 + VoteAbstain = 0x4 +) + +type ProposalType string + +const ( + ProposalTypePlainText = "Text" + ProposalTypeSoftwareUpgrade = "SoftwareUpgrade" +) + +type ProposalStatus byte + + +const ( + StatusNil ProposalStatus = 0x00 + StatusDepositPeriod ProposalStatus = 0x01 // Proposal is submitted. Participants can deposit on it but not vote + StatusVotingPeriod ProposalStatus = 0x02 // MinDeposit is reached, participants can vote + StatusPassed ProposalStatus = 0x03 // Proposal passed and successfully executed + StatusRejected ProposalStatus = 0x04 // Proposal has been rejected + StatusFailed ProposalStatus = 0x05 // Proposal passed but failed execution +) +``` + +## Deposit + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L34-L40 + +## ValidatorGovInfo + +This type is used in a temp map when tallying + +```go + type ValidatorGovInfo struct { + Minus sdk.Dec + Vote Vote + } +``` + +## Stores + +*Note: Stores are KVStores in the multi-store. The key to find the store is the first parameter in the list* + +We will use one KVStore `Governance` to store two mappings: + +* A mapping from `proposalID|'proposal'` to `Proposal`. +* A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows + us to query all addresses that voted on the proposal along with their vote by + doing a range query on `proposalID:addresses`. +* A mapping from `ParamsKey|'Params'` to `Params`. This map allows to query all + x/gov params. + +For pseudocode purposes, here are the two function we will use to read or write in stores: + +* `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore +* `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore + +## Proposal Processing Queue + +**Store:** + +* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the + `ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`, + all the proposals that have reached the end of their voting period are processed. + To process a finished proposal, the application tallies the votes, computes the + votes of each validator and checks if every validator in the validator set has + voted. If the proposal is accepted, deposits are refunded. Finally, the proposal + content `Handler` is executed. + +And the pseudocode for the `ProposalProcessingQueue`: + +```go + in EndBlock do + + for finishedProposalID in GetAllFinishedProposalIDs(block.Time) + proposal = load(Governance, ) // proposal is a const key + + validators = Keeper.getAllValidators() + tmpValMap := map(sdk.AccAddress)ValidatorGovInfo + + // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes + for each validator in validators + tmpValMap(validator.OperatorAddr).Minus = 0 + + // Tally + voterIterator = rangeQuery(Governance, ) //return all the addresses that voted on the proposal + for each (voterAddress, vote) in voterIterator + delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter + + for each delegation in delegations + // make sure delegation.Shares does NOT include shares being unbonded + tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares + proposal.updateTally(vote, delegation.Shares) + + _, isVal = stakingKeeper.getValidator(voterAddress) + if (isVal) + tmpValMap(voterAddress).Vote = vote + + tallyingParam = load(GlobalParams, 'TallyingParam') + + // Update tally if validator voted + for each validator in validators + if tmpValMap(validator).HasVoted + proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus)) + + + + // Check if proposal is accepted or rejected + totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes + if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto) + // proposal was accepted at the end of the voting period + // refund deposits (non-voters already punished) + for each (amount, depositor) in proposal.Deposits + depositor.AtomBalance += amount + + stateWriter, err := proposal.Handler() + if err != nil + // proposal passed but failed during state execution + proposal.CurrentStatus = ProposalStatusFailed + else + // proposal pass and state is persisted + proposal.CurrentStatus = ProposalStatusAccepted + stateWriter.save() + else + // proposal was rejected + proposal.CurrentStatus = ProposalStatusRejected + + store(Governance, , proposal) +``` + +## Legacy Proposal + +A legacy proposal is the old implementation of governance proposal. +Contrary to proposal that can contain any messages, a legacy proposal allows to submit a set of pre-defined proposals. +These proposal are defined by their types. + +While proposals should use the new implementation of the governance proposal, we need still to use legacy proposal in order to submit a `software-upgrade` and a `cancel-software-upgrade` proposal. + +More information on how to submit proposals in the [client section](07_client.md). + + + +# Messages + +## Proposal Submission + +Proposals can be submitted by any account via a `MsgSubmitProposal` +transaction. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L33-L43 + +All `sdk.Msgs` passed into the `messages` field of a `MsgSubmitProposal` message +must be registered in the app's `MsgServiceRouter`. Each of these messages must +have one signer, namely the gov module account. And finally, the metadata length +must not be larger than the `maxMetadataLen` config passed into the gov keeper. + +**State modifications:** + +* Generate new `proposalID` +* Create new `Proposal` +* Initialise `Proposal`'s attributes +* Decrease balance of sender by `InitialDeposit` +* If `MinDeposit` is reached: + * Push `proposalID` in `ProposalProcessingQueue` +* Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount` + +A `MsgSubmitProposal` transaction can be handled according to the following +pseudocode. + +```go +// PSEUDOCODE // +// Check if MsgSubmitProposal is valid. If it is, create proposal // + +upon receiving txGovSubmitProposal from sender do + + if !correctlyFormatted(txGovSubmitProposal) + // check if proposal is correctly formatted and the messages have routes to other modules. Includes fee payment. + // check if all messages' unique Signer is the gov acct. + // check if the metadata is not too long. + throw + + initialDeposit = txGovSubmitProposal.InitialDeposit + if (initialDeposit.Atoms <= 0) OR (sender.AtomBalance < initialDeposit.Atoms) + // InitialDeposit is negative or null OR sender has insufficient funds + throw + + if (txGovSubmitProposal.Type != ProposalTypePlainText) OR (txGovSubmitProposal.Type != ProposalTypeSoftwareUpgrade) + + sender.AtomBalance -= initialDeposit.Atoms + + depositParam = load(GlobalParams, 'DepositParam') + + proposalID = generate new proposalID + proposal = NewProposal() + + proposal.Messages = txGovSubmitProposal.Messages + proposal.Metadata = txGovSubmitProposal.Metadata + proposal.TotalDeposit = initialDeposit + proposal.SubmitTime = + proposal.DepositEndTime = .Add(depositParam.MaxDepositPeriod) + proposal.Deposits.append({initialDeposit, sender}) + proposal.Submitter = sender + proposal.YesVotes = 0 + proposal.NoVotes = 0 + proposal.NoWithVetoVotes = 0 + proposal.AbstainVotes = 0 + proposal.CurrentStatus = ProposalStatusOpen + + store(Proposals, , proposal) // Store proposal in Proposals mapping + return proposalID +``` + +## Deposit + +Once a proposal is submitted, if +`Proposal.TotalDeposit < ActiveParam.MinDeposit`, Atom holders can send +`MsgDeposit` transactions to increase the proposal's deposit. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L90-L97 + +**State modifications:** + +* Decrease balance of sender by `deposit` +* Add `deposit` of sender in `proposal.Deposits` +* Increase `proposal.TotalDeposit` by sender's `deposit` +* If `MinDeposit` is reached: + * Push `proposalID` in `ProposalProcessingQueueEnd` +* Transfer `Deposit` from the `proposer` to the governance `ModuleAccount` + +A `MsgDeposit` transaction has to go through a number of checks to be valid. +These checks are outlined in the following pseudocode. + +```go +// PSEUDOCODE // +// Check if MsgDeposit is valid. If it is, increase deposit and check if MinDeposit is reached + +upon receiving txGovDeposit from sender do + // check if proposal is correctly formatted. Includes fee payment. + + if !correctlyFormatted(txGovDeposit) + throw + + proposal = load(Proposals, ) // proposal is a const key, proposalID is variable + + if (proposal == nil) + // There is no proposal for this proposalID + throw + + if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.CurrentStatus != ProposalStatusOpen) + + // deposit is negative or null + // OR sender has insufficient funds + // OR proposal is not open for deposit anymore + + throw + + depositParam = load(GlobalParams, 'DepositParam') + + if (CurrentBlock >= proposal.SubmitBlock + depositParam.MaxDepositPeriod) + proposal.CurrentStatus = ProposalStatusClosed + + else + // sender can deposit + sender.AtomBalance -= txGovDeposit.Deposit.Atoms + + proposal.Deposits.append({txGovVote.Deposit, sender}) + proposal.TotalDeposit.Plus(txGovDeposit.Deposit) + + if (proposal.TotalDeposit >= depositParam.MinDeposit) + // MinDeposit is reached, vote opens + + proposal.VotingStartBlock = CurrentBlock + proposal.CurrentStatus = ProposalStatusActive + ProposalProcessingQueue.push(txGovDeposit.ProposalID) + + store(Proposals, , proposal) +``` + +## Vote + +Once `ActiveParam.MinDeposit` is reached, voting period starts. From there, +bonded Atom holders are able to send `MsgVote` transactions to cast their +vote on the proposal. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L64-L72 + +**State modifications:** + +* Record `Vote` of sender + +*Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker.* + +Next is a pseudocode outline of the way `MsgVote` transactions are +handled: + +```go + // PSEUDOCODE // + // Check if MsgVote is valid. If it is, count vote// + + upon receiving txGovVote from sender do + // check if proposal is correctly formatted. Includes fee payment. + + if !correctlyFormatted(txGovDeposit) + throw + + proposal = load(Proposals, ) + + if (proposal == nil) + // There is no proposal for this proposalID + throw + + + if (proposal.CurrentStatus == ProposalStatusActive) + + + // Sender can vote if + // Proposal is active + // Sender has some bonds + + store(Governance, , txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end. +``` + + + +# Events + +The governance module emits the following events: + +## EndBlocker + +| Type | Attribute Key | Attribute Value | +| ----------------- | --------------- | ---------------- | +| inactive_proposal | proposal_id | {proposalID} | +| inactive_proposal | proposal_result | {proposalResult} | +| active_proposal | proposal_id | {proposalID} | +| active_proposal | proposal_result | {proposalResult} | + +## Handlers + +### MsgSubmitProposal + +| Type | Attribute Key | Attribute Value | +| ------------------- | ------------------- | --------------- | +| submit_proposal | proposal_id | {proposalID} | +| submit_proposal [0] | voting_period_start | {proposalID} | +| proposal_deposit | amount | {depositAmount} | +| proposal_deposit | proposal_id | {proposalID} | +| message | module | governance | +| message | action | submit_proposal | +| message | sender | {senderAddress} | + +* [0] Event only emitted if the voting period starts during the submission. + +### MsgVote + +| Type | Attribute Key | Attribute Value | +| ------------- | ------------- | --------------- | +| proposal_vote | option | {voteOption} | +| proposal_vote | proposal_id | {proposalID} | +| message | module | governance | +| message | action | vote | +| message | sender | {senderAddress} | + +### MsgVoteWeighted + +| Type | Attribute Key | Attribute Value | +| ------------- | ------------- | ------------------------ | +| proposal_vote | option | {weightedVoteOptions} | +| proposal_vote | proposal_id | {proposalID} | +| message | module | governance | +| message | action | vote | +| message | sender | {senderAddress} | + +### MsgDeposit + +| Type | Attribute Key | Attribute Value | +| -------------------- | ------------------- | --------------- | +| proposal_deposit | amount | {depositAmount} | +| proposal_deposit | proposal_id | {proposalID} | +| proposal_deposit [0] | voting_period_start | {proposalID} | +| message | module | governance | +| message | action | deposit | +| message | sender | {senderAddress} | + +* [0] Event only emitted if the voting period starts during the submission. + + + +# Future Improvements + +The current documentation only describes the minimum viable product for the +governance module. Future improvements may include: + +* **`BountyProposals`:** If accepted, a `BountyProposal` creates an open + bounty. The `BountyProposal` specifies how many Atoms will be given upon + completion. These Atoms will be taken from the `reserve pool`. After a + `BountyProposal` is accepted by governance, anybody can submit a + `SoftwareUpgradeProposal` with the code to claim the bounty. Note that once a + `BountyProposal` is accepted, the corresponding funds in the `reserve pool` + are locked so that payment can always be honored. In order to link a + `SoftwareUpgradeProposal` to an open bounty, the submitter of the + `SoftwareUpgradeProposal` will use the `Proposal.LinkedProposal` attribute. + If a `SoftwareUpgradeProposal` linked to an open bounty is accepted by + governance, the funds that were reserved are automatically transferred to the + submitter. +* **Complex delegation:** Delegators could choose other representatives than + their validators. Ultimately, the chain of representatives would always end + up to a validator, but delegators could inherit the vote of their chosen + representative before they inherit the vote of their validator. In other + words, they would only inherit the vote of their validator if their other + appointed representative did not vote. +* **Better process for proposal review:** There would be two parts to + `proposal.Deposit`, one for anti-spam (same as in MVP) and an other one to + reward third party auditors. + + + +# Parameters + +The governance module contains the following parameters: + +| Key | Type | Example | +|---------------|--------|----------------------------------------------------------------------------------------------------| +| depositparams | object | {"min_deposit":[{"denom":"uatom","amount":"10000000"}],"max_deposit_period":"172800000000000"} | +| votingparams | object | {"voting_period":"172800000000000"} | +| tallyparams | object | {"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto":"0.334000000000000000"} | + +## SubKeys + +| Key | Type | Example | +|--------------------|------------------|-----------------------------------------| +| min_deposit | array (coins) | [{"denom":"uatom","amount":"10000000"}] | +| max_deposit_period | string (time ns) | "172800000000000" | +| voting_period | string (time ns) | "172800000000000" | +| quorum | string (dec) | "0.334000000000000000" | +| threshold | string (dec) | "0.500000000000000000" | +| veto | string (dec) | "0.334000000000000000" | + +**NOTE**: The governance module contains parameters that are objects unlike other +modules. If only a subset of parameters are desired to be changed, only they need +to be included and not the entire parameter object structure. + + + +# Client + +## CLI + +A user can query and interact with the `gov` module using the CLI. + +### Query + +The `query` commands allow users to query `gov` state. + +```bash +simd query gov --help +``` + +#### deposit + +The `deposit` command allows users to query a deposit for a given proposal from a given depositor. + +```bash +simd query gov deposit [proposal-id] [depositer-addr] [flags] +``` + +Example: + +```bash +simd query gov deposit 1 cosmos1.. +``` + +Example Output: + +```bash +amount: +- amount: "100" + denom: stake +depositor: cosmos1.. +proposal_id: "1" +``` + +#### deposits + +The `deposits` command allows users to query all deposits for a given proposal. + +```bash +simd query gov deposits [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov deposits 1 +``` + +Example Output: + +```bash +deposits: +- amount: + - amount: "100" + denom: stake + depositor: cosmos1.. + proposal_id: "1" +pagination: + next_key: null + total: "0" +``` + +#### param + +The `param` command allows users to query a given parameter for the `gov` module. + +```bash +simd query gov param [param-type] [flags] +``` + +Example: + +```bash +simd query gov param voting +``` + +Example Output: + +```bash +voting_period: "172800000000000" +``` + +#### params + +The `params` command allows users to query all parameters for the `gov` module. + +```bash +simd query gov params [flags] +``` + +Example: + +```bash +simd query gov params +``` + +Example Output: + +```bash +deposit_params: + max_deposit_period: "172800000000000" + min_deposit: + - amount: "10000000" + denom: stake +tally_params: + quorum: "0.334000000000000000" + threshold: "0.500000000000000000" + veto_threshold: "0.334000000000000000" +voting_params: + voting_period: "172800000000000" +``` + +#### proposal + +The `proposal` command allows users to query a given proposal. + +```bash +simd query gov proposal [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov proposal 1 +``` + +Example Output: + +```bash +deposit_end_time: "2022-03-30T11:50:20.819676256Z" +final_tally_result: + abstain_count: "0" + no_count: "0" + no_with_veto_count: "0" + yes_count: "0" +id: "1" +messages: +- '@type': /cosmos.bank.v1beta1.MsgSend + amount: + - amount: "10" + denom: stake + from_address: cosmos1.. + to_address: cosmos1.. +metadata: AQ== +status: PROPOSAL_STATUS_DEPOSIT_PERIOD +submit_time: "2022-03-28T11:50:20.819676256Z" +total_deposit: +- amount: "10" + denom: stake +voting_end_time: null +voting_start_time: null +``` + +#### proposals + +The `proposals` command allows users to query all proposals with optional filters. + +```bash +simd query gov proposals [flags] +``` + +Example: + +```bash +simd query gov proposals +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +proposals: +- deposit_end_time: "2022-03-30T11:50:20.819676256Z" + final_tally_result: + abstain_count: "0" + no_count: "0" + no_with_veto_count: "0" + yes_count: "0" + id: "1" + messages: + - '@type': /cosmos.bank.v1beta1.MsgSend + amount: + - amount: "10" + denom: stake + from_address: cosmos1.. + to_address: cosmos1.. + metadata: AQ== + status: PROPOSAL_STATUS_DEPOSIT_PERIOD + submit_time: "2022-03-28T11:50:20.819676256Z" + total_deposit: + - amount: "10" + denom: stake + voting_end_time: null + voting_start_time: null +- deposit_end_time: "2022-03-30T14:02:41.165025015Z" + final_tally_result: + abstain_count: "0" + no_count: "0" + no_with_veto_count: "0" + yes_count: "0" + id: "2" + messages: + - '@type': /cosmos.bank.v1beta1.MsgSend + amount: + - amount: "10" + denom: stake + from_address: cosmos1.. + to_address: cosmos1.. + metadata: AQ== + status: PROPOSAL_STATUS_DEPOSIT_PERIOD + submit_time: "2022-03-28T14:02:41.165025015Z" + total_deposit: + - amount: "10" + denom: stake + voting_end_time: null + voting_start_time: null +``` + +#### proposer + +The `proposer` command allows users to query the proposer for a given proposal. + +```bash +simd query gov proposer [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov proposer 1 +``` + +Example Output: + +```bash +proposal_id: "1" +proposer: cosmos1.. +``` + +#### tally + +The `tally` command allows users to query the tally of a given proposal vote. + +```bash +simd query gov tally [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov tally 1 +``` + +Example Output: + +```bash +abstain: "0" +"no": "0" +no_with_veto: "0" +"yes": "1" +``` + +#### vote + +The `vote` command allows users to query a vote for a given proposal. + +```bash +simd query gov vote [proposal-id] [voter-addr] [flags] +``` + +Example: + +```bash +simd query gov vote 1 cosmos1.. +``` + +Example Output: + +```bash +option: VOTE_OPTION_YES +options: +- option: VOTE_OPTION_YES + weight: "1.000000000000000000" +proposal_id: "1" +voter: cosmos1.. +``` + +#### votes + +The `votes` command allows users to query all votes for a given proposal. + +```bash +simd query gov votes [proposal-id] [flags] +``` + +Example: + +```bash +simd query gov votes 1 +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +votes: +- option: VOTE_OPTION_YES + options: + - option: VOTE_OPTION_YES + weight: "1.000000000000000000" + proposal_id: "1" + voter: cosmos1.. +``` + +### Transactions + +The `tx` commands allow users to interact with the `gov` module. + +```bash +simd tx gov --help +``` + +#### deposit + +The `deposit` command allows users to deposit tokens for a given proposal. + +```bash +simd tx gov deposit [proposal-id] [deposit] [flags] +``` + +Example: + +```bash +simd tx gov deposit 1 10000000stake --from cosmos1.. +``` + +#### submit-proposal + +The `submit-proposal` command allows users to submit a governance proposal along with some messages and metadata. +Messages, metadata and deposit are defined in a JSON file. + +```bash +simd tx gov submit-proposal [path-to-proposal-json] [flags] +``` + +Example: + +```bash +simd tx gov submit-proposal /path/to/proposal.json --from cosmos1.. +``` + +where `proposal.json` contains: + +```json +{ + "messages": [ + { + "@type": "/cosmos.bank.v1beta1.MsgSend", + "from_address": "cosmos1...", // The gov module module address + "to_address": "cosmos1...", + "amount":[{"denom": "stake","amount": "10"}] + } + ], + "metadata": "AQ==", + "deposit": "10stake" +} +``` + +#### submit-legacy-proposal + +The `submit-legacy-proposal` command allows users to submit a governance legacy proposal along with an initial deposit. + +```bash +simd tx gov submit-legacy-proposal [command] [flags] +``` + +Example: + +```bash +simd tx gov submit-legacy-proposal --title="Test Proposal" --description="testing" --type="Text" --deposit="100000000stake" --from cosmos1.. +``` + +Example (`cancel-software-upgrade`): + +```bash +simd tx gov submit-legacy-proposal cancel-software-upgrade --title="Test Proposal" --description="testing" --deposit="100000000stake" --from cosmos1.. +``` + +Example (`community-pool-spend`): + +```bash +simd tx gov submit-legacy-proposal community-pool-spend proposal.json --from cosmos1.. +``` + +```json +{ + "title": "Test Proposal", + "description": "testing, 1, 2, 3", + "recipient": "cosmos1..", + "amount": "10000000stake", + "deposit": "10000000stake" +} +``` + +Example (`param-change`): + +```bash +simd tx gov submit-legacy-proposal param-change proposal.json --from cosmos1.. +``` + +```json +{ + "title": "Test Proposal", + "description": "testing, testing, 1, 2, 3", + "changes": [ + { + "subspace": "staking", + "key": "MaxValidators", + "value": 100 + } + ], + "deposit": "10000000stake" +} +``` + +Example (`software-upgrade`): + +```bash +simd tx gov submit-legacy-proposal software-upgrade v2 --title="Test Proposal" --description="testing, testing, 1, 2, 3" --upgrade-height 1000000 --from cosmos1.. +``` + +#### vote + +The `vote` command allows users to submit a vote for a given governance proposal. + +```bash +simd tx gov vote [command] [flags] +``` + +Example: + +```bash +simd tx gov vote 1 yes --from cosmos1.. +``` + +#### weighted-vote + +The `weighted-vote` command allows users to submit a weighted vote for a given governance proposal. + +```bash +simd tx gov weighted-vote [proposal-id] [weighted-options] [flags] +``` + +Example: + +```bash +simd tx gov weighted-vote 1 yes=0.5,no=0.5 --from cosmos1.. +``` + +## gRPC + +A user can query the `gov` module using gRPC endpoints. + +### Proposal + +The `Proposal` endpoint allows users to query a given proposal. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Proposal +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Proposal +``` + +Example Output: + +```bash +{ + "proposal": { + "proposalId": "1", + "content": {"@type":"/cosmos.gov.v1beta1.TextProposal","description":"testing, testing, 1, 2, 3","title":"Test Proposal"}, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2021-09-16T19:40:08.712440474Z", + "depositEndTime": "2021-09-18T19:40:08.712440474Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "votingStartTime": "2021-09-16T19:40:08.712440474Z", + "votingEndTime": "2021-09-18T19:40:08.712440474Z" + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Proposal +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Proposal +``` + +Example Output: + +```bash +{ + "proposal": { + "id": "1", + "messages": [ + {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} + ], + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yesCount": "0", + "abstainCount": "0", + "noCount": "0", + "noWithVetoCount": "0" + }, + "submitTime": "2022-03-28T11:50:20.819676256Z", + "depositEndTime": "2022-03-30T11:50:20.819676256Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "votingStartTime": "2022-03-28T14:25:26.644857113Z", + "votingEndTime": "2022-03-30T14:25:26.644857113Z", + "metadata": "AQ==" + } +} +``` + + +### Proposals + +The `Proposals` endpoint allows users to query all proposals with optional filters. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Proposals +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "proposalId": "1", + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2022-03-28T11:50:20.819676256Z", + "depositEndTime": "2022-03-30T11:50:20.819676256Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000010" + } + ], + "votingStartTime": "2022-03-28T14:25:26.644857113Z", + "votingEndTime": "2022-03-30T14:25:26.644857113Z" + }, + { + "proposalId": "2", + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "finalTallyResult": { + "yes": "0", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + }, + "submitTime": "2022-03-28T14:02:41.165025015Z", + "depositEndTime": "2022-03-30T14:02:41.165025015Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10" + } + ], + "votingStartTime": "0001-01-01T00:00:00Z", + "votingEndTime": "0001-01-01T00:00:00Z" + } + ], + "pagination": { + "total": "2" + } +} + +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Proposals +``` + +Example: + +```bash +grpcurl -plaintext \ + localhost:9090 \ + cosmos.gov.v1.Query/Proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "id": "1", + "messages": [ + {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} + ], + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "finalTallyResult": { + "yesCount": "0", + "abstainCount": "0", + "noCount": "0", + "noWithVetoCount": "0" + }, + "submitTime": "2022-03-28T11:50:20.819676256Z", + "depositEndTime": "2022-03-30T11:50:20.819676256Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10000000010" + } + ], + "votingStartTime": "2022-03-28T14:25:26.644857113Z", + "votingEndTime": "2022-03-30T14:25:26.644857113Z", + "metadata": "AQ==" + }, + { + "id": "2", + "messages": [ + {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} + ], + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "finalTallyResult": { + "yesCount": "0", + "abstainCount": "0", + "noCount": "0", + "noWithVetoCount": "0" + }, + "submitTime": "2022-03-28T14:02:41.165025015Z", + "depositEndTime": "2022-03-30T14:02:41.165025015Z", + "totalDeposit": [ + { + "denom": "stake", + "amount": "10" + } + ], + "metadata": "AQ==" + } + ], + "pagination": { + "total": "2" + } +} +``` + +### Vote + +The `Vote` endpoint allows users to query a vote for a given proposal. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Vote +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1","voter":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Vote +``` + +Example Output: + +```bash +{ + "vote": { + "proposalId": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1000000000000000000" + } + ] + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Vote +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1","voter":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Vote +``` + +Example Output: + +```bash +{ + "vote": { + "proposalId": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } +} +``` + +### Votes + +The `Votes` endpoint allows users to query all votes for a given proposal. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Votes +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposalId": "1", + "voter": "cosmos1..", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1000000000000000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Votes +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposalId": "1", + "voter": "cosmos1..", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +### Params + +The `Params` endpoint allows users to query all parameters for the `gov` module. + + + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"params_type":"voting"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "votingParams": { + "votingPeriod": "172800s" + }, + "depositParams": { + "maxDepositPeriod": "0s" + }, + "tallyParams": { + "quorum": "MA==", + "threshold": "MA==", + "vetoThreshold": "MA==" + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"params_type":"voting"}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Params +``` + +Example Output: + +```bash +{ + "votingParams": { + "votingPeriod": "172800s" + } +} +``` + +### Deposit + +The `Deposit` endpoint allows users to query a deposit for a given proposal from a given depositor. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Deposit +``` + +Example: + +```bash +grpcurl -plaintext \ + '{"proposal_id":"1","depositor":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Deposit +``` + +Example Output: + +```bash +{ + "deposit": { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Deposit +``` + +Example: + +```bash +grpcurl -plaintext \ + '{"proposal_id":"1","depositor":"cosmos1.."}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Deposit +``` + +Example Output: + +```bash +{ + "deposit": { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +### deposits + +The `Deposits` endpoint allows users to query all deposits for a given proposal. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/Deposits +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/Deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/Deposits +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1.Query/Deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposalId": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "total": "1" + } +} +``` + +### TallyResult + +The `TallyResult` endpoint allows users to query the tally of a given proposal. + +Using legacy v1beta1: + +```bash +cosmos.gov.v1beta1.Query/TallyResult +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1beta1.Query/TallyResult +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + } +} +``` + +Using v1: + +```bash +cosmos.gov.v1.Query/TallyResult +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"proposal_id":"1"}' \ + localhost:9090 \ + cosmos.gov.v1.Query/TallyResult +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "noWithVeto": "0" + } +} +``` + +## REST + +A user can query the `gov` module using REST endpoints. + +### proposal + +The `proposals` endpoint allows users to query a given proposal. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1 +``` + +Example Output: + +```bash +{ + "proposal": { + "proposal_id": "1", + "content": null, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2022-03-28T11:50:20.819676256Z", + "deposit_end_time": "2022-03-30T11:50:20.819676256Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000010" + } + ], + "voting_start_time": "2022-03-28T14:25:26.644857113Z", + "voting_end_time": "2022-03-30T14:25:26.644857113Z" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1 +``` + +Example Output: + +```bash +{ + "proposal": { + "id": "1", + "messages": [ + { + "@type": "/cosmos.bank.v1beta1.MsgSend", + "from_address": "cosmos1..", + "to_address": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10" + } + ] + } + ], + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes_count": "0", + "abstain_count": "0", + "no_count": "0", + "no_with_veto_count": "0" + }, + "submit_time": "2022-03-28T11:50:20.819676256Z", + "deposit_end_time": "2022-03-30T11:50:20.819676256Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "voting_start_time": "2022-03-28T14:25:26.644857113Z", + "voting_end_time": "2022-03-30T14:25:26.644857113Z", + "metadata": "AQ==" + } +} +``` + +### proposals + +The `proposals` endpoint also allows users to query all proposals with optional filters. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "proposal_id": "1", + "content": null, + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2022-03-28T11:50:20.819676256Z", + "deposit_end_time": "2022-03-30T11:50:20.819676256Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000" + } + ], + "voting_start_time": "2022-03-28T14:25:26.644857113Z", + "voting_end_time": "2022-03-30T14:25:26.644857113Z" + }, + { + "proposal_id": "2", + "content": null, + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "final_tally_result": { + "yes": "0", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + }, + "submit_time": "2022-03-28T14:02:41.165025015Z", + "deposit_end_time": "2022-03-30T14:02:41.165025015Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10" + } + ], + "voting_start_time": "0001-01-01T00:00:00Z", + "voting_end_time": "0001-01-01T00:00:00Z" + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals +``` + +Example Output: + +```bash +{ + "proposals": [ + { + "id": "1", + "messages": [ + { + "@type": "/cosmos.bank.v1beta1.MsgSend", + "from_address": "cosmos1..", + "to_address": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10" + } + ] + } + ], + "status": "PROPOSAL_STATUS_VOTING_PERIOD", + "final_tally_result": { + "yes_count": "0", + "abstain_count": "0", + "no_count": "0", + "no_with_veto_count": "0" + }, + "submit_time": "2022-03-28T11:50:20.819676256Z", + "deposit_end_time": "2022-03-30T11:50:20.819676256Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10000000010" + } + ], + "voting_start_time": "2022-03-28T14:25:26.644857113Z", + "voting_end_time": "2022-03-30T14:25:26.644857113Z", + "metadata": "AQ==" + }, + { + "id": "2", + "messages": [ + { + "@type": "/cosmos.bank.v1beta1.MsgSend", + "from_address": "cosmos1..", + "to_address": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10" + } + ] + } + ], + "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", + "final_tally_result": { + "yes_count": "0", + "abstain_count": "0", + "no_count": "0", + "no_with_veto_count": "0" + }, + "submit_time": "2022-03-28T14:02:41.165025015Z", + "deposit_end_time": "2022-03-30T14:02:41.165025015Z", + "total_deposit": [ + { + "denom": "stake", + "amount": "10" + } + ], + "voting_start_time": null, + "voting_end_time": null, + "metadata": "AQ==" + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` + +### voter vote + +The `votes` endpoint allows users to query a vote for a given proposal. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes/cosmos1.. +``` + +Example Output: + +```bash +{ + "vote": { + "proposal_id": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id}/votes/{voter} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1/votes/cosmos1.. +``` + +Example Output: + +```bash +{ + "vote": { + "proposal_id": "1", + "voter": "cosmos1..", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ], + "metadata": "" + } +} +``` + +### votes + +The `votes` endpoint allows users to query all votes for a given proposal. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/votes +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposal_id": "1", + "voter": "cosmos1..", + "option": "VOTE_OPTION_YES", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id}/votes +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1/votes +``` + +Example Output: + +```bash +{ + "votes": [ + { + "proposal_id": "1", + "voter": "cosmos1..", + "options": [ + { + "option": "VOTE_OPTION_YES", + "weight": "1.000000000000000000" + } + ], + "metadata": "" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### params + +The `params` endpoint allows users to query all parameters for the `gov` module. + + + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/params/{params_type} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/params/voting +``` + +Example Output: + +```bash +{ + "voting_params": { + "voting_period": "172800s" + }, + "deposit_params": { + "min_deposit": [ + ], + "max_deposit_period": "0s" + }, + "tally_params": { + "quorum": "0.000000000000000000", + "threshold": "0.000000000000000000", + "veto_threshold": "0.000000000000000000" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/params/{params_type} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/params/voting +``` + +Example Output: + +```bash +{ + "voting_params": { + "voting_period": "172800s" + }, + "deposit_params": { + "min_deposit": [ + ], + "max_deposit_period": "0s" + }, + "tally_params": { + "quorum": "0.000000000000000000", + "threshold": "0.000000000000000000", + "veto_threshold": "0.000000000000000000" + } +} +``` + +### deposits + +The `deposits` endpoint allows users to query a deposit for a given proposal from a given depositor. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits/{depositor} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits/cosmos1.. +``` + +Example Output: + +```bash +{ + "deposit": { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id}/deposits/{depositor} +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1/deposits/cosmos1.. +``` + +Example Output: + +```bash +{ + "deposit": { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } +} +``` + +### proposal deposits + +The `deposits` endpoint allows users to query all deposits for a given proposal. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id}/deposits +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1/deposits +``` + +Example Output: + +```bash +{ + "deposits": [ + { + "proposal_id": "1", + "depositor": "cosmos1..", + "amount": [ + { + "denom": "stake", + "amount": "10000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### tally + +The `tally` endpoint allows users to query the tally of a given proposal. + +Using legacy v1beta1: + +```bash +/cosmos/gov/v1beta1/proposals/{proposal_id}/tally +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1beta1/proposals/1/tally +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + } +} +``` + +Using v1: + +```bash +/cosmos/gov/v1/proposals/{proposal_id}/tally +``` + +Example: + +```bash +curl localhost:1317/cosmos/gov/v1/proposals/1/tally +``` + +Example Output: + +```bash +{ + "tally": { + "yes": "1000000", + "abstain": "0", + "no": "0", + "no_with_veto": "0" + } +} +``` + + + +# Metadata + +The gov module has two locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the gov and group modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. + +## Proposal + +Location: off-chain as json object stored on IPFS (mirrors [group proposal](../../group/spec/06_metadata.md#proposal)) + +```json +{ + "title": "", + "authors": "", + "summary": "", + "details": "", + "proposalForumURL": "", + "voteOptionContext": "", +} +``` + +## Vote + +Location: on-chain as json within 255 character limit (mirrors [group vote](../../group/spec/06_metadata.md#vote)) + +```json +{ + "justification": "", +} +``` diff --git a/x/gov/spec/01_concepts.md b/x/gov/spec/01_concepts.md deleted file mode 100644 index fe2fba2c6473..000000000000 --- a/x/gov/spec/01_concepts.md +++ /dev/null @@ -1,203 +0,0 @@ - - -# Concepts - -_Disclaimer: This is work in progress. Mechanisms are susceptible to change._ - -The governance process is divided in a few steps that are outlined below: - -* **Proposal submission:** Proposal is submitted to the blockchain with a - deposit. -* **Vote:** Once deposit reaches a certain value (`MinDeposit`), proposal is - confirmed and vote opens. Bonded Atom holders can then send `TxGovVote` - transactions to vote on the proposal. -* **Execution** After a period of time, the votes are tallied and depending - on the result, the messages in the proposal will be executed. - -## Proposal submission - -### Right to submit a proposal - -Every account can submit proposals by sending a `MsgSubmitProposal` transaction. -Once a proposal is submitted, it is identified by its unique `proposalID`. - -### Proposal Messages - -A proposal includes an array of `sdk.Msg`s which are executed automatically if the -proposal passes. The messages are executed by the governance `ModuleAccount` itself. Modules -such as `x/upgrade`, that want to allow certain messages to be executed by governance -only should add a whitelist within the respective msg server, granting the governance -module the right to execute the message once a quorum has been reached. The governance -module uses the `MsgServiceRouter` to check that these messages are correctly constructed -and have a respective path to execute on but do not perform a full validity check. - -## Deposit - -To prevent spam, proposals must be submitted with a deposit in the coins defined by -the `MinDeposit` param. - -When a proposal is submitted, it has to be accompanied with a deposit that must be -strictly positive, but can be inferior to `MinDeposit`. The submitter doesn't need -to pay for the entire deposit on their own. The newly created proposal is stored in -an _inactive proposal queue_ and stays there until its deposit passes the `MinDeposit`. -Other token holders can increase the proposal's deposit by sending a `Deposit` -transaction. If a proposal doesn't pass the `MinDeposit` before the deposit end time -(the time when deposits are no longer accepted), the proposal will be destroyed: the -proposal will be removed from state and the deposit will be burned (see x/gov `EndBlocker`). -When a proposal deposit passes the `MinDeposit` threshold (even during the proposal -submission) before the deposit end time, the proposal will be moved into the -_active proposal queue_ and the voting period will begin. - -The deposit is kept in escrow and held by the governance `ModuleAccount` until the -proposal is finalized (passed or rejected). - -### Deposit refund and burn - -When a proposal is finalized, the coins from the deposit are either refunded or burned -according to the final tally of the proposal: - -* If the proposal is approved or rejected but _not_ vetoed, each deposit will be - automatically refunded to its respective depositor (transferred from the governance - `ModuleAccount`). -* When the proposal is vetoed with greater than 1/3, deposits will be burned from the - governance `ModuleAccount` and the proposal information along with its deposit - information will be removed from state. -* All refunded or burned deposits are removed from the state. Events are issued when - burning or refunding a deposit. - -## Vote - -### Participants - -_Participants_ are users that have the right to vote on proposals. On the -Cosmos Hub, participants are bonded Atom holders. Unbonded Atom holders and -other users do not get the right to participate in governance. However, they -can submit and deposit on proposals. - -Note that some _participants_ can be forbidden to vote on a proposal under a -certain validator if: - -* _participant_ bonded or unbonded Atoms to said validator after proposal - entered voting period. -* _participant_ became validator after proposal entered voting period. - -This does not prevent _participant_ to vote with Atoms bonded to other -validators. For example, if a _participant_ bonded some Atoms to validator A -before a proposal entered voting period and other Atoms to validator B after -proposal entered voting period, only the vote under validator B will be -forbidden. - -### Voting period - -Once a proposal reaches `MinDeposit`, it immediately enters `Voting period`. We -define `Voting period` as the interval between the moment the vote opens and -the moment the vote closes. `Voting period` should always be shorter than -`Unbonding period` to prevent double voting. The initial value of -`Voting period` is 2 weeks. - -### Option set - -The option set of a proposal refers to the set of choices a participant can -choose from when casting its vote. - -The initial option set includes the following options: - -* `Yes` -* `No` -* `NoWithVeto` -* `Abstain` - -`NoWithVeto` counts as `No` but also adds a `Veto` vote. `Abstain` option -allows voters to signal that they do not intend to vote in favor or against the -proposal but accept the result of the vote. - -_Note: from the UI, for urgent proposals we should maybe add a β€˜Not Urgent’ -option that casts a `NoWithVeto` vote._ - -### Weighted Votes - -[ADR-037](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-037-gov-split-vote.md) introduces the weighted vote feature which allows a staker to split their votes into several voting options. For example, it could use 70% of its voting power to vote Yes and 30% of its voting power to vote No. - -Often times the entity owning that address might not be a single individual. For example, a company might have different stakeholders who want to vote differently, and so it makes sense to allow them to split their voting power. Currently, it is not possible for them to do "passthrough voting" and giving their users voting rights over their tokens. However, with this system, exchanges can poll their users for voting preferences, and then vote on-chain proportionally to the results of the poll. - -To represent weighted vote on chain, we use the following Protobuf message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L33-L43 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1beta1/gov.proto#L136-L150 - -For a weighted vote to be valid, the `options` field must not contain duplicate vote options, and the sum of weights of all options must be equal to 1. - -### Quorum - -Quorum is defined as the minimum percentage of voting power that needs to be -cast on a proposal for the result to be valid. - -### Threshold - -Threshold is defined as the minimum proportion of `Yes` votes (excluding -`Abstain` votes) for the proposal to be accepted. - -Initially, the threshold is set at 50% of `Yes` votes, excluding `Abstain` -votes. A possibility to veto exists if more than 1/3rd of all votes are -`NoWithVeto` votes. Note, both of these values are derived from the `TallyParams` -on-chain parameter, which is modifiable by governance. -This means that proposals are accepted iff: - -* There exist bonded tokens. -* Quorum has been achieved. -* The proportion of `Abstain` votes is inferior to 1/1. -* The proportion of `NoWithVeto` votes is inferior to 1/3, including - `Abstain` votes. -* The proportion of `Yes` votes, excluding `Abstain` votes, at the end of - the voting period is superior to 1/2. - -### Inheritance - -If a delegator does not vote, it will inherit its validator vote. - -* If the delegator votes before its validator, it will not inherit from the - validator's vote. -* If the delegator votes after its validator, it will override its validator - vote with its own. If the proposal is urgent, it is possible - that the vote will close before delegators have a chance to react and - override their validator's vote. This is not a problem, as proposals require more than 2/3rd of the total voting power to pass before the end of the voting period. Because as little as 1/3 + 1 validation power could collude to censor transactions, non-collusion is already assumed for ranges exceeding this threshold. - -### Validator’s punishment for non-voting - -At present, validators are not punished for failing to vote. - -### Governance address - -Later, we may add permissioned keys that could only sign txs from certain modules. For the MVP, the `Governance address` will be the main validator address generated at account creation. This address corresponds to a different PrivKey than the Tendermint PrivKey which is responsible for signing consensus messages. Validators thus do not have to sign governance transactions with the sensitive Tendermint PrivKey. - -## Software Upgrade - -If proposals are of type `SoftwareUpgradeProposal`, then nodes need to upgrade -their software to the new version that was voted. This process is divided into -two steps: - -### Signal - -After a `SoftwareUpgradeProposal` is accepted, validators are expected to -download and install the new version of the software while continuing to run -the previous version. Once a validator has downloaded and installed the -upgrade, it will start signaling to the network that it is ready to switch by -including the proposal's `proposalID` in its _precommits_.(_Note: Confirmation -that we want it in the precommit?_) - -Note: There is only one signal slot per _precommit_. If several -`SoftwareUpgradeProposals` are accepted in a short timeframe, a pipeline will -form and they will be implemented one after the other in the order that they -were accepted. - -### Switch - -Once a block contains more than 2/3rd _precommits_ where a common -`SoftwareUpgradeProposal` is signaled, all the nodes (including validator -nodes, non-validating full nodes and light-nodes) are expected to switch to the -new version of the software. - -Validators and full nodes can use an automation tool, such as [Cosmovisor](https://github.com/cosmos/cosmos-sdk/blob/main/cosmovisor/README.md), for automatically switching version of the chain. diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md deleted file mode 100644 index 1eb945c4f356..000000000000 --- a/x/gov/spec/02_state.md +++ /dev/null @@ -1,219 +0,0 @@ - - -# State - -## Proposals - -`Proposal` objects are used to tally votes and generally track the proposal's state. -They contain an array of arbitrary `sdk.Msg`'s which the governance module will attempt -to resolve and then execute if the proposal passes. `Proposal`'s are identified by a -unique id and contains a series of timestamps: `submit_time`, `deposit_end_time`, -`voting_start_time`, `voting_end_time` which track the lifecycle of a proposal - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L42-L59 - -A proposal will generally require more than just a set of messages to explain its -purpose but need some greater justification and allow a means for interested participants -to discuss and debate the proposal. -In most cases, **it is encouraged to have an off-chain system that supports the on-chain governance process**. -To accommodate for this, a proposal contains a special **`metadata`** field, a string, -which can be used to add context to the proposal. The `metadata` field allows custom use for networks, -however, it is expected that the field contains a URL or some form of CID using a system such as -[IPFS](https://docs.ipfs.io/concepts/content-addressing/). To support the case of -interoperability across networks, the SDK recommends that the `metadata` represents -the following `JSON` template: - -```json -{ - "title": "...", - "description": "...", - "forum": "...", // a link to the discussion platform (i.e. Discord) - "other": "..." // any extra data that doesn't correspond to the other fields -} -``` - -This makes it far easier for clients to support multiple networks. - -The metadata has a maximum length that is chosen by the app developer, and -passed into the gov keeper as a config. The default maximum length in the SDK is 255 characters. - -### Writing a module that uses governance - -There are many aspects of a chain, or of the individual modules that you may want to -use governance to perform such as changing various parameters. This is very simple -to do. First, write out your message types and `MsgServer` implementation. Add an -`authority` field to the keeper which will be populated in the constructor with the -governance module account: `govKeeper.GetGovernanceAccount().GetAddress()`. Then for -the methods in the `msg_server.go`, perform a check on the message that the signer -matches `authority`. This will prevent any user from executing that message. - -## Parameters and base types - -`Parameters` define the rules according to which votes are run. There can only -be one active parameter set at any given time. If governance wants to change a -parameter set, either to modify a value or add/remove a parameter field, a new -parameter set has to be created and the previous one rendered inactive. - -### DepositParams - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L102-L112 - -### VotingParams - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L114-L118 - -### TallyParams - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L120-L132 - -Parameters are stored in a global `GlobalParams` KVStore. - -Additionally, we introduce some basic types: - -```go -type Vote byte - -const ( - VoteYes = 0x1 - VoteNo = 0x2 - VoteNoWithVeto = 0x3 - VoteAbstain = 0x4 -) - -type ProposalType string - -const ( - ProposalTypePlainText = "Text" - ProposalTypeSoftwareUpgrade = "SoftwareUpgrade" -) - -type ProposalStatus byte - - -const ( - StatusNil ProposalStatus = 0x00 - StatusDepositPeriod ProposalStatus = 0x01 // Proposal is submitted. Participants can deposit on it but not vote - StatusVotingPeriod ProposalStatus = 0x02 // MinDeposit is reached, participants can vote - StatusPassed ProposalStatus = 0x03 // Proposal passed and successfully executed - StatusRejected ProposalStatus = 0x04 // Proposal has been rejected - StatusFailed ProposalStatus = 0x05 // Proposal passed but failed execution -) -``` - -## Deposit - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/gov.proto#L34-L40 - -## ValidatorGovInfo - -This type is used in a temp map when tallying - -```go - type ValidatorGovInfo struct { - Minus sdk.Dec - Vote Vote - } -``` - -## Stores - -_Note: Stores are KVStores in the multi-store. The key to find the store is the first parameter in the list_ - -We will use one KVStore `Governance` to store two mappings: - -* A mapping from `proposalID|'proposal'` to `Proposal`. -* A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows - us to query all addresses that voted on the proposal along with their vote by - doing a range query on `proposalID:addresses`. -* A mapping from `ParamsKey|'Params'` to `Params`. This map allows to query all - x/gov params. - -For pseudocode purposes, here are the two function we will use to read or write in stores: - -* `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore -* `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore - -## Proposal Processing Queue - -**Store:** - -* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the - `ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`, - all the proposals that have reached the end of their voting period are processed. - To process a finished proposal, the application tallies the votes, computes the - votes of each validator and checks if every validator in the validator set has - voted. If the proposal is accepted, deposits are refunded. Finally, the proposal - content `Handler` is executed. - -And the pseudocode for the `ProposalProcessingQueue`: - -```go - in EndBlock do - - for finishedProposalID in GetAllFinishedProposalIDs(block.Time) - proposal = load(Governance, ) // proposal is a const key - - validators = Keeper.getAllValidators() - tmpValMap := map(sdk.AccAddress)ValidatorGovInfo - - // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes - for each validator in validators - tmpValMap(validator.OperatorAddr).Minus = 0 - - // Tally - voterIterator = rangeQuery(Governance, ) //return all the addresses that voted on the proposal - for each (voterAddress, vote) in voterIterator - delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter - - for each delegation in delegations - // make sure delegation.Shares does NOT include shares being unbonded - tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares - proposal.updateTally(vote, delegation.Shares) - - _, isVal = stakingKeeper.getValidator(voterAddress) - if (isVal) - tmpValMap(voterAddress).Vote = vote - - tallyingParam = load(GlobalParams, 'TallyingParam') - - // Update tally if validator voted - for each validator in validators - if tmpValMap(validator).HasVoted - proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus)) - - - - // Check if proposal is accepted or rejected - totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes - if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto) - // proposal was accepted at the end of the voting period - // refund deposits (non-voters already punished) - for each (amount, depositor) in proposal.Deposits - depositor.AtomBalance += amount - - stateWriter, err := proposal.Handler() - if err != nil - // proposal passed but failed during state execution - proposal.CurrentStatus = ProposalStatusFailed - else - // proposal pass and state is persisted - proposal.CurrentStatus = ProposalStatusAccepted - stateWriter.save() - else - // proposal was rejected - proposal.CurrentStatus = ProposalStatusRejected - - store(Governance, , proposal) -``` - -## Legacy Proposal - -A legacy proposal is the old implementation of governance proposal. -Contrary to proposal that can contain any messages, a legacy proposal allows to submit a set of pre-defined proposals. -These proposal are defined by their types. - -While proposals should use the new implementation of the governance proposal, we need still to use legacy proposal in order to submit a `software-upgrade` and a `cancel-software-upgrade` proposal. - -More information on how to submit proposals in the [client section](07_client.md). diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md deleted file mode 100644 index 7c755e0dc393..000000000000 --- a/x/gov/spec/03_messages.md +++ /dev/null @@ -1,183 +0,0 @@ - - -# Messages - -## Proposal Submission - -Proposals can be submitted by any account via a `MsgSubmitProposal` -transaction. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L33-L43 - -All `sdk.Msgs` passed into the `messages` field of a `MsgSubmitProposal` message -must be registered in the app's `MsgServiceRouter`. Each of these messages must -have one signer, namely the gov module account. And finally, the metadata length -must not be larger than the `maxMetadataLen` config passed into the gov keeper. - -**State modifications:** - -* Generate new `proposalID` -* Create new `Proposal` -* Initialise `Proposal`'s attributes -* Decrease balance of sender by `InitialDeposit` -* If `MinDeposit` is reached: - * Push `proposalID` in `ProposalProcessingQueue` -* Transfer `InitialDeposit` from the `Proposer` to the governance `ModuleAccount` - -A `MsgSubmitProposal` transaction can be handled according to the following -pseudocode. - -```go -// PSEUDOCODE // -// Check if MsgSubmitProposal is valid. If it is, create proposal // - -upon receiving txGovSubmitProposal from sender do - - if !correctlyFormatted(txGovSubmitProposal) - // check if proposal is correctly formatted and the messages have routes to other modules. Includes fee payment. - // check if all messages' unique Signer is the gov acct. - // check if the metadata is not too long. - throw - - initialDeposit = txGovSubmitProposal.InitialDeposit - if (initialDeposit.Atoms <= 0) OR (sender.AtomBalance < initialDeposit.Atoms) - // InitialDeposit is negative or null OR sender has insufficient funds - throw - - if (txGovSubmitProposal.Type != ProposalTypePlainText) OR (txGovSubmitProposal.Type != ProposalTypeSoftwareUpgrade) - - sender.AtomBalance -= initialDeposit.Atoms - - depositParam = load(GlobalParams, 'DepositParam') - - proposalID = generate new proposalID - proposal = NewProposal() - - proposal.Messages = txGovSubmitProposal.Messages - proposal.Metadata = txGovSubmitProposal.Metadata - proposal.TotalDeposit = initialDeposit - proposal.SubmitTime = - proposal.DepositEndTime = .Add(depositParam.MaxDepositPeriod) - proposal.Deposits.append({initialDeposit, sender}) - proposal.Submitter = sender - proposal.YesVotes = 0 - proposal.NoVotes = 0 - proposal.NoWithVetoVotes = 0 - proposal.AbstainVotes = 0 - proposal.CurrentStatus = ProposalStatusOpen - - store(Proposals, , proposal) // Store proposal in Proposals mapping - return proposalID -``` - -## Deposit - -Once a proposal is submitted, if -`Proposal.TotalDeposit < ActiveParam.MinDeposit`, Atom holders can send -`MsgDeposit` transactions to increase the proposal's deposit. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L90-L97 - -**State modifications:** - -* Decrease balance of sender by `deposit` -* Add `deposit` of sender in `proposal.Deposits` -* Increase `proposal.TotalDeposit` by sender's `deposit` -* If `MinDeposit` is reached: - * Push `proposalID` in `ProposalProcessingQueueEnd` -* Transfer `Deposit` from the `proposer` to the governance `ModuleAccount` - -A `MsgDeposit` transaction has to go through a number of checks to be valid. -These checks are outlined in the following pseudocode. - -```go -// PSEUDOCODE // -// Check if MsgDeposit is valid. If it is, increase deposit and check if MinDeposit is reached - -upon receiving txGovDeposit from sender do - // check if proposal is correctly formatted. Includes fee payment. - - if !correctlyFormatted(txGovDeposit) - throw - - proposal = load(Proposals, ) // proposal is a const key, proposalID is variable - - if (proposal == nil) - // There is no proposal for this proposalID - throw - - if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.CurrentStatus != ProposalStatusOpen) - - // deposit is negative or null - // OR sender has insufficient funds - // OR proposal is not open for deposit anymore - - throw - - depositParam = load(GlobalParams, 'DepositParam') - - if (CurrentBlock >= proposal.SubmitBlock + depositParam.MaxDepositPeriod) - proposal.CurrentStatus = ProposalStatusClosed - - else - // sender can deposit - sender.AtomBalance -= txGovDeposit.Deposit.Atoms - - proposal.Deposits.append({txGovVote.Deposit, sender}) - proposal.TotalDeposit.Plus(txGovDeposit.Deposit) - - if (proposal.TotalDeposit >= depositParam.MinDeposit) - // MinDeposit is reached, vote opens - - proposal.VotingStartBlock = CurrentBlock - proposal.CurrentStatus = ProposalStatusActive - ProposalProcessingQueue.push(txGovDeposit.ProposalID) - - store(Proposals, , proposal) -``` - -## Vote - -Once `ActiveParam.MinDeposit` is reached, voting period starts. From there, -bonded Atom holders are able to send `MsgVote` transactions to cast their -vote on the proposal. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/gov/v1/tx.proto#L64-L72 - -**State modifications:** - -* Record `Vote` of sender - -_Note: Gas cost for this message has to take into account the future tallying of the vote in EndBlocker._ - -Next is a pseudocode outline of the way `MsgVote` transactions are -handled: - -```go - // PSEUDOCODE // - // Check if MsgVote is valid. If it is, count vote// - - upon receiving txGovVote from sender do - // check if proposal is correctly formatted. Includes fee payment. - - if !correctlyFormatted(txGovDeposit) - throw - - proposal = load(Proposals, ) - - if (proposal == nil) - // There is no proposal for this proposalID - throw - - - if (proposal.CurrentStatus == ProposalStatusActive) - - - // Sender can vote if - // Proposal is active - // Sender has some bonds - - store(Governance, , txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end. -``` diff --git a/x/gov/spec/04_events.md b/x/gov/spec/04_events.md deleted file mode 100644 index 3c0d72ce987d..000000000000 --- a/x/gov/spec/04_events.md +++ /dev/null @@ -1,65 +0,0 @@ - - -# Events - -The governance module emits the following events: - -## EndBlocker - -| Type | Attribute Key | Attribute Value | -| ----------------- | --------------- | ---------------- | -| inactive_proposal | proposal_id | {proposalID} | -| inactive_proposal | proposal_result | {proposalResult} | -| active_proposal | proposal_id | {proposalID} | -| active_proposal | proposal_result | {proposalResult} | - -## Handlers - -### MsgSubmitProposal - -| Type | Attribute Key | Attribute Value | -| ------------------- | ------------------- | --------------- | -| submit_proposal | proposal_id | {proposalID} | -| submit_proposal [0] | voting_period_start | {proposalID} | -| proposal_deposit | amount | {depositAmount} | -| proposal_deposit | proposal_id | {proposalID} | -| message | module | governance | -| message | action | submit_proposal | -| message | sender | {senderAddress} | - -* [0] Event only emitted if the voting period starts during the submission. - -### MsgVote - -| Type | Attribute Key | Attribute Value | -| ------------- | ------------- | --------------- | -| proposal_vote | option | {voteOption} | -| proposal_vote | proposal_id | {proposalID} | -| message | module | governance | -| message | action | vote | -| message | sender | {senderAddress} | - -### MsgVoteWeighted - -| Type | Attribute Key | Attribute Value | -| ------------- | ------------- | ------------------------ | -| proposal_vote | option | {weightedVoteOptions} | -| proposal_vote | proposal_id | {proposalID} | -| message | module | governance | -| message | action | vote | -| message | sender | {senderAddress} | - -### MsgDeposit - -| Type | Attribute Key | Attribute Value | -| -------------------- | ------------------- | --------------- | -| proposal_deposit | amount | {depositAmount} | -| proposal_deposit | proposal_id | {proposalID} | -| proposal_deposit [0] | voting_period_start | {proposalID} | -| message | module | governance | -| message | action | deposit | -| message | sender | {senderAddress} | - -* [0] Event only emitted if the voting period starts during the submission. diff --git a/x/gov/spec/05_future_improvements.md b/x/gov/spec/05_future_improvements.md deleted file mode 100644 index 12f2e9e5c681..000000000000 --- a/x/gov/spec/05_future_improvements.md +++ /dev/null @@ -1,30 +0,0 @@ - - -# Future Improvements - -The current documentation only describes the minimum viable product for the -governance module. Future improvements may include: - -* **`BountyProposals`:** If accepted, a `BountyProposal` creates an open - bounty. The `BountyProposal` specifies how many Atoms will be given upon - completion. These Atoms will be taken from the `reserve pool`. After a - `BountyProposal` is accepted by governance, anybody can submit a - `SoftwareUpgradeProposal` with the code to claim the bounty. Note that once a - `BountyProposal` is accepted, the corresponding funds in the `reserve pool` - are locked so that payment can always be honored. In order to link a - `SoftwareUpgradeProposal` to an open bounty, the submitter of the - `SoftwareUpgradeProposal` will use the `Proposal.LinkedProposal` attribute. - If a `SoftwareUpgradeProposal` linked to an open bounty is accepted by - governance, the funds that were reserved are automatically transferred to the - submitter. -* **Complex delegation:** Delegators could choose other representatives than - their validators. Ultimately, the chain of representatives would always end - up to a validator, but delegators could inherit the vote of their chosen - representative before they inherit the vote of their validator. In other - words, they would only inherit the vote of their validator if their other - appointed representative did not vote. -* **Better process for proposal review:** There would be two parts to - `proposal.Deposit`, one for anti-spam (same as in MVP) and an other one to - reward third party auditors. diff --git a/x/gov/spec/06_params.md b/x/gov/spec/06_params.md deleted file mode 100644 index 2cc0176693eb..000000000000 --- a/x/gov/spec/06_params.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# Parameters - -The governance module contains the following parameters: - -| Key | Type | Example | -|---------------|--------|----------------------------------------------------------------------------------------------------| -| depositparams | object | {"min_deposit":[{"denom":"uatom","amount":"10000000"}],"max_deposit_period":"172800000000000"} | -| votingparams | object | {"voting_period":"172800000000000"} | -| tallyparams | object | {"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto":"0.334000000000000000"} | - -## SubKeys - -| Key | Type | Example | -|--------------------|------------------|-----------------------------------------| -| min_deposit | array (coins) | [{"denom":"uatom","amount":"10000000"}] | -| max_deposit_period | string (time ns) | "172800000000000" | -| voting_period | string (time ns) | "172800000000000" | -| quorum | string (dec) | "0.334000000000000000" | -| threshold | string (dec) | "0.500000000000000000" | -| veto | string (dec) | "0.334000000000000000" | - -__NOTE__: The governance module contains parameters that are objects unlike other -modules. If only a subset of parameters are desired to be changed, only they need -to be included and not the entire parameter object structure. diff --git a/x/gov/spec/07_client.md b/x/gov/spec/07_client.md deleted file mode 100644 index 00aa57e57859..000000000000 --- a/x/gov/spec/07_client.md +++ /dev/null @@ -1,1794 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `gov` module using the CLI. - -### Query - -The `query` commands allow users to query `gov` state. - -```bash -simd query gov --help -``` - -#### deposit - -The `deposit` command allows users to query a deposit for a given proposal from a given depositor. - -```bash -simd query gov deposit [proposal-id] [depositer-addr] [flags] -``` - -Example: - -```bash -simd query gov deposit 1 cosmos1.. -``` - -Example Output: - -```bash -amount: -- amount: "100" - denom: stake -depositor: cosmos1.. -proposal_id: "1" -``` - -#### deposits - -The `deposits` command allows users to query all deposits for a given proposal. - -```bash -simd query gov deposits [proposal-id] [flags] -``` - -Example: - -```bash -simd query gov deposits 1 -``` - -Example Output: - -```bash -deposits: -- amount: - - amount: "100" - denom: stake - depositor: cosmos1.. - proposal_id: "1" -pagination: - next_key: null - total: "0" -``` - -#### param - -The `param` command allows users to query a given parameter for the `gov` module. - -```bash -simd query gov param [param-type] [flags] -``` - -Example: - -```bash -simd query gov param voting -``` - -Example Output: - -```bash -voting_period: "172800000000000" -``` - -#### params - -The `params` command allows users to query all parameters for the `gov` module. - -```bash -simd query gov params [flags] -``` - -Example: - -```bash -simd query gov params -``` - -Example Output: - -```bash -deposit_params: - max_deposit_period: "172800000000000" - min_deposit: - - amount: "10000000" - denom: stake -tally_params: - quorum: "0.334000000000000000" - threshold: "0.500000000000000000" - veto_threshold: "0.334000000000000000" -voting_params: - voting_period: "172800000000000" -``` - -#### proposal - -The `proposal` command allows users to query a given proposal. - -```bash -simd query gov proposal [proposal-id] [flags] -``` - -Example: - -```bash -simd query gov proposal 1 -``` - -Example Output: - -```bash -deposit_end_time: "2022-03-30T11:50:20.819676256Z" -final_tally_result: - abstain_count: "0" - no_count: "0" - no_with_veto_count: "0" - yes_count: "0" -id: "1" -messages: -- '@type': /cosmos.bank.v1beta1.MsgSend - amount: - - amount: "10" - denom: stake - from_address: cosmos1.. - to_address: cosmos1.. -metadata: AQ== -status: PROPOSAL_STATUS_DEPOSIT_PERIOD -submit_time: "2022-03-28T11:50:20.819676256Z" -total_deposit: -- amount: "10" - denom: stake -voting_end_time: null -voting_start_time: null -``` - -#### proposals - -The `proposals` command allows users to query all proposals with optional filters. - -```bash -simd query gov proposals [flags] -``` - -Example: - -```bash -simd query gov proposals -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -proposals: -- deposit_end_time: "2022-03-30T11:50:20.819676256Z" - final_tally_result: - abstain_count: "0" - no_count: "0" - no_with_veto_count: "0" - yes_count: "0" - id: "1" - messages: - - '@type': /cosmos.bank.v1beta1.MsgSend - amount: - - amount: "10" - denom: stake - from_address: cosmos1.. - to_address: cosmos1.. - metadata: AQ== - status: PROPOSAL_STATUS_DEPOSIT_PERIOD - submit_time: "2022-03-28T11:50:20.819676256Z" - total_deposit: - - amount: "10" - denom: stake - voting_end_time: null - voting_start_time: null -- deposit_end_time: "2022-03-30T14:02:41.165025015Z" - final_tally_result: - abstain_count: "0" - no_count: "0" - no_with_veto_count: "0" - yes_count: "0" - id: "2" - messages: - - '@type': /cosmos.bank.v1beta1.MsgSend - amount: - - amount: "10" - denom: stake - from_address: cosmos1.. - to_address: cosmos1.. - metadata: AQ== - status: PROPOSAL_STATUS_DEPOSIT_PERIOD - submit_time: "2022-03-28T14:02:41.165025015Z" - total_deposit: - - amount: "10" - denom: stake - voting_end_time: null - voting_start_time: null -``` - -#### proposer - -The `proposer` command allows users to query the proposer for a given proposal. - -```bash -simd query gov proposer [proposal-id] [flags] -``` - -Example: - -```bash -simd query gov proposer 1 -``` - -Example Output: - -```bash -proposal_id: "1" -proposer: cosmos1.. -``` - -#### tally - -The `tally` command allows users to query the tally of a given proposal vote. - -```bash -simd query gov tally [proposal-id] [flags] -``` - -Example: - -```bash -simd query gov tally 1 -``` - -Example Output: - -```bash -abstain: "0" -"no": "0" -no_with_veto: "0" -"yes": "1" -``` - -#### vote - -The `vote` command allows users to query a vote for a given proposal. - -```bash -simd query gov vote [proposal-id] [voter-addr] [flags] -``` - -Example: - -```bash -simd query gov vote 1 cosmos1.. -``` - -Example Output: - -```bash -option: VOTE_OPTION_YES -options: -- option: VOTE_OPTION_YES - weight: "1.000000000000000000" -proposal_id: "1" -voter: cosmos1.. -``` - -#### votes - -The `votes` command allows users to query all votes for a given proposal. - -```bash -simd query gov votes [proposal-id] [flags] -``` - -Example: - -```bash -simd query gov votes 1 -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -votes: -- option: VOTE_OPTION_YES - options: - - option: VOTE_OPTION_YES - weight: "1.000000000000000000" - proposal_id: "1" - voter: cosmos1.. -``` - -### Transactions - -The `tx` commands allow users to interact with the `gov` module. - -```bash -simd tx gov --help -``` - -#### deposit - -The `deposit` command allows users to deposit tokens for a given proposal. - -```bash -simd tx gov deposit [proposal-id] [deposit] [flags] -``` - -Example: - -```bash -simd tx gov deposit 1 10000000stake --from cosmos1.. -``` - -#### submit-proposal - -The `submit-proposal` command allows users to submit a governance proposal along with some messages and metadata. -Messages, metadata and deposit are defined in a JSON file. - -```bash -simd tx gov submit-proposal [path-to-proposal-json] [flags] -``` - -Example: - -```bash -simd tx gov submit-proposal /path/to/proposal.json --from cosmos1.. -``` - -where `proposal.json` contains: - -```json -{ - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1...", // The gov module module address - "to_address": "cosmos1...", - "amount":[{"denom": "stake","amount": "10"}] - } - ], - "metadata": "AQ==", - "deposit": "10stake" -} -``` - -#### submit-legacy-proposal - -The `submit-legacy-proposal` command allows users to submit a governance legacy proposal along with an initial deposit. - -```bash -simd tx gov submit-legacy-proposal [command] [flags] -``` - -Example: - -```bash -simd tx gov submit-legacy-proposal --title="Test Proposal" --description="testing" --type="Text" --deposit="100000000stake" --from cosmos1.. -``` - -Example (`cancel-software-upgrade`): - -```bash -simd tx gov submit-legacy-proposal cancel-software-upgrade --title="Test Proposal" --description="testing" --deposit="100000000stake" --from cosmos1.. -``` - -Example (`community-pool-spend`): - -```bash -simd tx gov submit-legacy-proposal community-pool-spend proposal.json --from cosmos1.. -``` - -```json -{ - "title": "Test Proposal", - "description": "testing, 1, 2, 3", - "recipient": "cosmos1..", - "amount": "10000000stake", - "deposit": "10000000stake" -} -``` - -Example (`param-change`): - -```bash -simd tx gov submit-legacy-proposal param-change proposal.json --from cosmos1.. -``` - -```json -{ - "title": "Test Proposal", - "description": "testing, testing, 1, 2, 3", - "changes": [ - { - "subspace": "staking", - "key": "MaxValidators", - "value": 100 - } - ], - "deposit": "10000000stake" -} -``` - -Example (`software-upgrade`): - -```bash -simd tx gov submit-legacy-proposal software-upgrade v2 --title="Test Proposal" --description="testing, testing, 1, 2, 3" --upgrade-height 1000000 --from cosmos1.. -``` - -#### vote - -The `vote` command allows users to submit a vote for a given governance proposal. - -```bash -simd tx gov vote [command] [flags] -``` - -Example: - -```bash -simd tx gov vote 1 yes --from cosmos1.. -``` - -#### weighted-vote - -The `weighted-vote` command allows users to submit a weighted vote for a given governance proposal. - -```bash -simd tx gov weighted-vote [proposal-id] [weighted-options] [flags] -``` - -Example: - -```bash -simd tx gov weighted-vote 1 yes=0.5,no=0.5 --from cosmos1.. -``` - -## gRPC - -A user can query the `gov` module using gRPC endpoints. - -### Proposal - -The `Proposal` endpoint allows users to query a given proposal. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Proposal -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Proposal -``` - -Example Output: - -```bash -{ - "proposal": { - "proposalId": "1", - "content": {"@type":"/cosmos.gov.v1beta1.TextProposal","description":"testing, testing, 1, 2, 3","title":"Test Proposal"}, - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "finalTallyResult": { - "yes": "0", - "abstain": "0", - "no": "0", - "noWithVeto": "0" - }, - "submitTime": "2021-09-16T19:40:08.712440474Z", - "depositEndTime": "2021-09-18T19:40:08.712440474Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "votingStartTime": "2021-09-16T19:40:08.712440474Z", - "votingEndTime": "2021-09-18T19:40:08.712440474Z" - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Proposal -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Proposal -``` - -Example Output: - -```bash -{ - "proposal": { - "id": "1", - "messages": [ - {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} - ], - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "finalTallyResult": { - "yesCount": "0", - "abstainCount": "0", - "noCount": "0", - "noWithVetoCount": "0" - }, - "submitTime": "2022-03-28T11:50:20.819676256Z", - "depositEndTime": "2022-03-30T11:50:20.819676256Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "votingStartTime": "2022-03-28T14:25:26.644857113Z", - "votingEndTime": "2022-03-30T14:25:26.644857113Z", - "metadata": "AQ==" - } -} -``` - - -### Proposals - -The `Proposals` endpoint allows users to query all proposals with optional filters. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Proposals -``` - -Example: - -```bash -grpcurl -plaintext \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Proposals -``` - -Example Output: - -```bash -{ - "proposals": [ - { - "proposalId": "1", - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "finalTallyResult": { - "yes": "0", - "abstain": "0", - "no": "0", - "noWithVeto": "0" - }, - "submitTime": "2022-03-28T11:50:20.819676256Z", - "depositEndTime": "2022-03-30T11:50:20.819676256Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10000000010" - } - ], - "votingStartTime": "2022-03-28T14:25:26.644857113Z", - "votingEndTime": "2022-03-30T14:25:26.644857113Z" - }, - { - "proposalId": "2", - "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", - "finalTallyResult": { - "yes": "0", - "abstain": "0", - "no": "0", - "noWithVeto": "0" - }, - "submitTime": "2022-03-28T14:02:41.165025015Z", - "depositEndTime": "2022-03-30T14:02:41.165025015Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10" - } - ], - "votingStartTime": "0001-01-01T00:00:00Z", - "votingEndTime": "0001-01-01T00:00:00Z" - } - ], - "pagination": { - "total": "2" - } -} - -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Proposals -``` - -Example: - -```bash -grpcurl -plaintext \ - localhost:9090 \ - cosmos.gov.v1.Query/Proposals -``` - -Example Output: - -```bash -{ - "proposals": [ - { - "id": "1", - "messages": [ - {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} - ], - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "finalTallyResult": { - "yesCount": "0", - "abstainCount": "0", - "noCount": "0", - "noWithVetoCount": "0" - }, - "submitTime": "2022-03-28T11:50:20.819676256Z", - "depositEndTime": "2022-03-30T11:50:20.819676256Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10000000010" - } - ], - "votingStartTime": "2022-03-28T14:25:26.644857113Z", - "votingEndTime": "2022-03-30T14:25:26.644857113Z", - "metadata": "AQ==" - }, - { - "id": "2", - "messages": [ - {"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"10"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."} - ], - "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", - "finalTallyResult": { - "yesCount": "0", - "abstainCount": "0", - "noCount": "0", - "noWithVetoCount": "0" - }, - "submitTime": "2022-03-28T14:02:41.165025015Z", - "depositEndTime": "2022-03-30T14:02:41.165025015Z", - "totalDeposit": [ - { - "denom": "stake", - "amount": "10" - } - ], - "metadata": "AQ==" - } - ], - "pagination": { - "total": "2" - } -} -``` - -### Vote - -The `Vote` endpoint allows users to query a vote for a given proposal. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Vote -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1","voter":"cosmos1.."}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Vote -``` - -Example Output: - -```bash -{ - "vote": { - "proposalId": "1", - "voter": "cosmos1..", - "option": "VOTE_OPTION_YES", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1000000000000000000" - } - ] - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Vote -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1","voter":"cosmos1.."}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Vote -``` - -Example Output: - -```bash -{ - "vote": { - "proposalId": "1", - "voter": "cosmos1..", - "option": "VOTE_OPTION_YES", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ] - } -} -``` - -### Votes - -The `Votes` endpoint allows users to query all votes for a given proposal. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Votes -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Votes -``` - -Example Output: - -```bash -{ - "votes": [ - { - "proposalId": "1", - "voter": "cosmos1..", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1000000000000000000" - } - ] - } - ], - "pagination": { - "total": "1" - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Votes -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Votes -``` - -Example Output: - -```bash -{ - "votes": [ - { - "proposalId": "1", - "voter": "cosmos1..", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ] - } - ], - "pagination": { - "total": "1" - } -} -``` - -### Params - -The `Params` endpoint allows users to query all parameters for the `gov` module. - - - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Params -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"params_type":"voting"}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Params -``` - -Example Output: - -```bash -{ - "votingParams": { - "votingPeriod": "172800s" - }, - "depositParams": { - "maxDepositPeriod": "0s" - }, - "tallyParams": { - "quorum": "MA==", - "threshold": "MA==", - "vetoThreshold": "MA==" - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Params -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"params_type":"voting"}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Params -``` - -Example Output: - -```bash -{ - "votingParams": { - "votingPeriod": "172800s" - } -} -``` - -### Deposit - -The `Deposit` endpoint allows users to query a deposit for a given proposal from a given depositor. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Deposit -``` - -Example: - -```bash -grpcurl -plaintext \ - '{"proposal_id":"1","depositor":"cosmos1.."}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Deposit -``` - -Example Output: - -```bash -{ - "deposit": { - "proposalId": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Deposit -``` - -Example: - -```bash -grpcurl -plaintext \ - '{"proposal_id":"1","depositor":"cosmos1.."}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Deposit -``` - -Example Output: - -```bash -{ - "deposit": { - "proposalId": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } -} -``` - -### deposits - -The `Deposits` endpoint allows users to query all deposits for a given proposal. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/Deposits -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/Deposits -``` - -Example Output: - -```bash -{ - "deposits": [ - { - "proposalId": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } - ], - "pagination": { - "total": "1" - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/Deposits -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1.Query/Deposits -``` - -Example Output: - -```bash -{ - "deposits": [ - { - "proposalId": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } - ], - "pagination": { - "total": "1" - } -} -``` - -### TallyResult - -The `TallyResult` endpoint allows users to query the tally of a given proposal. - -Using legacy v1beta1: - -```bash -cosmos.gov.v1beta1.Query/TallyResult -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1beta1.Query/TallyResult -``` - -Example Output: - -```bash -{ - "tally": { - "yes": "1000000", - "abstain": "0", - "no": "0", - "noWithVeto": "0" - } -} -``` - -Using v1: - -```bash -cosmos.gov.v1.Query/TallyResult -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"proposal_id":"1"}' \ - localhost:9090 \ - cosmos.gov.v1.Query/TallyResult -``` - -Example Output: - -```bash -{ - "tally": { - "yes": "1000000", - "abstain": "0", - "no": "0", - "noWithVeto": "0" - } -} -``` - -## REST - -A user can query the `gov` module using REST endpoints. - -### proposal - -The `proposals` endpoint allows users to query a given proposal. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1 -``` - -Example Output: - -```bash -{ - "proposal": { - "proposal_id": "1", - "content": null, - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "final_tally_result": { - "yes": "0", - "abstain": "0", - "no": "0", - "no_with_veto": "0" - }, - "submit_time": "2022-03-28T11:50:20.819676256Z", - "deposit_end_time": "2022-03-30T11:50:20.819676256Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10000000010" - } - ], - "voting_start_time": "2022-03-28T14:25:26.644857113Z", - "voting_end_time": "2022-03-30T14:25:26.644857113Z" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1 -``` - -Example Output: - -```bash -{ - "proposal": { - "id": "1", - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1..", - "to_address": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10" - } - ] - } - ], - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "final_tally_result": { - "yes_count": "0", - "abstain_count": "0", - "no_count": "0", - "no_with_veto_count": "0" - }, - "submit_time": "2022-03-28T11:50:20.819676256Z", - "deposit_end_time": "2022-03-30T11:50:20.819676256Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "voting_start_time": "2022-03-28T14:25:26.644857113Z", - "voting_end_time": "2022-03-30T14:25:26.644857113Z", - "metadata": "AQ==" - } -} -``` - -### proposals - -The `proposals` endpoint also allows users to query all proposals with optional filters. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals -``` - -Example Output: - -```bash -{ - "proposals": [ - { - "proposal_id": "1", - "content": null, - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "final_tally_result": { - "yes": "0", - "abstain": "0", - "no": "0", - "no_with_veto": "0" - }, - "submit_time": "2022-03-28T11:50:20.819676256Z", - "deposit_end_time": "2022-03-30T11:50:20.819676256Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10000000" - } - ], - "voting_start_time": "2022-03-28T14:25:26.644857113Z", - "voting_end_time": "2022-03-30T14:25:26.644857113Z" - }, - { - "proposal_id": "2", - "content": null, - "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", - "final_tally_result": { - "yes": "0", - "abstain": "0", - "no": "0", - "no_with_veto": "0" - }, - "submit_time": "2022-03-28T14:02:41.165025015Z", - "deposit_end_time": "2022-03-30T14:02:41.165025015Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10" - } - ], - "voting_start_time": "0001-01-01T00:00:00Z", - "voting_end_time": "0001-01-01T00:00:00Z" - } - ], - "pagination": { - "next_key": null, - "total": "2" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals -``` - -Example Output: - -```bash -{ - "proposals": [ - { - "id": "1", - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1..", - "to_address": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10" - } - ] - } - ], - "status": "PROPOSAL_STATUS_VOTING_PERIOD", - "final_tally_result": { - "yes_count": "0", - "abstain_count": "0", - "no_count": "0", - "no_with_veto_count": "0" - }, - "submit_time": "2022-03-28T11:50:20.819676256Z", - "deposit_end_time": "2022-03-30T11:50:20.819676256Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10000000010" - } - ], - "voting_start_time": "2022-03-28T14:25:26.644857113Z", - "voting_end_time": "2022-03-30T14:25:26.644857113Z", - "metadata": "AQ==" - }, - { - "id": "2", - "messages": [ - { - "@type": "/cosmos.bank.v1beta1.MsgSend", - "from_address": "cosmos1..", - "to_address": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10" - } - ] - } - ], - "status": "PROPOSAL_STATUS_DEPOSIT_PERIOD", - "final_tally_result": { - "yes_count": "0", - "abstain_count": "0", - "no_count": "0", - "no_with_veto_count": "0" - }, - "submit_time": "2022-03-28T14:02:41.165025015Z", - "deposit_end_time": "2022-03-30T14:02:41.165025015Z", - "total_deposit": [ - { - "denom": "stake", - "amount": "10" - } - ], - "voting_start_time": null, - "voting_end_time": null, - "metadata": "AQ==" - } - ], - "pagination": { - "next_key": null, - "total": "2" - } -} -``` - -### voter vote - -The `votes` endpoint allows users to query a vote for a given proposal. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id}/votes/{voter} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes/cosmos1.. -``` - -Example Output: - -```bash -{ - "vote": { - "proposal_id": "1", - "voter": "cosmos1..", - "option": "VOTE_OPTION_YES", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ] - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id}/votes/{voter} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1/votes/cosmos1.. -``` - -Example Output: - -```bash -{ - "vote": { - "proposal_id": "1", - "voter": "cosmos1..", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ], - "metadata": "" - } -} -``` - -### votes - -The `votes` endpoint allows users to query all votes for a given proposal. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id}/votes -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1/votes -``` - -Example Output: - -```bash -{ - "votes": [ - { - "proposal_id": "1", - "voter": "cosmos1..", - "option": "VOTE_OPTION_YES", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id}/votes -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1/votes -``` - -Example Output: - -```bash -{ - "votes": [ - { - "proposal_id": "1", - "voter": "cosmos1..", - "options": [ - { - "option": "VOTE_OPTION_YES", - "weight": "1.000000000000000000" - } - ], - "metadata": "" - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### params - -The `params` endpoint allows users to query all parameters for the `gov` module. - - - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/params/{params_type} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/params/voting -``` - -Example Output: - -```bash -{ - "voting_params": { - "voting_period": "172800s" - }, - "deposit_params": { - "min_deposit": [ - ], - "max_deposit_period": "0s" - }, - "tally_params": { - "quorum": "0.000000000000000000", - "threshold": "0.000000000000000000", - "veto_threshold": "0.000000000000000000" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/params/{params_type} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/params/voting -``` - -Example Output: - -```bash -{ - "voting_params": { - "voting_period": "172800s" - }, - "deposit_params": { - "min_deposit": [ - ], - "max_deposit_period": "0s" - }, - "tally_params": { - "quorum": "0.000000000000000000", - "threshold": "0.000000000000000000", - "veto_threshold": "0.000000000000000000" - } -} -``` - -### deposits - -The `deposits` endpoint allows users to query a deposit for a given proposal from a given depositor. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits/{depositor} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits/cosmos1.. -``` - -Example Output: - -```bash -{ - "deposit": { - "proposal_id": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id}/deposits/{depositor} -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1/deposits/cosmos1.. -``` - -Example Output: - -```bash -{ - "deposit": { - "proposal_id": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } -} -``` - -### proposal deposits - -The `deposits` endpoint allows users to query all deposits for a given proposal. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id}/deposits -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1/deposits -``` - -Example Output: - -```bash -{ - "deposits": [ - { - "proposal_id": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id}/deposits -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1/deposits -``` - -Example Output: - -```bash -{ - "deposits": [ - { - "proposal_id": "1", - "depositor": "cosmos1..", - "amount": [ - { - "denom": "stake", - "amount": "10000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### tally - -The `tally` endpoint allows users to query the tally of a given proposal. - -Using legacy v1beta1: - -```bash -/cosmos/gov/v1beta1/proposals/{proposal_id}/tally -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1beta1/proposals/1/tally -``` - -Example Output: - -```bash -{ - "tally": { - "yes": "1000000", - "abstain": "0", - "no": "0", - "no_with_veto": "0" - } -} -``` - -Using v1: - -```bash -/cosmos/gov/v1/proposals/{proposal_id}/tally -``` - -Example: - -```bash -curl localhost:1317/cosmos/gov/v1/proposals/1/tally -``` - -Example Output: - -```bash -{ - "tally": { - "yes": "1000000", - "abstain": "0", - "no": "0", - "no_with_veto": "0" - } -} -``` diff --git a/x/gov/spec/08_metadata.md b/x/gov/spec/08_metadata.md deleted file mode 100644 index fcd161c76c6c..000000000000 --- a/x/gov/spec/08_metadata.md +++ /dev/null @@ -1,30 +0,0 @@ - - -# Metadata - -The gov module has two locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the gov and group modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. - -## Proposal -Location: off-chain as json object stored on IPFS (mirrors [group proposal](../../group/spec/06_metadata.md#proposal)) - -```json -{ - "title": "", - "authors": "", - "summary": "", - "details": "", - "proposalForumURL": "", - "voteOptionContext": "", -} -``` - -## Vote -Location: on-chain as json within 255 character limit (mirrors [group vote](../../group/spec/06_metadata.md#vote)) - -```json -{ - "justification": "", -} -``` \ No newline at end of file diff --git a/x/gov/spec/README.md b/x/gov/spec/README.md deleted file mode 100644 index 3a5a2decf758..000000000000 --- a/x/gov/spec/README.md +++ /dev/null @@ -1,65 +0,0 @@ - - -# `gov` - -## Abstract - -This paper specifies the Governance module of the Cosmos-SDK, which was first -described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in -June 2016. - -The module enables Cosmos-SDK based blockchain to support an on-chain governance -system. In this system, holders of the native staking token of the chain can vote -on proposals on a 1 token 1 vote basis. Next is a list of features the module -currently supports: - -* **Proposal submission:** Users can submit proposals with a deposit. Once the -minimum deposit is reached, proposal enters voting period -* **Vote:** Participants can vote on proposals that reached MinDeposit -* **Inheritance and penalties:** Delegators inherit their validator's vote if -they don't vote themselves. -* **Claiming deposit:** Users that deposited on proposals can recover their -deposits if the proposal was accepted OR if the proposal never entered voting period. - -This module will be used in the Cosmos Hub, the first Hub in the Cosmos network. -Features that may be added in the future are described in [Future Improvements](05_future_improvements.md). - -## Contents - -The following specification uses *ATOM* as the native staking token. The module -can be adapted to any Proof-Of-Stake blockchain by replacing *ATOM* with the native -staking token of the chain. - -1. **[Concepts](01_concepts.md)** - * [Proposal submission](01_concepts.md#proposal-submission) - * [Deposit](01_concepts.md#Deposit) - * [Vote](01_concepts.md#vote) - * [Software Upgrade](01_concepts.md#software-upgrade) -2. **[State](02_state.md)** - * [Parameters and base types](02_state.md#parameters-and-base-types) - * [Deposit](02_state.md#deposit) - * [ValidatorGovInfo](02_state.md#validatorgovinfo) - * [Proposals](02_state.md#proposals) - * [Stores](02_state.md#stores) - * [Proposal Processing Queue](02_state.md#proposal-processing-queue) -3. **[Messages](03_messages.md)** - * [Proposal Submission](03_messages.md#proposal-submission) - * [Deposit](03_messages.md#deposit) - * [Vote](03_messages.md#vote) -4. **[Events](04_events.md)** - * [EndBlocker](04_events.md#endblocker) - * [Handlers](04_events.md#handlers) -5. **[Future Improvements](05_future_improvements.md)** -6. **[Parameters](06_params.md)** -7. **[Client](07_client.md)** - * [CLI](07_client.md#cli) - * [gRPC](07_client.md#grpc) - * [REST](07_client.md#rest) -8. **[Metadata](08_metadata.md)** - * [Proposal](08_metadata.md#proposal) - * [Vote](08_metadata.md#vote) diff --git a/x/group/spec/05_client.md b/x/group/README.md similarity index 53% rename from x/group/spec/05_client.md rename to x/group/README.md index 4df6b42731a1..f1aab2cdeaee 100644 --- a/x/group/spec/05_client.md +++ b/x/group/README.md @@ -1,7 +1,554 @@ +# Group Module + +## Abstract + +The following documents specify the group module. + +This module allows the creation and management of on-chain multisig accounts and enables voting for message execution based on configurable decision policies. + +## Contents + +* [Concepts](#concepts) + * [Group](#group) + * [Group Policy](#group-policy) + * [Decision Policy](#decision-policy) + * [Proposal](#proposal) + * [Pruning](#pruning) +* [State](#state) + * [Group Table](#group-table) + * [Group Member Table](#group-member-table) + * [Group Policy Table](#group-policy-table) + * [Proposal Table](#proposal-table) + * [Vote Table](#vote-table) +* [Msg Service](#msg-service) + * [Msg/CreateGroup](#msgcreategroup) + * [Msg/UpdateGroupMembers](#msgupdategroupmembers) + * [Msg/UpdateGroupAdmin](#msgupdategroupadmin) + * [Msg/UpdateGroupMetadata](#msgupdategroupmetadata) + * [Msg/CreateGroupPolicy](#msgcreategrouppolicy) + * [Msg/CreateGroupWithPolicy](#msgcreategroupwithpolicy) + * [Msg/UpdateGroupPolicyAdmin](#msgupdategrouppolicyadmin) + * [Msg/UpdateGroupPolicyDecisionPolicy](#msgupdategrouppolicydecisionpolicy) + * [Msg/UpdateGroupPolicyMetadata](#msgupdategrouppolicymetadata) + * [Msg/SubmitProposal](#msgsubmitproposal) + * [Msg/WithdrawProposal](#msgwithdrawproposal) + * [Msg/Vote](#msgvote) + * [Msg/Exec](#msgexec) + * [Msg/LeaveGroup](#msgleavegroup) +* [Events](#events) + * [EventCreateGroup](#eventcreategroup) + * [EventUpdateGroup](#eventupdategroup) + * [EventCreateGroupPolicy](#eventcreategrouppolicy) + * [EventUpdateGroupPolicy](#eventupdategrouppolicy) + * [EventCreateProposal](#eventcreateproposal) + * [EventWithdrawProposal](#eventwithdrawproposal) + * [EventVote](#eventvote) + * [EventExec](#eventexec) + * [EventLeaveGroup](#eventleavegroup) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) +* [Metadata](#metadata) + + + +# Concepts + +## Group + +A group is simply an aggregation of accounts with associated weights. It is not +an account and doesn't have a balance. It doesn't in and of itself have any +sort of voting or decision weight. It does have an "administrator" which has +the ability to add, remove and update members in the group. Note that a +group policy account could be an administrator of a group, and that the +administrator doesn't necessarily have to be a member of the group. + +## Group Policy + +A group policy is an account associated with a group and a decision policy. +Group policies are abstracted from groups because a single group may have +multiple decision policies for different types of actions. Managing group +membership separately from decision policies results in the least overhead +and keeps membership consistent across different policies. The pattern that +is recommended is to have a single master group policy for a given group, +and then to create separate group policies with different decision policies +and delegate the desired permissions from the master account to +those "sub-accounts" using the `x/authz` module. + +## Decision Policy + +A decision policy is the mechanism by which members of a group can vote on +proposals, as well as the rules that dictate whether a proposal should pass +or not based on its tally outcome. + +All decision policies generally would have a mininum execution period and a +maximum voting window. The minimum execution period is the minimum amount of time +that must pass after submission in order for a proposal to potentially be executed, and it may +be set to 0. The maximum voting window is the maximum time after submission that a proposal may +be voted on before it is tallied. + +The chain developer also defines an app-wide maximum execution period, which is +the maximum amount of time after a proposal's voting period end where users are +allowed to execute a proposal. + +The current group module comes shipped with two decision policies: threshold +and percentage. Any chain developer can extend upon these two, by creating +custom decision policies, as long as they adhere to the `DecisionPolicy` +interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/types.go#L27-L41 + +### Threshold decision policy + +A threshold decision policy defines a threshold of yes votes (based on a tally +of voter weights) that must be achieved in order for a proposal to pass. For +this decision policy, abstain and veto are simply treated as no's. + +### Percentage decision policy + +A percentage decision policy is similar to a threshold decision policy, except +that the threshold is not defined as a constant weight, but as a percentage. +It's more suited for groups where the group members' weights can be updated, as +the percentage threshold stays the same, and doesn't depend on how those member +weights get updated. + +## Proposal + +Any member(s) of a group can submit a proposal for a group policy account to decide upon. +A proposal consists of a set of messages that will be executed if the proposal +passes as well as any metadata associated with the proposal. + +### Voting + +There are four choices to choose while voting - yes, no, abstain and veto. Not +all decision policies will take the four choices into account. Votes can contain some optional metadata. +In the current implementation, the voting window begins as soon as a proposal +is submitted, and the end is defined by the group policy's decision policy. + +### Withdrawing Proposals + +Proposals can be withdrawn any time before the voting period end, either by the +admin of the group policy or by one of the proposers. Once withdrawn, it is +marked as `PROPOSAL_STATUS_WITHDRAWN`, and no more voting or execution is +allowed on it. + +### Aborted Proposals + +If the group policy is updated during the voting period of the proposal, then +the proposal is marked as `PROPOSAL_STATUS_ABORTED`, and no more voting or +execution is allowed on it. This is because the group policy defines the rules +of proposal voting and execution, so if those rules change during the lifecycle +of a proposal, then the proposal should be marked as stale. + +### Tallying + +Tallying is the counting of all votes on a proposal. It happens only once in +the lifecycle of a proposal, but can be triggered by two factors, whichever +happens first: + +* either someone tries to execute the proposal (see next section), which can + happen on a `Msg/Exec` transaction, or a `Msg/{SubmitProposal,Vote}` + transaction with the `Exec` field set. When a proposal execution is attempted, + a tally is done first to make sure the proposal passes. +* or on `EndBlock` when the proposal's voting period end just passed. + +If the tally result passes the decision policy's rules, then the proposal is +marked as `PROPOSAL_STATUS_ACCEPTED`, or else it is marked as +`PROPOSAL_STATUS_REJECTED`. In any case, no more voting is allowed anymore, and the tally +result is persisted to state in the proposal's `FinalTallyResult`. + +### Executing Proposals + +Proposals are executed only when the tallying is done, and the group account's +decision policy allows the proposal to pass based on the tally outcome. They +are marked by the status `PROPOSAL_STATUS_ACCEPTED`. Execution must happen +before a duration of `MaxExecutionPeriod` (set by the chain developer) after +each proposal's voting period end. + +Proposals will not be automatically executed by the chain in this current design, +but rather a user must submit a `Msg/Exec` transaction to attempt to execute the +proposal based on the current votes and decision policy. Any user (not only the +group members) can execute proposals that have been accepted, and execution fees are +paid by the proposal executor. +It's also possible to try to execute a proposal immediately on creation or on +new votes using the `Exec` field of `Msg/SubmitProposal` and `Msg/Vote` requests. +In the former case, proposers signatures are considered as yes votes. +In these cases, if the proposal can't be executed (i.e. it didn't pass the +decision policy's rules), it will still be opened for new votes and +could be tallied and executed later on. + +A successful proposal execution will have its `ExecutorResult` marked as +`PROPOSAL_EXECUTOR_RESULT_SUCCESS`. The proposal will be automatically pruned +after execution. On the other hand, a failed proposal execution will be marked +as `PROPOSAL_EXECUTOR_RESULT_FAILURE`. Such a proposal can be re-executed +multiple times, until it expires after `MaxExecutionPeriod` after voting period +end. + +## Pruning + +Proposals and votes are automatically pruned to avoid state bloat. + +Votes are pruned: + +* either after a successful tally, i.e. a tally whose result passes the decision + policy's rules, which can be trigged by a `Msg/Exec` or a + `Msg/{SubmitProposal,Vote}` with the `Exec` field set, +* or on `EndBlock` right after the proposal's voting period end. This applies to proposals with status `aborted` or `withdrawn` too. + +whichever happens first. + +Proposals are pruned: + +* on `EndBlock` whose proposal status is `withdrawn` or `aborted` on proposal's voting period end before tallying, +* and either after a successful proposal execution, +* or on `EndBlock` right after the proposal's `voting_period_end` + + `max_execution_period` (defined as an app-wide configuration) is passed, + +whichever happens first. + + + +# State + +The `group` module uses the `orm` package which provides table storage with support for +primary keys and secondary indexes. `orm` also defines `Sequence` which is a persistent unique key generator based on a counter that can be used along with `Table`s. + +Here's the list of tables and associated sequences and indexes stored as part of the `group` module. + +## Group Table + +The `groupTable` stores `GroupInfo`: `0x0 | BigEndian(GroupId) -> ProtocolBuffer(GroupInfo)`. + +### groupSeq + +The value of `groupSeq` is incremented when creating a new group and corresponds to the new `GroupId`: `0x1 | 0x1 -> BigEndian`. + +The second `0x1` corresponds to the ORM `sequenceStorageKey`. + +### groupByAdminIndex + +`groupByAdminIndex` allows to retrieve groups by admin address: +`0x2 | len([]byte(group.Admin)) | []byte(group.Admin) | BigEndian(GroupId) -> []byte()`. + +## Group Member Table + +The `groupMemberTable` stores `GroupMember`s: `0x10 | BigEndian(GroupId) | []byte(member.Address) -> ProtocolBuffer(GroupMember)`. + +The `groupMemberTable` is a primary key table and its `PrimaryKey` is given by +`BigEndian(GroupId) | []byte(member.Address)` which is used by the following indexes. + +### groupMemberByGroupIndex + +`groupMemberByGroupIndex` allows to retrieve group members by group id: +`0x11 | BigEndian(GroupId) | PrimaryKey -> []byte()`. + +### groupMemberByMemberIndex + +`groupMemberByMemberIndex` allows to retrieve group members by member address: +`0x12 | len([]byte(member.Address)) | []byte(member.Address) | PrimaryKey -> []byte()`. + +## Group Policy Table + +The `groupPolicyTable` stores `GroupPolicyInfo`: `0x20 | len([]byte(Address)) | []byte(Address) -> ProtocolBuffer(GroupPolicyInfo)`. + +The `groupPolicyTable` is a primary key table and its `PrimaryKey` is given by +`len([]byte(Address)) | []byte(Address)` which is used by the following indexes. + +### groupPolicySeq + +The value of `groupPolicySeq` is incremented when creating a new group policy and is used to generate the new group policy account `Address`: +`0x21 | 0x1 -> BigEndian`. + +The second `0x1` corresponds to the ORM `sequenceStorageKey`. + +### groupPolicyByGroupIndex + +`groupPolicyByGroupIndex` allows to retrieve group policies by group id: +`0x22 | BigEndian(GroupId) | PrimaryKey -> []byte()`. + +### groupPolicyByAdminIndex + +`groupPolicyByAdminIndex` allows to retrieve group policies by admin address: +`0x23 | len([]byte(Address)) | []byte(Address) | PrimaryKey -> []byte()`. + +## Proposal Table + +The `proposalTable` stores `Proposal`s: `0x30 | BigEndian(ProposalId) -> ProtocolBuffer(Proposal)`. + +### proposalSeq + +The value of `proposalSeq` is incremented when creating a new proposal and corresponds to the new `ProposalId`: `0x31 | 0x1 -> BigEndian`. + +The second `0x1` corresponds to the ORM `sequenceStorageKey`. + +### proposalByGroupPolicyIndex + +`proposalByGroupPolicyIndex` allows to retrieve proposals by group policy account address: +`0x32 | len([]byte(account.Address)) | []byte(account.Address) | BigEndian(ProposalId) -> []byte()`. + +### ProposalsByVotingPeriodEndIndex + +`proposalsByVotingPeriodEndIndex` allows to retrieve proposals sorted by chronological `voting_period_end`: +`0x33 | sdk.FormatTimeBytes(proposal.VotingPeriodEnd) | BigEndian(ProposalId) -> []byte()`. + +This index is used when tallying the proposal votes at the end of the voting period, and for pruning proposals at `VotingPeriodEnd + MaxExecutionPeriod`. + +## Vote Table + +The `voteTable` stores `Vote`s: `0x40 | BigEndian(ProposalId) | []byte(voter.Address) -> ProtocolBuffer(Vote)`. + +The `voteTable` is a primary key table and its `PrimaryKey` is given by +`BigEndian(ProposalId) | []byte(voter.Address)` which is used by the following indexes. + +### voteByProposalIndex + +`voteByProposalIndex` allows to retrieve votes by proposal id: +`0x41 | BigEndian(ProposalId) | PrimaryKey -> []byte()`. + +### voteByVoterIndex + +`voteByVoterIndex` allows to retrieve votes by voter address: +`0x42 | len([]byte(voter.Address)) | []byte(voter.Address) | PrimaryKey -> []byte()`. + + + +# Msg Service + +## Msg/CreateGroup + +A new group can be created with the `MsgCreateGroup`, which has an admin address, a list of members and some optional metadata. + +The metadata has a maximum length that is chosen by the app developer, and +passed into the group keeper as a config. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L66-L78 + +It's expected to fail if + +* metadata length is greater than `MaxMetadataLen` + config +* members are not correctly set (e.g. wrong address format, duplicates, or with 0 weight). + +## Msg/UpdateGroupMembers + +Group members can be updated with the `UpdateGroupMembers`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L87-L100 + +In the list of `MemberUpdates`, an existing member can be removed by setting its weight to 0. + +It's expected to fail if: + +* the signer is not the admin of the group. +* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group. + +## Msg/UpdateGroupAdmin + +The `UpdateGroupAdmin` can be used to update a group admin. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L105-L117 + +It's expected to fail if the signer is not the admin of the group. + +## Msg/UpdateGroupMetadata + +The `UpdateGroupMetadata` can be used to update a group metadata. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L122-L134 + +It's expected to fail if: + +* new metadata length is greater than `MaxMetadataLen` config. +* the signer is not the admin of the group. + +## Msg/CreateGroupPolicy + +A new group policy can be created with the `MsgCreateGroupPolicy`, which has an admin address, a group id, a decision policy and some optional metadata. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L143-L160 + +It's expected to fail if: + +* the signer is not the admin of the group. +* metadata length is greater than `MaxMetadataLen` config. +* the decision policy's `Validate()` method doesn't pass against the group. + +## Msg/CreateGroupWithPolicy + +A new group with policy can be created with the `MsgCreateGroupWithPolicy`, which has an admin address, a list of members, a decision policy, a `group_policy_as_admin` field to optionally set group and group policy admin with group policy address and some optional metadata for group and group policy. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L183-L206 + +It's expected to fail for the same reasons as `Msg/CreateGroup` and `Msg/CreateGroupPolicy`. + +## Msg/UpdateGroupPolicyAdmin + +The `UpdateGroupPolicyAdmin` can be used to update a group policy admin. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L169-L181 + +It's expected to fail if the signer is not the admin of the group policy. + +## Msg/UpdateGroupPolicyDecisionPolicy + +The `UpdateGroupPolicyDecisionPolicy` can be used to update a decision policy. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L219-L235 + +It's expected to fail if: + +* the signer is not the admin of the group policy. +* the new decision policy's `Validate()` method doesn't pass against the group. + +## Msg/UpdateGroupPolicyMetadata + +The `UpdateGroupPolicyMetadata` can be used to update a group policy metadata. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L240-L252 + +It's expected to fail if: + +* new metadata length is greater than `MaxMetadataLen` config. +* the signer is not the admin of the group. + +## Msg/SubmitProposal + +A new proposal can be created with the `MsgSubmitProposal`, which has a group policy account address, a list of proposers addresses, a list of messages to execute if the proposal is accepted and some optional metadata. +An optional `Exec` value can be provided to try to execute the proposal immediately after proposal creation. Proposers signatures are considered as yes votes in this case. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L275-L298 + +It's expected to fail if: + +* metadata length is greater than `MaxMetadataLen` config. +* if any of the proposers is not a group member. + +## Msg/WithdrawProposal + +A proposal can be withdrawn using `MsgWithdrawProposal` which has an `address` (can be either a proposer or the group policy admin) and a `proposal_id` (which has to be withdrawn). + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L307-L316 + +It's expected to fail if: + +* the signer is neither the group policy admin nor proposer of the proposal. +* the proposal is already closed or aborted. + +## Msg/Vote + +A new vote can be created with the `MsgVote`, given a proposal id, a voter address, a choice (yes, no, veto or abstain) and some optional metadata. +An optional `Exec` value can be provided to try to execute the proposal immediately after voting. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L321-L339 + +It's expected to fail if: + +* metadata length is greater than `MaxMetadataLen` config. +* the proposal is not in voting period anymore. + +## Msg/Exec + +A proposal can be executed with the `MsgExec`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L341-L353 + +The messages that are part of this proposal won't be executed if: + +* the proposal has not been accepted by the group policy. +* the proposal has already been successfully executed. + +## Msg/LeaveGroup + +The `MsgLeaveGroup` allows group member to leave a group. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L362-L370 + +It's expected to fail if: + +* the group member is not part of the group. +* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group. + + + +# Events + +The group module emits the following events: + +## EventCreateGroup + +| Type | Attribute Key | Attribute Value | +| -------------------------------- | ------------- | -------------------------------- | +| message | action | /cosmos.group.v1.Msg/CreateGroup | +| cosmos.group.v1.EventCreateGroup | group_id | {groupId} | + +## EventUpdateGroup + +| Type | Attribute Key | Attribute Value | +| -------------------------------- | ------------- | ---------------------------------------------------------- | +| message | action | /cosmos.group.v1.Msg/UpdateGroup{Admin\|Metadata\|Members} | +| cosmos.group.v1.EventUpdateGroup | group_id | {groupId} | + +## EventCreateGroupPolicy + +| Type | Attribute Key | Attribute Value | +| -------------------------------------- | ------------- | -------------------------------------- | +| message | action | /cosmos.group.v1.Msg/CreateGroupPolicy | +| cosmos.group.v1.EventCreateGroupPolicy | address | {groupPolicyAddress} | + +## EventUpdateGroupPolicy + +| Type | Attribute Key | Attribute Value | +| -------------------------------------- | ------------- | ----------------------------------------------------------------------- | +| message | action | /cosmos.group.v1.Msg/UpdateGroupPolicy{Admin\|Metadata\|DecisionPolicy} | +| cosmos.group.v1.EventUpdateGroupPolicy | address | {groupPolicyAddress} | + +## EventCreateProposal + +| Type | Attribute Key | Attribute Value | +| ----------------------------------- | ------------- | ----------------------------------- | +| message | action | /cosmos.group.v1.Msg/CreateProposal | +| cosmos.group.v1.EventCreateProposal | proposal_id | {proposalId} | + +## EventWithdrawProposal + +| Type | Attribute Key | Attribute Value | +| ------------------------------------- | ------------- | ------------------------------------- | +| message | action | /cosmos.group.v1.Msg/WithdrawProposal | +| cosmos.group.v1.EventWithdrawProposal | proposal_id | {proposalId} | + +## EventVote + +| Type | Attribute Key | Attribute Value | +| ------------------------- | ------------- | ------------------------- | +| message | action | /cosmos.group.v1.Msg/Vote | +| cosmos.group.v1.EventVote | proposal_id | {proposalId} | + +## EventExec + +| Type | Attribute Key | Attribute Value | +| ------------------------- | ------------- | ------------------------- | +| message | action | /cosmos.group.v1.Msg/Exec | +| cosmos.group.v1.EventExec | proposal_id | {proposalId} | +| cosmos.group.v1.EventExec | logs | {logs_string} | + +## EventLeaveGroup + +| Type | Attribute Key | Attribute Value | +| ------------------------------- | ------------- | ------------------------------- | +| message | action | /cosmos.group.v1.Msg/LeaveGroup | +| cosmos.group.v1.EventLeaveGroup | proposal_id | {proposalId} | +| cosmos.group.v1.EventLeaveGroup | address | {address} | + + + # Client ## CLI @@ -1509,3 +2056,58 @@ Example Output: } } ``` + + + +# Metadata + +The group module has four locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the group and gov modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. + +## Proposal + +Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../../gov/spec/08_metadata.md#proposal)) + +```json +{ + "title": "", + "authors": "", + "summary": "", + "details": "", + "proposalForumURL": "", + "voteOptionContext": "", +} +``` + +## Vote + +Location: on-chain as json within 255 character limit (mirrors [gov vote](../../gov/spec/08_metadata.md#vote)) + +```json +{ + "justification": "", +} +``` + +## Group + +Location: off-chain as json object stored on IPFS + +```json +{ + "name": "", + "description": "", + "groupWebsiteURL": "", + "groupForumURL": "", +} +``` + +## Decision policy + +Location: on-chain as json within 255 character limit + +```json +{ + "name": "", + "description": "", +} +``` diff --git a/x/group/internal/orm/README.md b/x/group/internal/orm/README.md new file mode 100644 index 000000000000..056d7be052be --- /dev/null +++ b/x/group/internal/orm/README.md @@ -0,0 +1,119 @@ +# Abstract + +The orm package provides a framework for creating relational database tables with primary and secondary keys. + +## Contents + +* [Table](#table) + * [AutoUInt64Table](#autouint64table) + * [PrimaryKeyTable](#primarykeytable) + * [PrimaryKeyed](#primarykeyed) + * [Key codec](#key-codec) +* [Secondary Index](#secondary-index) + * [MultiKeyIndex](#multikeyindex) + * [UniqueIndex](#uniqueindex) +* [Iterator and Pagination](#iterator-and-pagination) + * [Iterator](#iterator) + * [Pagination](#pagination) + +# Table + +A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L30-L36 + +In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes. +Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. + +The `table` struct does not: + +* enforce uniqueness of the `RowID` +* enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix of another +* optimize Gas usage conditions + +The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements. + +`table` provides methods for exporting (using a [`PrefixScan` `Iterator`](03_iterator_pagination.md#iterator)) and importing genesis data. For the import to be successful, objects have to be aware of their primary key by implementing the [`PrimaryKeyed`](#primarykeyed) interface. + +## AutoUInt64Table + +`AutoUInt64Table` is a table type with an auto incrementing `uint64` ID. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/auto_uint64.go#L15-L18 + +It's based on the `Sequence` struct which is a persistent unique key generator based on a counter encoded using 8 byte big endian. + +## PrimaryKeyTable + +`PrimaryKeyTable` provides simpler object style orm methods where are persisted and loaded with a reference to their unique primary key. + +### PrimaryKeyed + +The model provided for creating a `PrimaryKeyTable` should implement the `PrimaryKeyed` interface: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/primary_key.go#L30-L44 + +`PrimaryKeyFields()` method returns the list of key parts for a given object. +The primary key parts can be []byte, string, and `uint64` types. + +### Key codec + +Key parts, except the last part, follow these rules: + +* []byte is encoded with a single byte length prefix (which means the max []byte length is 255) +* strings are null-terminated +* `uint64` are encoded using 8 byte big endian. + +# Secondary Index + +Secondary indexes can be used on `Indexable` [tables](01_table.md). Indeed, those tables implement the `Indexable` interface that provides a set of functions that can be called by indexes to register and interact with the tables, like callback functions that are called on entries creation, update or deletion to create, update or remove corresponding entries in the table secondary indexes. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L88-L93 + +## MultiKeyIndex + +A `MultiKeyIndex` is an index where multiple entries can point to the same underlying object. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L26-L32 + +Internally, it uses an `Indexer` that manages the persistence of the index based on searchable keys and create/update/delete operations. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L15-L20 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/indexer.go#L15-L19 + +The currently used implementation of an `indexer`, `Indexer`, relies on an `IndexerFunc` that should be provided when instantiating the index. Based on the source object, this function returns one or multiple index keys as `[]interface{}`. Such secondary index keys should be bytes, string or `uint64` in order to be handled properly by the [key codec](01_table.md#key-codec) which defines specific encoding for those types. +In the index prefix store, the keys are built based on the source object's `RowID` and its secondary index key(s) using the key codec and the values are set as empty bytes. + +## UniqueIndex + +As opposed to `MultiKeyIndex`, `UniqueIndex` is an index where duplicate keys are prohibited. + +# Iterator and Pagination + +Both [tables](01_table.md) and [secondary indexes](02_secondary_index.md) support iterating over a domain of keys, through `PrefixScan` or `ReversePrefixScan`, as well pagination. + +## Iterator + +An `Iterator` allows iteration through a sequence of key value pairs. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L77-L85 + +Tables rely on a `typeSafeIterator` that is used by `PrefixScan` and `ReversePrefixScan` `table` methods to iterate through a range of `RowID`s. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L285-L290 + +Secondary indexes rely on an `indexIterator` that can strip the `RowID` from the full index key in order to get the underlying value in the table prefix store. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L232-L238 + +Under the hood, both use a prefix store `Iterator` (alias for tm-db `Iterator`). + +## Pagination + +The `Paginate` function does pagination given an [`Iterator`](#iterator) and a `query.PageRequest`, and returns a `query.PageResponse`. +It unmarshals the results into the provided dest interface that should be a pointer to a slice of models. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/iterator.go#L102-L220 + +Secondary indexes have a `GetPaginated` method that returns an `Iterator` for the given searched secondary index key, starting from the `query.PageRequest` key if provided. It's important to note that this `query.PageRequest` key should be a `RowID` (that could have been returned by a previous paginated request). The returned `Iterator` can then be used with the `Paginate` function and the same `query.PageRequest`. diff --git a/x/group/internal/orm/spec/01_table.md b/x/group/internal/orm/spec/01_table.md deleted file mode 100644 index 343a8378cb1a..000000000000 --- a/x/group/internal/orm/spec/01_table.md +++ /dev/null @@ -1,47 +0,0 @@ -# Table - -A table can be built given a `codec.ProtoMarshaler` model type, a prefix to access the underlying prefix store used to store table data as well as a `Codec` for marshalling/unmarshalling. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L30-L36 - -In the prefix store, entities should be stored by an unique identifier called `RowID` which can be based either on an `uint64` auto-increment counter, string or dynamic size bytes. -Regular CRUD operations can be performed on a table, these methods take a `sdk.KVStore` as parameter to get the table prefix store. - -The `table` struct does not: - -* enforce uniqueness of the `RowID` -* enforce prefix uniqueness of keys, i.e. not allowing one key to be a prefix of another -* optimize Gas usage conditions - -The `table` struct is private, so that we only have custom tables built on top of it, that do satisfy these requirements. - -`table` provides methods for exporting (using a [`PrefixScan` `Iterator`](03_iterator_pagination.md#iterator)) and importing genesis data. For the import to be successful, objects have to be aware of their primary key by implementing the [`PrimaryKeyed`](#primarykeyed) interface. - -## AutoUInt64Table - -`AutoUInt64Table` is a table type with an auto incrementing `uint64` ID. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/auto_uint64.go#L15-L18 - -It's based on the `Sequence` struct which is a persistent unique key generator based on a counter encoded using 8 byte big endian. - -## PrimaryKeyTable - -`PrimaryKeyTable` provides simpler object style orm methods where are persisted and loaded with a reference to their unique primary key. - -### PrimaryKeyed - -The model provided for creating a `PrimaryKeyTable` should implement the `PrimaryKeyed` interface: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/primary_key.go#L30-L44 - -`PrimaryKeyFields()` method returns the list of key parts for a given object. -The primary key parts can be []byte, string, and `uint64` types. - -### Key codec - -Key parts, except the last part, follow these rules: - -* []byte is encoded with a single byte length prefix (which means the max []byte length is 255) -* strings are null-terminated -* `uint64` are encoded using 8 byte big endian. diff --git a/x/group/internal/orm/spec/02_secondary_index.md b/x/group/internal/orm/spec/02_secondary_index.md deleted file mode 100644 index ba8495ab3b85..000000000000 --- a/x/group/internal/orm/spec/02_secondary_index.md +++ /dev/null @@ -1,24 +0,0 @@ -# Secondary Index - -Secondary indexes can be used on `Indexable` [tables](01_table.md). Indeed, those tables implement the `Indexable` interface that provides a set of functions that can be called by indexes to register and interact with the tables, like callback functions that are called on entries creation, update or deletion to create, update or remove corresponding entries in the table secondary indexes. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L88-L93 - -## MultiKeyIndex - -A `MultiKeyIndex` is an index where multiple entries can point to the same underlying object. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L26-L32 - -Internally, it uses an `Indexer` that manages the persistence of the index based on searchable keys and create/update/delete operations. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L15-L20 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/indexer.go#L15-L19 - -The currently used implementation of an `indexer`, `Indexer`, relies on an `IndexerFunc` that should be provided when instantiating the index. Based on the source object, this function returns one or multiple index keys as `[]interface{}`. Such secondary index keys should be bytes, string or `uint64` in order to be handled properly by the [key codec](01_table.md#key-codec) which defines specific encoding for those types. -In the index prefix store, the keys are built based on the source object's `RowID` and its secondary index key(s) using the key codec and the values are set as empty bytes. - -## UniqueIndex - -As opposed to `MultiKeyIndex`, `UniqueIndex` is an index where duplicate keys are prohibited. diff --git a/x/group/internal/orm/spec/03_iterator_pagination.md b/x/group/internal/orm/spec/03_iterator_pagination.md deleted file mode 100644 index e4fc52528ff5..000000000000 --- a/x/group/internal/orm/spec/03_iterator_pagination.md +++ /dev/null @@ -1,28 +0,0 @@ -# Iterator and Pagination - -Both [tables](01_table.md) and [secondary indexes](02_secondary_index.md) support iterating over a domain of keys, through `PrefixScan` or `ReversePrefixScan`, as well pagination. - -## Iterator - -An `Iterator` allows iteration through a sequence of key value pairs. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/types.go#L77-L85 - -Tables rely on a `typeSafeIterator` that is used by `PrefixScan` and `ReversePrefixScan` `table` methods to iterate through a range of `RowID`s. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/table.go#L285-L290 - -Secondary indexes rely on an `indexIterator` that can strip the `RowID` from the full index key in order to get the underlying value in the table prefix store. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/index.go#L232-L238 - -Under the hood, both use a prefix store `Iterator` (alias for tm-db `Iterator`). - -## Pagination - -The `Paginate` function does pagination given an [`Iterator`](#iterator) and a `query.PageRequest`, and returns a `query.PageResponse`. -It unmarshals the results into the provided dest interface that should be a pointer to a slice of models. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/internal/orm/iterator.go#L102-L220 - -Secondary indexes have a `GetPaginated` method that returns an `Iterator` for the given searched secondary index key, starting from the `query.PageRequest` key if provided. It's important to note that this `query.PageRequest` key should be a `RowID` (that could have been returned by a previous paginated request). The returned `Iterator` can then be used with the `Paginate` function and the same `query.PageRequest`. diff --git a/x/group/internal/orm/spec/README.md b/x/group/internal/orm/spec/README.md deleted file mode 100644 index 7aed09315fcf..000000000000 --- a/x/group/internal/orm/spec/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Abstract - -The orm package provides a framework for creating relational database tables with primary and secondary keys. - -## Contents - -1. **[Table](01_table.md)** - * [AutoUInt64Table](01_table.md#autouint64table) - * [PrimaryKeyTable](01_table.md#primarykeytable) -2. **[Secondary Index](02_secondary_index.md)** - * [MultiKeyIndex](02_secondary_index.md#multikeyindex) - * [UniqueIndex](02_secondary_index.md#uniqueindex) -3. **[Iterator and Pagination](03_iterator_pagination.md)** - * [Iterator](03_iterator_pagination.md#iterator) - * [Pagination](03_iterator_pagination.md#pagination) diff --git a/x/group/spec/01_concepts.md b/x/group/spec/01_concepts.md deleted file mode 100644 index 217a44c3cfc8..000000000000 --- a/x/group/spec/01_concepts.md +++ /dev/null @@ -1,157 +0,0 @@ - - -# Concepts - -## Group - -A group is simply an aggregation of accounts with associated weights. It is not -an account and doesn't have a balance. It doesn't in and of itself have any -sort of voting or decision weight. It does have an "administrator" which has -the ability to add, remove and update members in the group. Note that a -group policy account could be an administrator of a group, and that the -administrator doesn't necessarily have to be a member of the group. - -## Group Policy - -A group policy is an account associated with a group and a decision policy. -Group policies are abstracted from groups because a single group may have -multiple decision policies for different types of actions. Managing group -membership separately from decision policies results in the least overhead -and keeps membership consistent across different policies. The pattern that -is recommended is to have a single master group policy for a given group, -and then to create separate group policies with different decision policies -and delegate the desired permissions from the master account to -those "sub-accounts" using the `x/authz` module. - -## Decision Policy - -A decision policy is the mechanism by which members of a group can vote on -proposals, as well as the rules that dictate whether a proposal should pass -or not based on its tally outcome. - -All decision policies generally would have a mininum execution period and a -maximum voting window. The minimum execution period is the minimum amount of time -that must pass after submission in order for a proposal to potentially be executed, and it may -be set to 0. The maximum voting window is the maximum time after submission that a proposal may -be voted on before it is tallied. - -The chain developer also defines an app-wide maximum execution period, which is -the maximum amount of time after a proposal's voting period end where users are -allowed to execute a proposal. - -The current group module comes shipped with two decision policies: threshold -and percentage. Any chain developer can extend upon these two, by creating -custom decision policies, as long as they adhere to the `DecisionPolicy` -interface: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/x/group/types.go#L27-L41 - -### Threshold decision policy - -A threshold decision policy defines a threshold of yes votes (based on a tally -of voter weights) that must be achieved in order for a proposal to pass. For -this decision policy, abstain and veto are simply treated as no's. - -### Percentage decision policy - -A percentage decision policy is similar to a threshold decision policy, except -that the threshold is not defined as a constant weight, but as a percentage. -It's more suited for groups where the group members' weights can be updated, as -the percentage threshold stays the same, and doesn't depend on how those member -weights get updated. - -## Proposal - -Any member(s) of a group can submit a proposal for a group policy account to decide upon. -A proposal consists of a set of messages that will be executed if the proposal -passes as well as any metadata associated with the proposal. - -### Voting - -There are four choices to choose while voting - yes, no, abstain and veto. Not -all decision policies will take the four choices into account. Votes can contain some optional metadata. -In the current implementation, the voting window begins as soon as a proposal -is submitted, and the end is defined by the group policy's decision policy. - -### Withdrawing Proposals - -Proposals can be withdrawn any time before the voting period end, either by the -admin of the group policy or by one of the proposers. Once withdrawn, it is -marked as `PROPOSAL_STATUS_WITHDRAWN`, and no more voting or execution is -allowed on it. - -### Aborted Proposals - -If the group policy is updated during the voting period of the proposal, then -the proposal is marked as `PROPOSAL_STATUS_ABORTED`, and no more voting or -execution is allowed on it. This is because the group policy defines the rules -of proposal voting and execution, so if those rules change during the lifecycle -of a proposal, then the proposal should be marked as stale. - -### Tallying - -Tallying is the counting of all votes on a proposal. It happens only once in -the lifecycle of a proposal, but can be triggered by two factors, whichever -happens first: - -* either someone tries to execute the proposal (see next section), which can - happen on a `Msg/Exec` transaction, or a `Msg/{SubmitProposal,Vote}` - transaction with the `Exec` field set. When a proposal execution is attempted, - a tally is done first to make sure the proposal passes. -* or on `EndBlock` when the proposal's voting period end just passed. - -If the tally result passes the decision policy's rules, then the proposal is -marked as `PROPOSAL_STATUS_ACCEPTED`, or else it is marked as -`PROPOSAL_STATUS_REJECTED`. In any case, no more voting is allowed anymore, and the tally -result is persisted to state in the proposal's `FinalTallyResult`. - -### Executing Proposals - -Proposals are executed only when the tallying is done, and the group account's -decision policy allows the proposal to pass based on the tally outcome. They -are marked by the status `PROPOSAL_STATUS_ACCEPTED`. Execution must happen -before a duration of `MaxExecutionPeriod` (set by the chain developer) after -each proposal's voting period end. - -Proposals will not be automatically executed by the chain in this current design, -but rather a user must submit a `Msg/Exec` transaction to attempt to execute the -proposal based on the current votes and decision policy. Any user (not only the -group members) can execute proposals that have been accepted, and execution fees are -paid by the proposal executor. -It's also possible to try to execute a proposal immediately on creation or on -new votes using the `Exec` field of `Msg/SubmitProposal` and `Msg/Vote` requests. -In the former case, proposers signatures are considered as yes votes. -In these cases, if the proposal can't be executed (i.e. it didn't pass the -decision policy's rules), it will still be opened for new votes and -could be tallied and executed later on. - -A successful proposal execution will have its `ExecutorResult` marked as -`PROPOSAL_EXECUTOR_RESULT_SUCCESS`. The proposal will be automatically pruned -after execution. On the other hand, a failed proposal execution will be marked -as `PROPOSAL_EXECUTOR_RESULT_FAILURE`. Such a proposal can be re-executed -multiple times, until it expires after `MaxExecutionPeriod` after voting period -end. - -## Pruning - -Proposals and votes are automatically pruned to avoid state bloat. - -Votes are pruned: - -* either after a successful tally, i.e. a tally whose result passes the decision - policy's rules, which can be trigged by a `Msg/Exec` or a - `Msg/{SubmitProposal,Vote}` with the `Exec` field set, -* or on `EndBlock` right after the proposal's voting period end. This applies to proposals with status `aborted` or `withdrawn` too. - -whichever happens first. - -Proposals are pruned: - -* on `EndBlock` whose proposal status is `withdrawn` or `aborted` on proposal's voting period end before tallying, -* and either after a successful proposal execution, -* or on `EndBlock` right after the proposal's `voting_period_end` + - `max_execution_period` (defined as an app-wide configuration) is passed, - -whichever happens first. diff --git a/x/group/spec/02_state.md b/x/group/spec/02_state.md deleted file mode 100644 index a26d16313938..000000000000 --- a/x/group/spec/02_state.md +++ /dev/null @@ -1,105 +0,0 @@ - - -# State - -The `group` module uses the `orm` package which provides table storage with support for -primary keys and secondary indexes. `orm` also defines `Sequence` which is a persistent unique key generator based on a counter that can be used along with `Table`s. - -Here's the list of tables and associated sequences and indexes stored as part of the `group` module. - -## Group Table - -The `groupTable` stores `GroupInfo`: `0x0 | BigEndian(GroupId) -> ProtocolBuffer(GroupInfo)`. - -### groupSeq - -The value of `groupSeq` is incremented when creating a new group and corresponds to the new `GroupId`: `0x1 | 0x1 -> BigEndian`. - -The second `0x1` corresponds to the ORM `sequenceStorageKey`. - -### groupByAdminIndex - -`groupByAdminIndex` allows to retrieve groups by admin address: -`0x2 | len([]byte(group.Admin)) | []byte(group.Admin) | BigEndian(GroupId) -> []byte()`. - -## Group Member Table - -The `groupMemberTable` stores `GroupMember`s: `0x10 | BigEndian(GroupId) | []byte(member.Address) -> ProtocolBuffer(GroupMember)`. - -The `groupMemberTable` is a primary key table and its `PrimaryKey` is given by -`BigEndian(GroupId) | []byte(member.Address)` which is used by the following indexes. - -### groupMemberByGroupIndex - -`groupMemberByGroupIndex` allows to retrieve group members by group id: -`0x11 | BigEndian(GroupId) | PrimaryKey -> []byte()`. - -### groupMemberByMemberIndex - -`groupMemberByMemberIndex` allows to retrieve group members by member address: -`0x12 | len([]byte(member.Address)) | []byte(member.Address) | PrimaryKey -> []byte()`. - -## Group Policy Table - -The `groupPolicyTable` stores `GroupPolicyInfo`: `0x20 | len([]byte(Address)) | []byte(Address) -> ProtocolBuffer(GroupPolicyInfo)`. - -The `groupPolicyTable` is a primary key table and its `PrimaryKey` is given by -`len([]byte(Address)) | []byte(Address)` which is used by the following indexes. - -### groupPolicySeq - -The value of `groupPolicySeq` is incremented when creating a new group policy and is used to generate the new group policy account `Address`: -`0x21 | 0x1 -> BigEndian`. - -The second `0x1` corresponds to the ORM `sequenceStorageKey`. - -### groupPolicyByGroupIndex - -`groupPolicyByGroupIndex` allows to retrieve group policies by group id: -`0x22 | BigEndian(GroupId) | PrimaryKey -> []byte()`. - -### groupPolicyByAdminIndex - -`groupPolicyByAdminIndex` allows to retrieve group policies by admin address: -`0x23 | len([]byte(Address)) | []byte(Address) | PrimaryKey -> []byte()`. - -## Proposal Table - -The `proposalTable` stores `Proposal`s: `0x30 | BigEndian(ProposalId) -> ProtocolBuffer(Proposal)`. - -### proposalSeq - -The value of `proposalSeq` is incremented when creating a new proposal and corresponds to the new `ProposalId`: `0x31 | 0x1 -> BigEndian`. - -The second `0x1` corresponds to the ORM `sequenceStorageKey`. - -### proposalByGroupPolicyIndex - -`proposalByGroupPolicyIndex` allows to retrieve proposals by group policy account address: -`0x32 | len([]byte(account.Address)) | []byte(account.Address) | BigEndian(ProposalId) -> []byte()`. - -### ProposalsByVotingPeriodEndIndex - -`proposalsByVotingPeriodEndIndex` allows to retrieve proposals sorted by chronological `voting_period_end`: -`0x33 | sdk.FormatTimeBytes(proposal.VotingPeriodEnd) | BigEndian(ProposalId) -> []byte()`. - -This index is used when tallying the proposal votes at the end of the voting period, and for pruning proposals at `VotingPeriodEnd + MaxExecutionPeriod`. - -## Vote Table - -The `voteTable` stores `Vote`s: `0x40 | BigEndian(ProposalId) | []byte(voter.Address) -> ProtocolBuffer(Vote)`. - -The `voteTable` is a primary key table and its `PrimaryKey` is given by -`BigEndian(ProposalId) | []byte(voter.Address)` which is used by the following indexes. - -### voteByProposalIndex - -`voteByProposalIndex` allows to retrieve votes by proposal id: -`0x41 | BigEndian(ProposalId) | PrimaryKey -> []byte()`. - -### voteByVoterIndex - -`voteByVoterIndex` allows to retrieve votes by voter address: -`0x42 | len([]byte(voter.Address)) | []byte(voter.Address) | PrimaryKey -> []byte()`. diff --git a/x/group/spec/03_messages.md b/x/group/spec/03_messages.md deleted file mode 100644 index abfc0a0ea58c..000000000000 --- a/x/group/spec/03_messages.md +++ /dev/null @@ -1,159 +0,0 @@ - - -# Msg Service - -## Msg/CreateGroup - -A new group can be created with the `MsgCreateGroup`, which has an admin address, a list of members and some optional metadata. - -The metadata has a maximum length that is chosen by the app developer, and -passed into the group keeper as a config. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L66-L78 - -It's expected to fail if - -* metadata length is greater than `MaxMetadataLen` - config -* members are not correctly set (e.g. wrong address format, duplicates, or with 0 weight). - -## Msg/UpdateGroupMembers - -Group members can be updated with the `UpdateGroupMembers`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L87-L100 - -In the list of `MemberUpdates`, an existing member can be removed by setting its weight to 0. - -It's expected to fail if: - -* the signer is not the admin of the group. -* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group. - -## Msg/UpdateGroupAdmin - -The `UpdateGroupAdmin` can be used to update a group admin. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L105-L117 - -It's expected to fail if the signer is not the admin of the group. - -## Msg/UpdateGroupMetadata - -The `UpdateGroupMetadata` can be used to update a group metadata. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L122-L134 - -It's expected to fail if: - -* new metadata length is greater than `MaxMetadataLen` config. -* the signer is not the admin of the group. - -## Msg/CreateGroupPolicy - -A new group policy can be created with the `MsgCreateGroupPolicy`, which has an admin address, a group id, a decision policy and some optional metadata. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L143-L160 - -It's expected to fail if: - -* the signer is not the admin of the group. -* metadata length is greater than `MaxMetadataLen` config. -* the decision policy's `Validate()` method doesn't pass against the group. - -## Msg/CreateGroupWithPolicy - -A new group with policy can be created with the `MsgCreateGroupWithPolicy`, which has an admin address, a list of members, a decision policy, a `group_policy_as_admin` field to optionally set group and group policy admin with group policy address and some optional metadata for group and group policy. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L183-L206 - -It's expected to fail for the same reasons as `Msg/CreateGroup` and `Msg/CreateGroupPolicy`. - -## Msg/UpdateGroupPolicyAdmin - -The `UpdateGroupPolicyAdmin` can be used to update a group policy admin. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L169-L181 - -It's expected to fail if the signer is not the admin of the group policy. - -## Msg/UpdateGroupPolicyDecisionPolicy - -The `UpdateGroupPolicyDecisionPolicy` can be used to update a decision policy. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L219-L235 - -It's expected to fail if: - -* the signer is not the admin of the group policy. -* the new decision policy's `Validate()` method doesn't pass against the group. - -## Msg/UpdateGroupPolicyMetadata - -The `UpdateGroupPolicyMetadata` can be used to update a group policy metadata. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L240-L252 - -It's expected to fail if: - -* new metadata length is greater than `MaxMetadataLen` config. -* the signer is not the admin of the group. - -## Msg/SubmitProposal - -A new proposal can be created with the `MsgSubmitProposal`, which has a group policy account address, a list of proposers addresses, a list of messages to execute if the proposal is accepted and some optional metadata. -An optional `Exec` value can be provided to try to execute the proposal immediately after proposal creation. Proposers signatures are considered as yes votes in this case. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L275-L298 - -It's expected to fail if: - -* metadata length is greater than `MaxMetadataLen` config. -* if any of the proposers is not a group member. - -## Msg/WithdrawProposal - -A proposal can be withdrawn using `MsgWithdrawProposal` which has an `address` (can be either a proposer or the group policy admin) and a `proposal_id` (which has to be withdrawn). - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L307-L316 - -It's expected to fail if: - -* the signer is neither the group policy admin nor proposer of the proposal. -* the proposal is already closed or aborted. - -## Msg/Vote - -A new vote can be created with the `MsgVote`, given a proposal id, a voter address, a choice (yes, no, veto or abstain) and some optional metadata. -An optional `Exec` value can be provided to try to execute the proposal immediately after voting. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L321-L339 - -It's expected to fail if: - -* metadata length is greater than `MaxMetadataLen` config. -* the proposal is not in voting period anymore. - -## Msg/Exec - -A proposal can be executed with the `MsgExec`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L341-L353 - -The messages that are part of this proposal won't be executed if: - -* the proposal has not been accepted by the group policy. -* the proposal has already been successfully executed. - -## Msg/LeaveGroup - -The `MsgLeaveGroup` allows group member to leave a group. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/group/v1/tx.proto#L362-L370 - -It's expected to fail if: - -* the group member is not part of the group. -* for any one of the associated group policies, if its decision policy's `Validate()` method fails against the updated group. diff --git a/x/group/spec/04_events.md b/x/group/spec/04_events.md deleted file mode 100644 index ca4e2fdf20bb..000000000000 --- a/x/group/spec/04_events.md +++ /dev/null @@ -1,72 +0,0 @@ - - -# Events - -The group module emits the following events: - -## EventCreateGroup - -| Type | Attribute Key | Attribute Value | -| -------------------------------- | ------------- | -------------------------------- | -| message | action | /cosmos.group.v1.Msg/CreateGroup | -| cosmos.group.v1.EventCreateGroup | group_id | {groupId} | - -## EventUpdateGroup - -| Type | Attribute Key | Attribute Value | -| -------------------------------- | ------------- | ---------------------------------------------------------- | -| message | action | /cosmos.group.v1.Msg/UpdateGroup{Admin\|Metadata\|Members} | -| cosmos.group.v1.EventUpdateGroup | group_id | {groupId} | - -## EventCreateGroupPolicy - -| Type | Attribute Key | Attribute Value | -| -------------------------------------- | ------------- | -------------------------------------- | -| message | action | /cosmos.group.v1.Msg/CreateGroupPolicy | -| cosmos.group.v1.EventCreateGroupPolicy | address | {groupPolicyAddress} | - -## EventUpdateGroupPolicy - -| Type | Attribute Key | Attribute Value | -| -------------------------------------- | ------------- | ----------------------------------------------------------------------- | -| message | action | /cosmos.group.v1.Msg/UpdateGroupPolicy{Admin\|Metadata\|DecisionPolicy} | -| cosmos.group.v1.EventUpdateGroupPolicy | address | {groupPolicyAddress} | - -## EventCreateProposal - -| Type | Attribute Key | Attribute Value | -| ----------------------------------- | ------------- | ----------------------------------- | -| message | action | /cosmos.group.v1.Msg/CreateProposal | -| cosmos.group.v1.EventCreateProposal | proposal_id | {proposalId} | - -## EventWithdrawProposal - -| Type | Attribute Key | Attribute Value | -| ------------------------------------- | ------------- | ------------------------------------- | -| message | action | /cosmos.group.v1.Msg/WithdrawProposal | -| cosmos.group.v1.EventWithdrawProposal | proposal_id | {proposalId} | - -## EventVote - -| Type | Attribute Key | Attribute Value | -| ------------------------- | ------------- | ------------------------- | -| message | action | /cosmos.group.v1.Msg/Vote | -| cosmos.group.v1.EventVote | proposal_id | {proposalId} | - -## EventExec - -| Type | Attribute Key | Attribute Value | -| ------------------------- | ------------- | ------------------------- | -| message | action | /cosmos.group.v1.Msg/Exec | -| cosmos.group.v1.EventExec | proposal_id | {proposalId} | -| cosmos.group.v1.EventExec | logs | {logs_string} | - -## EventLeaveGroup - -| Type | Attribute Key | Attribute Value | -| ------------------------------- | ------------- | ------------------------------- | -| message | action | /cosmos.group.v1.Msg/LeaveGroup | -| cosmos.group.v1.EventLeaveGroup | proposal_id | {proposalId} | -| cosmos.group.v1.EventLeaveGroup | address | {address} | diff --git a/x/group/spec/06_metadata.md b/x/group/spec/06_metadata.md deleted file mode 100644 index 27108673557e..000000000000 --- a/x/group/spec/06_metadata.md +++ /dev/null @@ -1,52 +0,0 @@ - - -# Metadata - -The group module has four locations for metadata where users can provide further context about the on-chain actions they are taking. By default all metadata fields have a 255 character length field where metadata can be stored in json format, either on-chain or off-chain depending on the amount of data required. Here we provide a recommendation for the json structure and where the data should be stored. There are two important factors in making these recommendations. First, that the group and gov modules are consistent with one another, note the number of proposals made by all groups may be quite large. Second, that client applications such as block explorers and governance interfaces have confidence in the consistency of metadata structure accross chains. - -## Proposal -Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../../gov/spec/08_metadata.md#proposal)) - -```json -{ - "title": "", - "authors": "", - "summary": "", - "details": "", - "proposalForumURL": "", - "voteOptionContext": "", -} -``` - -## Vote -Location: on-chain as json within 255 character limit (mirrors [gov vote](../../gov/spec/08_metadata.md#vote)) - -```json -{ - "justification": "", -} -``` - -## Group -Location: off-chain as json object stored on IPFS - -```json -{ - "name": "", - "description": "", - "groupWebsiteURL": "", - "groupForumURL": "", -} -``` - -## Decision policy -Location: on-chain as json within 255 character limit - -```json -{ - "name": "", - "description": "", -} -``` \ No newline at end of file diff --git a/x/group/spec/README.md b/x/group/spec/README.md deleted file mode 100644 index 362a56e7016c..000000000000 --- a/x/group/spec/README.md +++ /dev/null @@ -1,63 +0,0 @@ - - -# Group Module - -## Abstract - -The following documents specify the group module. - -This module allows the creation and management of on-chain multisig accounts and enables voting for message execution based on configurable decision policies. - -## Contents - -1. **[Concepts](01_concepts.md)** - - [Group](01_concepts.md#group) - - [Group Policy](01_concepts.md#group-policy) - - [Group With Policy](01_concepts.md#group-with-policy) - - [Decision Policy](01_concepts.md#decision-policy) - - [Proposal](01_concepts.md#proposal) - - [Voting](01_concepts.md#voting) - - [Executing Proposals](01_concepts.md#executing-proposals) -2. **[State](02_state.md)** - * [Group Table](02_state.md#group-table) - * [Group Member Table](02_state.md#group-member-table) - * [Group Policy Table](02_state.md#group-policy-table) - * [Proposal](02_state.md#proposal-table) - * [Vote Table](02_state.md#vote-table) -3. **[Msg Service](03_messages.md)** - - [Msg/CreateGroup](03_messages.md#msgcreategroup) - - [Msg/UpdateGroupMembers](03_messages.md#msgupdategroupmembers) - - [Msg/UpdateGroupAdmin](03_messages.md#msgupdategroupadmin) - - [Msg/UpdateGroupMetadata](03_messages.md#msgupdategroupmetadata) - - [Msg/CreateGroupPolicy](03_messages.md#msgcreategrouppolicy) - - [Msg/CreateGroupWithPolicy](03_messages.md#msgcreategroupwithpolicy) - - [Msg/UpdateGroupPolicyAdmin](03_messages.md#msgupdategrouppolicyadmin) - - [Msg/UpdateGroupPolicyDecisionPolicy](03_messages.md#msgupdategrouppolicydecisionpolicy) - - [Msg/UpdateGroupPolicyMetadata](03_messages.md#msgupdategrouppolicymetadata) - - [Msg/CreateProposal](03_messages.md#msgcreateproposal) - - [Msg/WithdrawProposal](03_messages.md#msgwithdrawproposal) - - [Msg/Vote](03_messages.md#msgvote) - - [Msg/Exec](03_messages.md#msgexec) -4. **[Events](04_events.md)** - * [EventCreateGroup](04_events.md#eventcreategroup) - * [EventUpdateGroup](04_events.md#eventupdategroup) - * [EventCreateGroupPolicy](04_events.md#eventcreategrouppolicy) - * [EventUpdateGroupPolicy](04_events.md#eventupdategrouppolicy) - * [EventCreateProposal](04_events.md#eventcreateproposal) - * [EventWithdrawProposal](04_events.md#eventwithdrawproposal) - * [EventVote](04_events.md#eventvote) - * [EventExec](04_events.md#eventexec) -5. **[Client](05_client.md)** - * [CLI](05_client.md#cli) - * [gRPC](05_client.md#grpc) - * [REST](05_client.md#rest) -6. **[Metadata](06_metadata.md)** - * [Proposal](06_metadata.md#proposal) - * [Vote](06_metadata.md#vote) - * [Group](06_metadata.md#group) - * [Decision policy](06_metadata.md#decision%20policy) \ No newline at end of file diff --git a/x/mint/README.md b/x/mint/README.md index e5c3f70c11dc..a8856de215cc 100644 --- a/x/mint/README.md +++ b/x/mint/README.md @@ -1,7 +1,389 @@ -# Mint +# `x/mint` -* [Mint](spec/README.md) - Creation of new units of staking token. +## Contents + +* [State](#state) + * [Minter](#minter) + * [Params](#params) +* [Begin-Block](#begin-block) + * [NextInflationRate](#nextinflationrate) + * [NextAnnualProvisions](#nextannualprovisions) + * [BlockProvision](#blockprovision) +* [Parameters](#parameters) +* [Events](#events) + * [BeginBlocker](#beginblocker) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) + +# Concepts + +## The Minting Mechanism + +The minting mechanism was designed to: + +* allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio +* effect a balance between market liquidity and staked supply + +In order to best determine the appropriate market rate for inflation rewards, a +moving change rate is used. The moving change rate mechanism ensures that if +the % bonded is either over or under the goal %-bonded, the inflation rate will +adjust to further incentivize or disincentivize being bonded, respectively. Setting the goal +%-bonded at less than 100% encourages the network to maintain some non-staked tokens +which should help provide some liquidity. + +It can be broken down in the following way: + +* If the inflation rate is below the goal %-bonded the inflation rate will + increase until a maximum value is reached +* If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation + rate will stay constant +* If the inflation rate is above the goal %-bonded the inflation rate will + decrease until a minimum value is reached + + + +# State + +## Minter + +The minter is a space for holding current inflation information. + +* Minter: `0x00 -> ProtocolBuffer(minter)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L9-L23 + +## Params + +The mint module stores it's params in state with the prefix of `0x01`, +it can be updated with governance or the address with authority. + +* Params: `mint/params -> legacy_amino(params)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L25-L57 + + + +# Begin-Block + +Minting parameters are recalculated and inflation +paid at the beginning of each block. + +## Inflation rate calculation + +Inflation rate is calculated using an "inflation calculation function" that's +passed to the `NewAppModule` function. If no function is passed, then the SDK's +default inflation function will be used (`NextInflationRate`). In case a custom +inflation calculation logic is needed, this can be achieved by defining and +passing a function that matches `InflationCalculationFn`'s signature. + +```go +type InflationCalculationFn func(ctx sdk.Context, minter Minter, params Params, bondedRatio sdk.Dec) sdk.Dec +``` + +### NextInflationRate + +The target annual inflation rate is recalculated each block. +The inflation is also subject to a rate change (positive or negative) +depending on the distance from the desired ratio (67%). The maximum rate change +possible is defined to be 13% per year, however the annual inflation is capped +as between 7% and 20%. + +```go +NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) { + inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange + inflationRateChange = inflationRateChangePerYear/blocksPerYr + + // increase the new annual inflation for this next cycle + inflation += inflationRateChange + if inflation > params.InflationMax { + inflation = params.InflationMax + } + if inflation < params.InflationMin { + inflation = params.InflationMin + } + + return inflation +} +``` + +## NextAnnualProvisions + +Calculate the annual provisions based on current total supply and inflation +rate. This parameter is calculated once per block. + +```go +NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) { + return Inflation * totalSupply +``` + +## BlockProvision + +Calculate the provisions generated for each block based on current annual provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount` and then transferred to the `auth`'s `FeeCollector` `ModuleAccount`. + +```go +BlockProvision(params Params) sdk.Coin { + provisionAmt = AnnualProvisions/ params.BlocksPerYear + return sdk.NewCoin(params.MintDenom, provisionAmt.Truncate()) +``` + + + +# Parameters + +The minting module contains the following parameters: + +| Key | Type | Example | +|---------------------|-----------------|------------------------| +| MintDenom | string | "uatom" | +| InflationRateChange | string (dec) | "0.130000000000000000" | +| InflationMax | string (dec) | "0.200000000000000000" | +| InflationMin | string (dec) | "0.070000000000000000" | +| GoalBonded | string (dec) | "0.670000000000000000" | +| BlocksPerYear | string (uint64) | "6311520" | + + + +# Events + +The minting module emits the following events: + +## BeginBlocker + +| Type | Attribute Key | Attribute Value | +|------|-------------------|--------------------| +| mint | bonded_ratio | {bondedRatio} | +| mint | inflation | {inflation} | +| mint | annual_provisions | {annualProvisions} | +| mint | amount | {amount} | + + + +# Client + +## CLI + +A user can query and interact with the `mint` module using the CLI. + +### Query + +The `query` commands allow users to query `mint` state. + +```sh +simd query mint --help +``` + +#### annual-provisions + +The `annual-provisions` command allow users to query the current minting annual provisions value + +```sh +simd query mint annual-provisions [flags] +``` + +Example: + +```sh +simd query mint annual-provisions +``` + +Example Output: + +```sh +22268504368893.612100895088410693 +``` + +#### inflation + +The `inflation` command allow users to query the current minting inflation value + +```sh +simd query mint inflation [flags] +``` + +Example: + +```sh +simd query mint inflation +``` + +Example Output: + +```sh +0.199200302563256955 +``` + +#### params + +The `params` command allow users to query the current minting parameters + +```sh +simd query mint params [flags] +``` + +Example: + +```yml +blocks_per_year: "4360000" +goal_bonded: "0.670000000000000000" +inflation_max: "0.200000000000000000" +inflation_min: "0.070000000000000000" +inflation_rate_change: "0.130000000000000000" +mint_denom: stake +``` + +## gRPC + +A user can query the `mint` module using gRPC endpoints. + +### AnnualProvisions + +The `AnnualProvisions` endpoint allow users to query the current minting annual provisions value + +```sh +/cosmos.mint.v1beta1.Query/AnnualProvisions +``` + +Example: + +```sh +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/AnnualProvisions +``` + +Example Output: + +```json +{ + "annualProvisions": "1432452520532626265712995618" +} +``` + +### Inflation + +The `Inflation` endpoint allow users to query the current minting inflation value + +```sh +/cosmos.mint.v1beta1.Query/Inflation +``` + +Example: + +```sh +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Inflation +``` + +Example Output: + +```json +{ + "inflation": "130197115720711261" +} +``` + +### Params + +The `Params` endpoint allow users to query the current minting parameters + +```sh +/cosmos.mint.v1beta1.Query/Params +``` + +Example: + +```sh +grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Params +``` + +Example Output: + +```json +{ + "params": { + "mintDenom": "stake", + "inflationRateChange": "130000000000000000", + "inflationMax": "200000000000000000", + "inflationMin": "70000000000000000", + "goalBonded": "670000000000000000", + "blocksPerYear": "6311520" + } +} +``` + +## REST + +A user can query the `mint` module using REST endpoints. + +### annual-provisions + +```sh +/cosmos/mint/v1beta1/annual_provisions +``` + +Example: + +```sh +curl "localhost:1317/cosmos/mint/v1beta1/annual_provisions" +``` + +Example Output: + +```json +{ + "annualProvisions": "1432452520532626265712995618" +} +``` + +### inflation + +```sh +/cosmos/mint/v1beta1/inflation +``` + +Example: + +```sh +curl "localhost:1317/cosmos/mint/v1beta1/inflation" +``` + +Example Output: + +```json +{ + "inflation": "130197115720711261" +} +``` + +### params + +```sh +/cosmos/mint/v1beta1/params +``` + +Example: + +```sh +curl "localhost:1317/cosmos/mint/v1beta1/params" +``` + +Example Output: + +```json +{ + "params": { + "mintDenom": "stake", + "inflationRateChange": "130000000000000000", + "inflationMax": "200000000000000000", + "inflationMin": "70000000000000000", + "goalBonded": "670000000000000000", + "blocksPerYear": "6311520" + } +} +``` diff --git a/x/mint/spec/01_concepts.md b/x/mint/spec/01_concepts.md deleted file mode 100644 index 11669404d195..000000000000 --- a/x/mint/spec/01_concepts.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# Concepts - -## The Minting Mechanism - -The minting mechanism was designed to: - -* allow for a flexible inflation rate determined by market demand targeting a particular bonded-stake ratio -* effect a balance between market liquidity and staked supply - -In order to best determine the appropriate market rate for inflation rewards, a -moving change rate is used. The moving change rate mechanism ensures that if -the % bonded is either over or under the goal %-bonded, the inflation rate will -adjust to further incentivize or disincentivize being bonded, respectively. Setting the goal -%-bonded at less than 100% encourages the network to maintain some non-staked tokens -which should help provide some liquidity. - -It can be broken down in the following way: - -* If the inflation rate is below the goal %-bonded the inflation rate will - increase until a maximum value is reached -* If the goal % bonded (67% in Cosmos-Hub) is maintained, then the inflation - rate will stay constant -* If the inflation rate is above the goal %-bonded the inflation rate will - decrease until a minimum value is reached diff --git a/x/mint/spec/02_state.md b/x/mint/spec/02_state.md deleted file mode 100644 index c038197937bd..000000000000 --- a/x/mint/spec/02_state.md +++ /dev/null @@ -1,22 +0,0 @@ - - -# State - -## Minter - -The minter is a space for holding current inflation information. - -* Minter: `0x00 -> ProtocolBuffer(minter)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L9-L23 - -## Params - -The mint module stores it's params in state with the prefix of `0x01`, -it can be updated with governance or the address with authority. - -* Params: `mint/params -> legacy_amino(params)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/mint/v1beta1/mint.proto#L25-L57 diff --git a/x/mint/spec/03_begin_block.md b/x/mint/spec/03_begin_block.md deleted file mode 100644 index 67bd7d8a8f53..000000000000 --- a/x/mint/spec/03_begin_block.md +++ /dev/null @@ -1,66 +0,0 @@ - - -# Begin-Block - -Minting parameters are recalculated and inflation -paid at the beginning of each block. - -## Inflation rate calculation - -Inflation rate is calculated using an "inflation calculation function" that's -passed to the `NewAppModule` function. If no function is passed, then the SDK's -default inflation function will be used (`NextInflationRate`). In case a custom -inflation calculation logic is needed, this can be achieved by defining and -passing a function that matches `InflationCalculationFn`'s signature. - -```go -type InflationCalculationFn func(ctx sdk.Context, minter Minter, params Params, bondedRatio sdk.Dec) sdk.Dec -``` - -### NextInflationRate - -The target annual inflation rate is recalculated each block. -The inflation is also subject to a rate change (positive or negative) -depending on the distance from the desired ratio (67%). The maximum rate change -possible is defined to be 13% per year, however the annual inflation is capped -as between 7% and 20%. - -```go -NextInflationRate(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) { - inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange - inflationRateChange = inflationRateChangePerYear/blocksPerYr - - // increase the new annual inflation for this next cycle - inflation += inflationRateChange - if inflation > params.InflationMax { - inflation = params.InflationMax - } - if inflation < params.InflationMin { - inflation = params.InflationMin - } - - return inflation -} -``` - -## NextAnnualProvisions - -Calculate the annual provisions based on current total supply and inflation -rate. This parameter is calculated once per block. - -```go -NextAnnualProvisions(params Params, totalSupply sdk.Dec) (provisions sdk.Dec) { - return Inflation * totalSupply -``` - -## BlockProvision - -Calculate the provisions generated for each block based on current annual provisions. The provisions are then minted by the `mint` module's `ModuleMinterAccount` and then transferred to the `auth`'s `FeeCollector` `ModuleAccount`. - -```go -BlockProvision(params Params) sdk.Coin { - provisionAmt = AnnualProvisions/ params.BlocksPerYear - return sdk.NewCoin(params.MintDenom, provisionAmt.Truncate()) -``` diff --git a/x/mint/spec/04_params.md b/x/mint/spec/04_params.md deleted file mode 100644 index ed18e5557ebb..000000000000 --- a/x/mint/spec/04_params.md +++ /dev/null @@ -1,16 +0,0 @@ - - -# Parameters - -The minting module contains the following parameters: - -| Key | Type | Example | -|---------------------|-----------------|------------------------| -| MintDenom | string | "uatom" | -| InflationRateChange | string (dec) | "0.130000000000000000" | -| InflationMax | string (dec) | "0.200000000000000000" | -| InflationMin | string (dec) | "0.070000000000000000" | -| GoalBonded | string (dec) | "0.670000000000000000" | -| BlocksPerYear | string (uint64) | "6311520" | diff --git a/x/mint/spec/05_events.md b/x/mint/spec/05_events.md deleted file mode 100644 index f6130a3b999a..000000000000 --- a/x/mint/spec/05_events.md +++ /dev/null @@ -1,16 +0,0 @@ - - -# Events - -The minting module emits the following events: - -## BeginBlocker - -| Type | Attribute Key | Attribute Value | -|------|-------------------|--------------------| -| mint | bonded_ratio | {bondedRatio} | -| mint | inflation | {inflation} | -| mint | annual_provisions | {annualProvisions} | -| mint | amount | {amount} | diff --git a/x/mint/spec/06_client.md b/x/mint/spec/06_client.md deleted file mode 100644 index a79063a99be1..000000000000 --- a/x/mint/spec/06_client.md +++ /dev/null @@ -1,224 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `mint` module using the CLI. - -### Query - -The `query` commands allow users to query `mint` state. - -```sh -simd query mint --help -``` - -#### annual-provisions - -The `annual-provisions` command allow users to query the current minting annual provisions value - -```sh -simd query mint annual-provisions [flags] -``` - -Example: - -```sh -simd query mint annual-provisions -``` - -Example Output: - -```sh -22268504368893.612100895088410693 -``` - -#### inflation - -The `inflation` command allow users to query the current minting inflation value - -```sh -simd query mint inflation [flags] -``` - -Example: - -```sh -simd query mint inflation -``` - -Example Output: - -```sh -0.199200302563256955 -``` - -#### params - -The `params` command allow users to query the current minting parameters - -```sh -simd query mint params [flags] -``` - -Example: - -```yml -blocks_per_year: "4360000" -goal_bonded: "0.670000000000000000" -inflation_max: "0.200000000000000000" -inflation_min: "0.070000000000000000" -inflation_rate_change: "0.130000000000000000" -mint_denom: stake -``` - -## gRPC - -A user can query the `mint` module using gRPC endpoints. - -### AnnualProvisions - -The `AnnualProvisions` endpoint allow users to query the current minting annual provisions value - -```sh -/cosmos.mint.v1beta1.Query/AnnualProvisions -``` - -Example: - -```sh -grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/AnnualProvisions -``` - -Example Output: - -```json -{ - "annualProvisions": "1432452520532626265712995618" -} -``` - -### Inflation - -The `Inflation` endpoint allow users to query the current minting inflation value - -```sh -/cosmos.mint.v1beta1.Query/Inflation -``` - -Example: - -```sh -grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Inflation -``` - -Example Output: - -```json -{ - "inflation": "130197115720711261" -} -``` - -### Params - -The `Params` endpoint allow users to query the current minting parameters - -```sh -/cosmos.mint.v1beta1.Query/Params -``` - -Example: - -```sh -grpcurl -plaintext localhost:9090 cosmos.mint.v1beta1.Query/Params -``` - -Example Output: - -```json -{ - "params": { - "mintDenom": "stake", - "inflationRateChange": "130000000000000000", - "inflationMax": "200000000000000000", - "inflationMin": "70000000000000000", - "goalBonded": "670000000000000000", - "blocksPerYear": "6311520" - } -} -``` - -## REST - -A user can query the `mint` module using REST endpoints. - -### annual-provisions - -```sh -/cosmos/mint/v1beta1/annual_provisions -``` - -Example: - -```sh -curl "localhost:1317/cosmos/mint/v1beta1/annual_provisions" -``` - -Example Output: - -```json -{ - "annualProvisions": "1432452520532626265712995618" -} -``` - -### inflation - -```sh -/cosmos/mint/v1beta1/inflation -``` - -Example: - -```sh -curl "localhost:1317/cosmos/mint/v1beta1/inflation" -``` - -Example Output: - -```json -{ - "inflation": "130197115720711261" -} -``` - -### params - -```sh -/cosmos/mint/v1beta1/params -``` - -Example: - -```sh -curl "localhost:1317/cosmos/mint/v1beta1/params" -``` - -Example Output: - -```json -{ - "params": { - "mintDenom": "stake", - "inflationRateChange": "130000000000000000", - "inflationMax": "200000000000000000", - "inflationMin": "70000000000000000", - "goalBonded": "670000000000000000", - "blocksPerYear": "6311520" - } -} -``` diff --git a/x/mint/spec/README.md b/x/mint/spec/README.md deleted file mode 100644 index 400d723b2a3c..000000000000 --- a/x/mint/spec/README.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# `mint` - -## Contents - -1. **[Concept](01_concepts.md)** -2. **[State](02_state.md)** - * [Minter](02_state.md#minter) - * [Params](02_state.md#params) -3. **[Begin-Block](03_begin_block.md)** - * [NextInflationRate](03_begin_block.md#nextinflationrate) - * [NextAnnualProvisions](03_begin_block.md#nextannualprovisions) - * [BlockProvision](03_begin_block.md#blockprovision) -4. **[Parameters](04_params.md)** -5. **[Events](05_events.md)** - * [BeginBlocker](05_events.md#beginblocker) -6. **[Client](06_client.md)** - * [CLI](06_client.md#cli) - * [gRPC](06_client.md#grpc) - * [REST](06_client.md#rest) diff --git a/x/nft/README.md b/x/nft/README.md new file mode 100644 index 000000000000..82179d5bbb78 --- /dev/null +++ b/x/nft/README.md @@ -0,0 +1,88 @@ + + +# `x/nft` + +## Contents + +## Abstract + +`x/nft` is an implementation of a Cosmos SDK module, per [ADR 43](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md), that allows you to create nft classification, create nft, transfer nft, update nft, and support various queries by integrating the module. It is fully compatible with the ERC721 specification. + +* [Concept](#concepts) + * [Class](#class) + * [NFT](#nft) +*[State](#state) +*[Messages](#messages) + * [MsgSend](#msgsend) +*[Events](#events) + +# Concepts + +## Class + +`x/nft` module defines a struct `Class` to describe the common characteristics of a class of nft, under this class, you can create a variety of nft, which is equivalent to an erc721 contract for Ethereum. The design is defined in the [ADR 043](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md). + +## NFT + +The full name of NFT is Non-Fungible Tokens. Because of the irreplaceable nature of NFT, it means that it can be used to represent unique things. The nft implemented by this module is fully compatible with Ethereum ERC721 standard. + + + +# State + +## Class + +Class is mainly composed of `id`, `name`, `symbol`, `description`, `uri`, `uri_hash`,`data` where `id` is the unique identifier of the class, similar to the Ethereum ERC721 contract address, the others are optional. + +* Class: `0x01 | classID | -> ProtocolBuffer(Class)` + +## NFT + +NFT is mainly composed of `class_id`, `id`, `uri`, `uri_hash` and `data`. Among them, `class_id` and `id` are two-tuples that identify the uniqueness of nft, `uri` and `uri_hash` is optional, which identifies the off-chain storage location of the nft, and `data` is an Any type. Use Any chain of `x/nft` modules can be customized by extending this field + +* NFT: `0x02 | classID | 0x00 | nftID |-> ProtocolBuffer(NFT)` + +## NFTOfClassByOwner + +NFTOfClassByOwner is mainly to realize the function of querying all nfts using classID and owner, without other redundant functions. + +* NFTOfClassByOwner: `0x03 | owner | 0x00 | classID | 0x00 | nftID |-> 0x01` + +## Owner + +Since there is no extra field in NFT to indicate the owner of nft, an additional key-value pair is used to save the ownership of nft. With the transfer of nft, the key-value pair is updated synchronously. + +* OwnerKey: `0x04 | classID | 0x00 | nftID |-> owner` + +## TotalSupply + +TotalSupply is responsible for tracking the number of all nfts under a certain class. Mint operation is performed under the changed class, supply increases by one, burn operation, and supply decreases by one. + +* OwnerKey: `0x05 | classID |-> totalSupply` + + + +# Messages + +In this section we describe the processing of messages for the nft module. + +## MsgSend + +You can use the `MsgSend` message to transfer the ownership of nft. This is a function provided by the `x/nft` module. Of course, you can use the `Transfer` method to implement your own transfer logic, but you need to pay extra attention to the transfer permissions. + +The message handling should fail if: + +* provided `ClassID` is not exist. +* provided `Id` is not exist. +* provided `Sender` is not the owner of nft. + + + +# Events + +The nft module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main:cosmos.nft.v1beta1). diff --git a/x/nft/spec/01_concepts.md b/x/nft/spec/01_concepts.md deleted file mode 100644 index ae4bbd99f7c9..000000000000 --- a/x/nft/spec/01_concepts.md +++ /dev/null @@ -1,13 +0,0 @@ - - -# Concepts - -## Class - -`x/nft` module defines a struct `Class` to describe the common characteristics of a class of nft, under this class, you can create a variety of nft, which is equivalent to an erc721 contract for Ethereum. The design is defined in the [ADR 043](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md). - -## NFT - -The full name of NFT is Non-Fungible Tokens. Because of the irreplaceable nature of NFT, it means that it can be used to represent unique things. The nft implemented by this module is fully compatible with Ethereum ERC721 standard. diff --git a/x/nft/spec/02_state.md b/x/nft/spec/02_state.md deleted file mode 100644 index 6edb0c1d0c59..000000000000 --- a/x/nft/spec/02_state.md +++ /dev/null @@ -1,35 +0,0 @@ - - -# State - -## Class - -Class is mainly composed of `id`, `name`, `symbol`, `description`, `uri`, `uri_hash`,`data` where `id` is the unique identifier of the class, similar to the Ethereum ERC721 contract address, the others are optional. - -* Class: `0x01 | classID | -> ProtocolBuffer(Class)` - -## NFT - -NFT is mainly composed of `class_id`, `id`, `uri`, `uri_hash` and `data`. Among them, `class_id` and `id` are two-tuples that identify the uniqueness of nft, `uri` and `uri_hash` is optional, which identifies the off-chain storage location of the nft, and `data` is an Any type. Use Any chain of `x/nft` modules can be customized by extending this field - -* NFT: `0x02 | classID | 0x00 | nftID |-> ProtocolBuffer(NFT)` - -## NFTOfClassByOwner - -NFTOfClassByOwner is mainly to realize the function of querying all nfts using classID and owner, without other redundant functions. - -* NFTOfClassByOwner: `0x03 | owner | 0x00 | classID | 0x00 | nftID |-> 0x01` - -## Owner - -Since there is no extra field in NFT to indicate the owner of nft, an additional key-value pair is used to save the ownership of nft. With the transfer of nft, the key-value pair is updated synchronously. - -* OwnerKey: `0x04 | classID | 0x00 | nftID |-> owner` - -## TotalSupply - -TotalSupply is responsible for tracking the number of all nfts under a certain class. Mint operation is performed under the changed class, supply increases by one, burn operation, and supply decreases by one. - -* OwnerKey: `0x05 | classID |-> totalSupply` diff --git a/x/nft/spec/03_messages.md b/x/nft/spec/03_messages.md deleted file mode 100644 index fd1ce0c321e6..000000000000 --- a/x/nft/spec/03_messages.md +++ /dev/null @@ -1,17 +0,0 @@ - - -# Messages - -In this section we describe the processing of messages for the nft module. - -## MsgSend - -You can use the `MsgSend` message to transfer the ownership of nft. This is a function provided by the `x/nft` module. Of course, you can use the `Transfer` method to implement your own transfer logic, but you need to pay extra attention to the transfer permissions. - -The message handling should fail if: - -* provided `ClassID` is not exist. -* provided `Id` is not exist. -* provided `Sender` is not the owner of nft. diff --git a/x/nft/spec/04_events.md b/x/nft/spec/04_events.md deleted file mode 100644 index a831c8b7b216..000000000000 --- a/x/nft/spec/04_events.md +++ /dev/null @@ -1,3 +0,0 @@ -# Events - -The nft module emits proto events defined in [the Protobuf reference](https://buf.build/cosmos/cosmos-sdk/docs/main:cosmos.nft.v1beta1). diff --git a/x/nft/spec/README.md b/x/nft/spec/README.md deleted file mode 100644 index 570a15058c35..000000000000 --- a/x/nft/spec/README.md +++ /dev/null @@ -1,22 +0,0 @@ - - -# `nft` - -## Contents - -## Abstract - -`x/nft` is an implementation of a Cosmos SDK module, per [ADR 43](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-043-nft-module.md), that allows you to create nft classification, create nft, transfer nft, update nft, and support various queries by integrating the module. It is fully compatible with the ERC721 specification. - -1. **[Concept](01_concepts.md)** - * [Class](01_concepts.md#Class) - * [NFT](01_concepts.md#NFT) -2. **[State](02_state.md)** -3. **[Messages](03_messages.md)** - * [MsgSend](03_messages.md#MsgSend) -4. **[Events](04_events.md)** diff --git a/x/params/README.md b/x/params/README.md index 82fb82fde69f..9a35d3debef0 100644 --- a/x/params/README.md +++ b/x/params/README.md @@ -1,7 +1,86 @@ -# Params +# `x/params` (Deprecated) -* [Params](spec/README.md) - Globally available parameter store. +> Note: The Params module has been depreacted in favour of each module housing its own parameters. + +## Abstract + +Package params provides a globally available parameter store. + +There are two main types, Keeper and Subspace. Subspace is an isolated namespace for a +paramstore, where keys are prefixed by preconfigured spacename. Keeper has a +permission to access all existing spaces. + +Subspace can be used by the individual keepers, which need a private parameter store +that the other keepers cannot modify. The params Keeper can be used to add a route to `x/gov` router in order to modify any parameter in case a proposal passes. + +The following contents explains how to use params module for master and user modules. + +## Contents + +* [Keeper](#keeper) +* [Subspace](#subspace) + * [Key](#key) + * [KeyTable](#keytable) + * [ParamSet](#paramset) + + + +# Keeper + +In the app initialization stage, [subspaces](#subspace) can be allocated for other modules' keeper using `Keeper.Subspace` and are stored in `Keeper.spaces`. Then, those modules can have a reference to their specific parameter store through `Keeper.GetSubspace`. + +Example: + +```go +type ExampleKeeper struct { + paramSpace paramtypes.Subspace +} + +func (k ExampleKeeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramSpace.SetParamSet(ctx, ¶ms) +} +``` + + + +# Subspace + +`Subspace` is a prefixed subspace of the parameter store. Each module which uses the +parameter store will take a `Subspace` to isolate permission to access. + +## Key + +Parameter keys are human readable alphanumeric strings. A parameter for the key +`"ExampleParameter"` is stored under `[]byte("SubspaceName" + "/" + "ExampleParameter")`, + where `"SubspaceName"` is the name of the subspace. + +Subkeys are secondary parameter keys those are used along with a primary parameter key. +Subkeys can be used for grouping or dynamic parameter key generation during runtime. + +## KeyTable + +All of the parameter keys that will be used should be registered at the compile +time. `KeyTable` is essentially a `map[string]attribute`, where the `string` is a parameter key. + +Currently, `attribute` consists of a `reflect.Type`, which indicates the parameter +type to check that provided key and value are compatible and registered, as well as a function `ValueValidatorFn` to validate values. + +Only primary keys have to be registered on the `KeyTable`. Subkeys inherit the +attribute of the primary key. + +## ParamSet + +Modules often define parameters as a proto message. The generated struct can implement +`ParamSet` interface to be used with the following methods: + +* `KeyTable.RegisterParamSet()`: registers all parameters in the struct +* `Subspace.{Get, Set}ParamSet()`: Get to & Set from the struct + +The implementor should be a pointer in order to use `GetParamSet()`. diff --git a/x/params/spec/01_keeper.md b/x/params/spec/01_keeper.md deleted file mode 100644 index fa97ec5b37fc..000000000000 --- a/x/params/spec/01_keeper.md +++ /dev/null @@ -1,19 +0,0 @@ - - -# Keeper - -In the app initialization stage, [subspaces](02_subspace.md) can be allocated for other modules' keeper using `Keeper.Subspace` and are stored in `Keeper.spaces`. Then, those modules can have a reference to their specific parameter store through `Keeper.GetSubspace`. - -Example: - -```go -type ExampleKeeper struct { - paramSpace paramtypes.Subspace -} - -func (k ExampleKeeper) SetParams(ctx sdk.Context, params types.Params) { - k.paramSpace.SetParamSet(ctx, ¶ms) -} -``` diff --git a/x/params/spec/02_subspace.md b/x/params/spec/02_subspace.md deleted file mode 100644 index 2eaa391a25c9..000000000000 --- a/x/params/spec/02_subspace.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Subspace - -`Subspace` is a prefixed subspace of the parameter store. Each module which uses the -parameter store will take a `Subspace` to isolate permission to access. - -## Key - -Parameter keys are human readable alphanumeric strings. A parameter for the key -`"ExampleParameter"` is stored under `[]byte("SubspaceName" + "/" + "ExampleParameter")`, - where `"SubspaceName"` is the name of the subspace. - -Subkeys are secondary parameter keys those are used along with a primary parameter key. -Subkeys can be used for grouping or dynamic parameter key generation during runtime. - -## KeyTable - -All of the parameter keys that will be used should be registered at the compile -time. `KeyTable` is essentially a `map[string]attribute`, where the `string` is a parameter key. - -Currently, `attribute` consists of a `reflect.Type`, which indicates the parameter -type to check that provided key and value are compatible and registered, as well as a function `ValueValidatorFn` to validate values. - -Only primary keys have to be registered on the `KeyTable`. Subkeys inherit the -attribute of the primary key. - -## ParamSet - -Modules often define parameters as a proto message. The generated struct can implement -`ParamSet` interface to be used with the following methods: - -* `KeyTable.RegisterParamSet()`: registers all parameters in the struct -* `Subspace.{Get, Set}ParamSet()`: Get to & Set from the struct - -The implementor should be a pointer in order to use `GetParamSet()`. diff --git a/x/params/spec/README.md b/x/params/spec/README.md deleted file mode 100644 index cdeeb1a66077..000000000000 --- a/x/params/spec/README.md +++ /dev/null @@ -1,31 +0,0 @@ - - -# `params` (Deprecated) - -> Note: The Params module has been depreacted in favour of each module housing its own parameters. - -## Abstract - -Package params provides a globally available parameter store. - -There are two main types, Keeper and Subspace. Subspace is an isolated namespace for a -paramstore, where keys are prefixed by preconfigured spacename. Keeper has a -permission to access all existing spaces. - -Subspace can be used by the individual keepers, which need a private parameter store -that the other keepers cannot modify. The params Keeper can be used to add a route to `x/gov` router in order to modify any parameter in case a proposal passes. - -The following contents explains how to use params module for master and user modules. - -## Contents - -1. **[Keeper](01_keeper.md)** -2. **[Subspace](02_subspace.md)** - * [Key](02_subspace.md#key) - * [KeyTable](02_subspace.md#keytable) - * [ParamSet](02_subspace.md#paramset) diff --git a/x/slashing/README.md b/x/slashing/README.md index 9f79636b9892..9647d6912989 100644 --- a/x/slashing/README.md +++ b/x/slashing/README.md @@ -1,7 +1,828 @@ -# Slashing +# `x/slashing` -* [Slashing](spec/README.md) - validator punishment mechanisms. +## Abstract + +This section specifies the slashing module of the Cosmos SDK, which implements functionality +first outlined in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in June 2016. + +The slashing module enables Cosmos SDK-based blockchains to disincentivize any attributable action +by a protocol-recognized actor with value at stake by penalizing them ("slashing"). + +Penalties may include, but are not limited to: + +* Burning some amount of their stake +* Removing their ability to vote on future blocks for a period of time. + +This module will be used by the Cosmos Hub, the first hub in the Cosmos ecosystem. + +## Contents + +* [Concepts](#concepts) + * [States](#states) + * [Tombstone Caps](#tombstone-caps) + * [Infraction Timelines](#infraction-timelines) +* [State](#state) + * [Signing Info (Liveness)](#signing-info-liveness) + * [Params](#params) +* [Messages](#messages) + * [Unjail](#unjail) +* [BeginBlock](#beginblock) + * [Liveness Tracking](#liveness-tracking) +* [Hooks](#hooks) +* [Events](#events) +* [Staking Tombstone](#staking-tombstone) +* [Parameters](#parameters) +* [CLI](#cli) + * [Query](#query) + * [Transactions](#transactions) + * [gRPC](#grpc) + * [REST](#rest) + + + +# Concepts + +## States + +At any given time, there are any number of validators registered in the state +machine. Each block, the top `MaxValidators` (defined by `x/staking`) validators +who are not jailed become _bonded_, meaning that they may propose and vote on +blocks. Validators who are _bonded_ are _at stake_, meaning that part or all of +their stake and their delegators' stake is at risk if they commit a protocol fault. + +For each of these validators we keep a `ValidatorSigningInfo` record that contains +information partaining to validator's liveness and other infraction related +attributes. + +## Tombstone Caps + +In order to mitigate the impact of initially likely categories of non-malicious +protocol faults, the Cosmos Hub implements for each validator +a _tombstone_ cap, which only allows a validator to be slashed once for a double +sign fault. For example, if you misconfigure your HSM and double-sign a bunch of +old blocks, you'll only be punished for the first double-sign (and then immediately tombstombed). This will still be quite expensive and desirable to avoid, but tombstone caps +somewhat blunt the economic impact of unintentional misconfiguration. + +Liveness faults do not have caps, as they can't stack upon each other. Liveness bugs are "detected" as soon as the infraction occurs, and the validators are immediately put in jail, so it is not possible for them to commit multiple liveness faults without unjailing in between. + +## Infraction Timelines + +To illustrate how the `x/slashing` module handles submitted evidence through +Tendermint consensus, consider the following examples: + +**Definitions**: + +_[_ : timeline start +_]_ : timeline end +_Cn_ : infraction `n` committed +_Dn_ : infraction `n` discovered +_Vb_ : validator bonded +_Vu_ : validator unbonded + +### Single Double Sign Infraction + +\[----------C1----D1,Vu-----\] + +A single infraction is committed then later discovered, at which point the +validator is unbonded and slashed at the full amount for the infraction. + +### Multiple Double Sign Infractions + +\[----------C1--C2---C3---D1,D2,D3Vu-----\] + +Multiple infractions are committed and then later discovered, at which point the +validator is jailed and slashed for only one infraction. Because the validator +is also tombstoned, they can not rejoin the validator set. + + + +# State + +## Signing Info (Liveness) + +Every block includes a set of precommits by the validators for the previous block, +known as the `LastCommitInfo` provided by Tendermint. A `LastCommitInfo` is valid so +long as it contains precommits from +2/3 of total voting power. + +Proposers are incentivized to include precommits from all validators in the Tendermint `LastCommitInfo` +by receiving additional fees proportional to the difference between the voting +power included in the `LastCommitInfo` and +2/3 (see [fee distribution](x/distribution/spec/03_begin_block.md)). + +```go +type LastCommitInfo struct { + Round int32 + Votes []VoteInfo +} +``` + +Validators are penalized for failing to be included in the `LastCommitInfo` for some +number of blocks by being automatically jailed, potentially slashed, and unbonded. + +Information about validator's liveness activity is tracked through `ValidatorSigningInfo`. +It is indexed in the store as follows: + +* ValidatorSigningInfo: `0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)` +* MissedBlocksBitArray: `0x02 | ConsAddrLen (1 byte) | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format) + +The first mapping allows us to easily lookup the recent signing info for a +validator based on the validator's consensus address. + +The second mapping (`MissedBlocksBitArray`) acts +as a bit-array of size `SignedBlocksWindow` that tells us if the validator missed +the block for a given index in the bit-array. The index in the bit-array is given +as little endian uint64. +The result is a `varint` that takes on `0` or `1`, where `0` indicates the +validator did not miss (did sign) the corresponding block, and `1` indicates +they missed the block (did not sign). + +Note that the `MissedBlocksBitArray` is not explicitly initialized up-front. Keys +are added as we progress through the first `SignedBlocksWindow` blocks for a newly +bonded validator. The `SignedBlocksWindow` parameter defines the size +(number of blocks) of the sliding window used to track validator liveness. + +The information stored for tracking validator liveness is as follows: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/slashing/v1beta1/slashing.proto#L12-L33 + +## Params + +The slashing module stores it's params in state with the prefix of `0x00`, +it can be updated with governance or the address with authority. + +* Params: `0x00 | ProtocolBuffer(Params)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc3/proto/cosmos/slashing/v1beta1/slashing.proto#L35-L45 + + + +# Messages + +In this section we describe the processing of messages for the `slashing` module. + +## Unjail + +If a validator was automatically unbonded due to downtime and wishes to come back online & +possibly rejoin the bonded set, it must send `MsgUnjail`: + +```protobuf +// MsgUnjail is an sdk.Msg used for unjailing a jailed validator, thus returning +// them into the bonded validator set, so they can begin receiving provisions +// and rewards again. +message MsgUnjail { + string validator_addr = 1; +} +``` + +Below is a pseudocode of the `MsgSrv/Unjail` RPC: + +```go +unjail(tx MsgUnjail) + validator = getValidator(tx.ValidatorAddr) + if validator == nil + fail with "No validator found" + + if getSelfDelegation(validator) == 0 + fail with "validator must self delegate before unjailing" + + if !validator.Jailed + fail with "Validator not jailed, cannot unjail" + + info = GetValidatorSigningInfo(operator) + if info.Tombstoned + fail with "Tombstoned validator cannot be unjailed" + if block time < info.JailedUntil + fail with "Validator still jailed, cannot unjail until period has expired" + + validator.Jailed = false + setValidator(validator) + + return +``` + +If the validator has enough stake to be in the top `n = MaximumBondedValidators`, it will be automatically rebonded, +and all delegators still delegated to the validator will be rebonded and begin to again collect +provisions and rewards. + + + +# BeginBlock + +## Liveness Tracking + +At the beginning of each block, we update the `ValidatorSigningInfo` for each +validator and check if they've crossed below the liveness threshold over a +sliding window. This sliding window is defined by `SignedBlocksWindow` and the +index in this window is determined by `IndexOffset` found in the validator's +`ValidatorSigningInfo`. For each block processed, the `IndexOffset` is incremented +regardless if the validator signed or not. Once the index is determined, the +`MissedBlocksBitArray` and `MissedBlocksCounter` are updated accordingly. + +Finally, in order to determine if a validator crosses below the liveness threshold, +we fetch the maximum number of blocks missed, `maxMissed`, which is +`SignedBlocksWindow - (MinSignedPerWindow * SignedBlocksWindow)` and the minimum +height at which we can determine liveness, `minHeight`. If the current block is +greater than `minHeight` and the validator's `MissedBlocksCounter` is greater than +`maxMissed`, they will be slashed by `SlashFractionDowntime`, will be jailed +for `DowntimeJailDuration`, and have the following values reset: +`MissedBlocksBitArray`, `MissedBlocksCounter`, and `IndexOffset`. + +**Note**: Liveness slashes do **NOT** lead to a tombstombing. + +```go +height := block.Height + +for vote in block.LastCommitInfo.Votes { + signInfo := GetValidatorSigningInfo(vote.Validator.Address) + + // This is a relative index, so we counts blocks the validator SHOULD have + // signed. We use the 0-value default signing info if not present, except for + // start height. + index := signInfo.IndexOffset % SignedBlocksWindow() + signInfo.IndexOffset++ + + // Update MissedBlocksBitArray and MissedBlocksCounter. The MissedBlocksCounter + // just tracks the sum of MissedBlocksBitArray. That way we avoid needing to + // read/write the whole array each time. + missedPrevious := GetValidatorMissedBlockBitArray(vote.Validator.Address, index) + missed := !signed + + switch { + case !missedPrevious && missed: + // array index has changed from not missed to missed, increment counter + SetValidatorMissedBlockBitArray(vote.Validator.Address, index, true) + signInfo.MissedBlocksCounter++ + + case missedPrevious && !missed: + // array index has changed from missed to not missed, decrement counter + SetValidatorMissedBlockBitArray(vote.Validator.Address, index, false) + signInfo.MissedBlocksCounter-- + + default: + // array index at this index has not changed; no need to update counter + } + + if missed { + // emit events... + } + + minHeight := signInfo.StartHeight + SignedBlocksWindow() + maxMissed := SignedBlocksWindow() - MinSignedPerWindow() + + // If we are past the minimum height and the validator has missed too many + // jail and slash them. + if height > minHeight && signInfo.MissedBlocksCounter > maxMissed { + validator := ValidatorByConsAddr(vote.Validator.Address) + + // emit events... + + // We need to retrieve the stake distribution which signed the block, so we + // subtract ValidatorUpdateDelay from the block height, and subtract an + // additional 1 since this is the LastCommit. + // + // Note, that this CAN result in a negative "distributionHeight" up to + // -ValidatorUpdateDelay-1, i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block. + // That's fine since this is just used to filter unbonding delegations & redelegations. + distributionHeight := height - sdk.ValidatorUpdateDelay - 1 + + Slash(vote.Validator.Address, distributionHeight, vote.Validator.Power, SlashFractionDowntime()) + Jail(vote.Validator.Address) + + signInfo.JailedUntil = block.Time.Add(DowntimeJailDuration()) + + // We need to reset the counter & array so that the validator won't be + // immediately slashed for downtime upon rebonding. + signInfo.MissedBlocksCounter = 0 + signInfo.IndexOffset = 0 + ClearValidatorMissedBlockBitArray(vote.Validator.Address) + } + + SetValidatorSigningInfo(vote.Validator.Address, signInfo) +} +``` + + +# Hooks + +This section contains a description of the module's `hooks`. Hooks are operations that are executed automatically when events are raised. + +## Staking hooks + +The slashing module implements the `StakingHooks` defined in `x/staking` and are used as record-keeping of validators information. During the app initialization, these hooks should be registered in the staking module struct. + +The following hooks impact the slashing state: + +* `AfterValidatorBonded` creates a `ValidatorSigningInfo` instance as described in the following section. +* `AfterValidatorCreated` stores a validator's consensus key. +* `AfterValidatorRemoved` removes a validator's consensus key. + +## Validator Bonded + +Upon successful first-time bonding of a new validator, we create a new `ValidatorSigningInfo` structure for the +now-bonded validator, which `StartHeight` of the current block. + +If the validator was out of the validator set and gets bonded again, its new bonded height is set. + +```go +onValidatorBonded(address sdk.ValAddress) + + signingInfo, found = GetValidatorSigningInfo(address) + if !found { + signingInfo = ValidatorSigningInfo { + StartHeight : CurrentHeight, + IndexOffset : 0, + JailedUntil : time.Unix(0, 0), + Tombstone : false, + MissedBloskCounter : 0 + } else { + signingInfo.StartHeight = CurrentHeight + } + + setValidatorSigningInfo(signingInfo) + } + + return +``` + + +# Events + +The slashing module emits the following events: + +## MsgServer + +### MsgUnjail + +| Type | Attribute Key | Attribute Value | +| ------- | ------------- | ------------------ | +| message | module | slashing | +| message | sender | {validatorAddress} | + +## Keeper + +## BeginBlocker: HandleValidatorSignature + +| Type | Attribute Key | Attribute Value | +| ----- | ------------- | --------------------------- | +| slash | address | {validatorConsensusAddress} | +| slash | power | {validatorPower} | +| slash | reason | {slashReason} | +| slash | jailed [0] | {validatorConsensusAddress} | +| slash | burned coins | {math.Int} | + +* [0] Only included if the validator is jailed. + +| Type | Attribute Key | Attribute Value | +| -------- | ------------- | --------------------------- | +| liveness | address | {validatorConsensusAddress} | +| liveness | missed_blocks | {missedBlocksCounter} | +| liveness | height | {blockHeight} | + +### Slash + +* same as `"slash"` event from `HandleValidatorSignature`, but without the `jailed` attribute. + +### Jail + +| Type | Attribute Key | Attribute Value | +| ----- | ------------- | ------------------ | +| slash | jailed | {validatorAddress} | + + + +# Staking Tombstone + +## Abstract + +In the current implementation of the `slashing` module, when the consensus engine +informs the state machine of a validator's consensus fault, the validator is +partially slashed, and put into a "jail period", a period of time in which they +are not allowed to rejoin the validator set. However, because of the nature of +consensus faults and ABCI, there can be a delay between an infraction occurring, +and evidence of the infraction reaching the state machine (this is one of the +primary reasons for the existence of the unbonding period). + +> Note: The tombstone concept, only applies to faults that have a delay between +> the infraction occurring and evidence reaching the state machine. For example, +> evidence of a validator double signing may take a while to reach the state machine +> due to unpredictable evidence gossip layer delays and the ability of validators to +> selectively reveal double-signatures (e.g. to infrequently-online light clients). +> Liveness slashing, on the other hand, is detected immediately as soon as the +> infraction occurs, and therefore no slashing period is needed. A validator is +> immediately put into jail period, and they cannot commit another liveness fault +> until they unjail. In the future, there may be other types of byzantine faults +> that have delays (for example, submitting evidence of an invalid proposal as a transaction). +> When implemented, it will have to be decided whether these future types of +> byzantine faults will result in a tombstoning (and if not, the slash amounts +> will not be capped by a slashing period). + +In the current system design, once a validator is put in the jail for a consensus +fault, after the `JailPeriod` they are allowed to send a transaction to `unjail` +themselves, and thus rejoin the validator set. + +One of the "design desires" of the `slashing` module is that if multiple +infractions occur before evidence is executed (and a validator is put in jail), +they should only be punished for single worst infraction, but not cumulatively. +For example, if the sequence of events is: + +1. Validator A commits Infraction 1 (worth 30% slash) +2. Validator A commits Infraction 2 (worth 40% slash) +3. Validator A commits Infraction 3 (worth 35% slash) +4. Evidence for Infraction 1 reaches state machine (and validator is put in jail) +5. Evidence for Infraction 2 reaches state machine +6. Evidence for Infraction 3 reaches state machine + +Only Infraction 2 should have its slash take effect, as it is the highest. This +is done, so that in the case of the compromise of a validator's consensus key, +they will only be punished once, even if the hacker double-signs many blocks. +Because, the unjailing has to be done with the validator's operator key, they +have a chance to re-secure their consensus key, and then signal that they are +ready using their operator key. We call this period during which we track only +the max infraction, the "slashing period". + +Once, a validator rejoins by unjailing themselves, we begin a new slashing period; +if they commit a new infraction after unjailing, it gets slashed cumulatively on +top of the worst infraction from the previous slashing period. + +However, while infractions are grouped based off of the slashing periods, because +evidence can be submitted up to an `unbondingPeriod` after the infraction, we +still have to allow for evidence to be submitted for previous slashing periods. +For example, if the sequence of events is: + +1. Validator A commits Infraction 1 (worth 30% slash) +2. Validator A commits Infraction 2 (worth 40% slash) +3. Evidence for Infraction 1 reaches state machine (and Validator A is put in jail) +4. Validator A unjails + +We are now in a new slashing period, however we still have to keep the door open +for the previous infraction, as the evidence for Infraction 2 may still come in. +As the number of slashing periods increase, it creates more complexity as we have +to keep track of the highest infraction amount for every single slashing period. + +> Note: Currently, according to the `slashing` module spec, a new slashing period +> is created every time a validator is unbonded then rebonded. This should probably +> be changed to jailed/unjailed. See issue [#3205](https://github.com/cosmos/cosmos-sdk/issues/3205) +> for further details. For the remainder of this, I will assume that we only start +> a new slashing period when a validator gets unjailed. + +The maximum number of slashing periods is the `len(UnbondingPeriod) / len(JailPeriod)`. +The current defaults in Gaia for the `UnbondingPeriod` and `JailPeriod` are 3 weeks +and 2 days, respectively. This means there could potentially be up to 11 slashing +periods concurrently being tracked per validator. If we set the `JailPeriod >= UnbondingPeriod`, +we only have to track 1 slashing period (i.e not have to track slashing periods). + +Currently, in the jail period implementation, once a validator unjails, all of +their delegators who are delegated to them (haven't unbonded / redelegated away), +stay with them. Given that consensus safety faults are so egregious +(way more so than liveness faults), it is probably prudent to have delegators not +"auto-rebond" to the validator. + +### Proposal: infinite jail + +We propose setting the "jail time" for a +validator who commits a consensus safety fault, to `infinite` (i.e. a tombstone state). +This essentially kicks the validator out of the validator set and does not allow +them to re-enter the validator set. All of their delegators (including the operator themselves) +have to either unbond or redelegate away. The validator operator can create a new +validator if they would like, with a new operator key and consensus key, but they +have to "re-earn" their delegations back. + +Implementing the tombstone system and getting rid of the slashing period tracking +will make the `slashing` module way simpler, especially because we can remove all +of the hooks defined in the `slashing` module consumed by the `staking` module +(the `slashing` module still consumes hooks defined in `staking`). + +### Single slashing amount + +Another optimization that can be made is that if we assume that all ABCI faults +for Tendermint consensus are slashed at the same level, we don't have to keep +track of "max slash". Once an ABCI fault happens, we don't have to worry about +comparing potential future ones to find the max. + +Currently the only Tendermint ABCI fault is: + +* Unjustified precommits (double signs) + +It is currently planned to include the following fault in the near future: + +* Signing a precommit when you're in unbonding phase (needed to make light client bisection safe) + +Given that these faults are both attributable byzantine faults, we will likely +want to slash them equally, and thus we can enact the above change. + +> Note: This change may make sense for current Tendermint consensus, but maybe +> not for a different consensus algorithm or future versions of Tendermint that +> may want to punish at different levels (for example, partial slashing). + + + +# Parameters + +The slashing module contains the following parameters: + +| Key | Type | Example | +| ----------------------- | -------------- | ---------------------- | +| SignedBlocksWindow | string (int64) | "100" | +| MinSignedPerWindow | string (dec) | "0.500000000000000000" | +| DowntimeJailDuration | string (ns) | "600000000000" | +| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" | +| SlashFractionDowntime | string (dec) | "0.010000000000000000" | + + + +# CLI + +A user can query and interact with the `slashing` module using the CLI. + +## Query + +The `query` commands allow users to query `slashing` state. + +```sh +simd query slashing --help +``` + +### params + +The `params` command allows users to query genesis parameters for the slashing module. + +```sh +simd query slashing params [flags] +``` + +Example: + +```sh +simd query slashing params +``` + +Example Output: + +```yml +downtime_jail_duration: 600s +min_signed_per_window: "0.500000000000000000" +signed_blocks_window: "100" +slash_fraction_double_sign: "0.050000000000000000" +slash_fraction_downtime: "0.010000000000000000" +``` + +### signing-info + +The `signing-info` command allows users to query signing-info of the validator using consensus public key. + +```sh +simd query slashing signing-infos [flags] +``` + +Example: + +```sh +simd query slashing signing-info '{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys6jD5B6tPgC8="}' + +``` + +Example Output: + +```yml +address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c +index_offset: "2068" +jailed_until: "1970-01-01T00:00:00Z" +missed_blocks_counter: "0" +start_height: "0" +tombstoned: false +``` + +### signing-infos + +The `signing-infos` command allows users to query signing infos of all validators. + +```sh +simd query slashing signing-infos [flags] +``` + +Example: + +```sh +simd query slashing signing-infos +``` + +Example Output: + +```yml +info: +- address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c + index_offset: "2075" + jailed_until: "1970-01-01T00:00:00Z" + missed_blocks_counter: "0" + start_height: "0" + tombstoned: false +pagination: + next_key: null + total: "0" +``` + +## Transactions + +The `tx` commands allow users to interact with the `slashing` module. + +```bash +simd tx slashing --help +``` + +### unjail + +The `unjail` command allows users to unjail a validator previously jailed for downtime. + +```bash + simd tx slashing unjail --from mykey [flags] +``` + +Example: + +```bash +simd tx slashing unjail --from mykey +``` + +## gRPC + +A user can query the `slashing` module using gRPC endpoints. + +### Params + +The `Params` endpoint allows users to query the parameters of slashing module. + +```sh +cosmos.slashing.v1beta1.Query/Params +``` + +Example: + +```sh +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/Params +``` + +Example Output: + +```json +{ + "params": { + "signedBlocksWindow": "100", + "minSignedPerWindow": "NTAwMDAwMDAwMDAwMDAwMDAw", + "downtimeJailDuration": "600s", + "slashFractionDoubleSign": "NTAwMDAwMDAwMDAwMDAwMDA=", + "slashFractionDowntime": "MTAwMDAwMDAwMDAwMDAwMDA=" + } +} +``` + +### SigningInfo + +The SigningInfo queries the signing info of given cons address. + +```sh +cosmos.slashing.v1beta1.Query/SigningInfo +``` + +Example: + +```sh +grpcurl -plaintext -d '{"cons_address":"cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c"}' localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfo +``` + +Example Output: + +```json +{ + "valSigningInfo": { + "address": "cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c", + "indexOffset": "3493", + "jailedUntil": "1970-01-01T00:00:00Z" + } +} +``` + +### SigningInfos + +The SigningInfos queries signing info of all validators. + +```sh +cosmos.slashing.v1beta1.Query/SigningInfos +``` + +Example: + +```sh +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfos +``` + +Example Output: + +```json +{ + "info": [ + { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "indexOffset": "2467", + "jailedUntil": "1970-01-01T00:00:00Z" + } + ], + "pagination": { + "total": "1" + } +} +``` + +## REST + +A user can query the `slashing` module using REST endpoints. + +### Params + +```sh +/cosmos/slashing/v1beta1/params +``` + +Example: + +```sh +curl "localhost:1317/cosmos/slashing/v1beta1/params" +``` + +Example Output: + +```json +{ + "params": { + "signed_blocks_window": "100", + "min_signed_per_window": "0.500000000000000000", + "downtime_jail_duration": "600s", + "slash_fraction_double_sign": "0.050000000000000000", + "slash_fraction_downtime": "0.010000000000000000" +} +``` + +### signing_info + +```sh +/cosmos/slashing/v1beta1/signing_infos/%s +``` + +Example: + +```sh +curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos/cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c" +``` + +Example Output: + +```json +{ + "val_signing_info": { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "start_height": "0", + "index_offset": "4184", + "jailed_until": "1970-01-01T00:00:00Z", + "tombstoned": false, + "missed_blocks_counter": "0" + } +} +``` + +### signing_infos + +```sh +/cosmos/slashing/v1beta1/signing_infos +``` + +Example: + +```sh +curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos +``` + +Example Output: + +```json +{ + "info": [ + { + "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", + "start_height": "0", + "index_offset": "4169", + "jailed_until": "1970-01-01T00:00:00Z", + "tombstoned": false, + "missed_blocks_counter": "0" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` diff --git a/x/slashing/spec/01_concepts.md b/x/slashing/spec/01_concepts.md deleted file mode 100644 index ea7c6b319bae..000000000000 --- a/x/slashing/spec/01_concepts.md +++ /dev/null @@ -1,57 +0,0 @@ - - -# Concepts - -## States - -At any given time, there are any number of validators registered in the state -machine. Each block, the top `MaxValidators` (defined by `x/staking`) validators -who are not jailed become _bonded_, meaning that they may propose and vote on -blocks. Validators who are _bonded_ are _at stake_, meaning that part or all of -their stake and their delegators' stake is at risk if they commit a protocol fault. - -For each of these validators we keep a `ValidatorSigningInfo` record that contains -information partaining to validator's liveness and other infraction related -attributes. - -## Tombstone Caps - -In order to mitigate the impact of initially likely categories of non-malicious -protocol faults, the Cosmos Hub implements for each validator -a _tombstone_ cap, which only allows a validator to be slashed once for a double -sign fault. For example, if you misconfigure your HSM and double-sign a bunch of -old blocks, you'll only be punished for the first double-sign (and then immediately tombstombed). This will still be quite expensive and desirable to avoid, but tombstone caps -somewhat blunt the economic impact of unintentional misconfiguration. - -Liveness faults do not have caps, as they can't stack upon each other. Liveness bugs are "detected" as soon as the infraction occurs, and the validators are immediately put in jail, so it is not possible for them to commit multiple liveness faults without unjailing in between. - -## Infraction Timelines - -To illustrate how the `x/slashing` module handles submitted evidence through -Tendermint consensus, consider the following examples: - -**Definitions**: - -_[_ : timeline start -_]_ : timeline end -_Cn_ : infraction `n` committed -_Dn_ : infraction `n` discovered -_Vb_ : validator bonded -_Vu_ : validator unbonded - -### Single Double Sign Infraction - -\[----------C1----D1,Vu-----\] - -A single infraction is committed then later discovered, at which point the -validator is unbonded and slashed at the full amount for the infraction. - -### Multiple Double Sign Infractions - -\[----------C1--C2---C3---D1,D2,D3Vu-----\] - -Multiple infractions are committed and then later discovered, at which point the -validator is jailed and slashed for only one infraction. Because the validator -is also tombstoned, they can not rejoin the validator set. diff --git a/x/slashing/spec/02_state.md b/x/slashing/spec/02_state.md deleted file mode 100644 index e07d5fbf88f1..000000000000 --- a/x/slashing/spec/02_state.md +++ /dev/null @@ -1,60 +0,0 @@ - - -# State - -## Signing Info (Liveness) - -Every block includes a set of precommits by the validators for the previous block, -known as the `LastCommitInfo` provided by Tendermint. A `LastCommitInfo` is valid so -long as it contains precommits from +2/3 of total voting power. - -Proposers are incentivized to include precommits from all validators in the Tendermint `LastCommitInfo` -by receiving additional fees proportional to the difference between the voting -power included in the `LastCommitInfo` and +2/3 (see [fee distribution](x/distribution/spec/03_begin_block.md)). - -```go -type LastCommitInfo struct { - Round int32 - Votes []VoteInfo -} -``` - -Validators are penalized for failing to be included in the `LastCommitInfo` for some -number of blocks by being automatically jailed, potentially slashed, and unbonded. - -Information about validator's liveness activity is tracked through `ValidatorSigningInfo`. -It is indexed in the store as follows: - -* ValidatorSigningInfo: `0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)` -* MissedBlocksBitArray: `0x02 | ConsAddrLen (1 byte) | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format) - -The first mapping allows us to easily lookup the recent signing info for a -validator based on the validator's consensus address. - -The second mapping (`MissedBlocksBitArray`) acts -as a bit-array of size `SignedBlocksWindow` that tells us if the validator missed -the block for a given index in the bit-array. The index in the bit-array is given -as little endian uint64. -The result is a `varint` that takes on `0` or `1`, where `0` indicates the -validator did not miss (did sign) the corresponding block, and `1` indicates -they missed the block (did not sign). - -Note that the `MissedBlocksBitArray` is not explicitly initialized up-front. Keys -are added as we progress through the first `SignedBlocksWindow` blocks for a newly -bonded validator. The `SignedBlocksWindow` parameter defines the size -(number of blocks) of the sliding window used to track validator liveness. - -The information stored for tracking validator liveness is as follows: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/slashing/v1beta1/slashing.proto#L12-L33 - -## Params - -The slashing module stores it's params in state with the prefix of `0x00`, -it can be updated with governance or the address with authority. - -* Params: `0x00 | ProtocolBuffer(Params)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0-rc3/proto/cosmos/slashing/v1beta1/slashing.proto#L35-L45 diff --git a/x/slashing/spec/03_messages.md b/x/slashing/spec/03_messages.md deleted file mode 100644 index 8749315794d9..000000000000 --- a/x/slashing/spec/03_messages.md +++ /dev/null @@ -1,51 +0,0 @@ - - -# Messages - -In this section we describe the processing of messages for the `slashing` module. - -## Unjail - -If a validator was automatically unbonded due to downtime and wishes to come back online & -possibly rejoin the bonded set, it must send `MsgUnjail`: - -```protobuf -// MsgUnjail is an sdk.Msg used for unjailing a jailed validator, thus returning -// them into the bonded validator set, so they can begin receiving provisions -// and rewards again. -message MsgUnjail { - string validator_addr = 1; -} -``` - -Below is a pseudocode of the `MsgSrv/Unjail` RPC: - -```go -unjail(tx MsgUnjail) - validator = getValidator(tx.ValidatorAddr) - if validator == nil - fail with "No validator found" - - if getSelfDelegation(validator) == 0 - fail with "validator must self delegate before unjailing" - - if !validator.Jailed - fail with "Validator not jailed, cannot unjail" - - info = GetValidatorSigningInfo(operator) - if info.Tombstoned - fail with "Tombstoned validator cannot be unjailed" - if block time < info.JailedUntil - fail with "Validator still jailed, cannot unjail until period has expired" - - validator.Jailed = false - setValidator(validator) - - return -``` - -If the validator has enough stake to be in the top `n = MaximumBondedValidators`, it will be automatically rebonded, -and all delegators still delegated to the validator will be rebonded and begin to again collect -provisions and rewards. diff --git a/x/slashing/spec/04_begin_block.md b/x/slashing/spec/04_begin_block.md deleted file mode 100644 index 99572c419f20..000000000000 --- a/x/slashing/spec/04_begin_block.md +++ /dev/null @@ -1,98 +0,0 @@ - - -# BeginBlock - -## Liveness Tracking - -At the beginning of each block, we update the `ValidatorSigningInfo` for each -validator and check if they've crossed below the liveness threshold over a -sliding window. This sliding window is defined by `SignedBlocksWindow` and the -index in this window is determined by `IndexOffset` found in the validator's -`ValidatorSigningInfo`. For each block processed, the `IndexOffset` is incremented -regardless if the validator signed or not. Once the index is determined, the -`MissedBlocksBitArray` and `MissedBlocksCounter` are updated accordingly. - -Finally, in order to determine if a validator crosses below the liveness threshold, -we fetch the maximum number of blocks missed, `maxMissed`, which is -`SignedBlocksWindow - (MinSignedPerWindow * SignedBlocksWindow)` and the minimum -height at which we can determine liveness, `minHeight`. If the current block is -greater than `minHeight` and the validator's `MissedBlocksCounter` is greater than -`maxMissed`, they will be slashed by `SlashFractionDowntime`, will be jailed -for `DowntimeJailDuration`, and have the following values reset: -`MissedBlocksBitArray`, `MissedBlocksCounter`, and `IndexOffset`. - -**Note**: Liveness slashes do **NOT** lead to a tombstombing. - -```go -height := block.Height - -for vote in block.LastCommitInfo.Votes { - signInfo := GetValidatorSigningInfo(vote.Validator.Address) - - // This is a relative index, so we counts blocks the validator SHOULD have - // signed. We use the 0-value default signing info if not present, except for - // start height. - index := signInfo.IndexOffset % SignedBlocksWindow() - signInfo.IndexOffset++ - - // Update MissedBlocksBitArray and MissedBlocksCounter. The MissedBlocksCounter - // just tracks the sum of MissedBlocksBitArray. That way we avoid needing to - // read/write the whole array each time. - missedPrevious := GetValidatorMissedBlockBitArray(vote.Validator.Address, index) - missed := !signed - - switch { - case !missedPrevious && missed: - // array index has changed from not missed to missed, increment counter - SetValidatorMissedBlockBitArray(vote.Validator.Address, index, true) - signInfo.MissedBlocksCounter++ - - case missedPrevious && !missed: - // array index has changed from missed to not missed, decrement counter - SetValidatorMissedBlockBitArray(vote.Validator.Address, index, false) - signInfo.MissedBlocksCounter-- - - default: - // array index at this index has not changed; no need to update counter - } - - if missed { - // emit events... - } - - minHeight := signInfo.StartHeight + SignedBlocksWindow() - maxMissed := SignedBlocksWindow() - MinSignedPerWindow() - - // If we are past the minimum height and the validator has missed too many - // jail and slash them. - if height > minHeight && signInfo.MissedBlocksCounter > maxMissed { - validator := ValidatorByConsAddr(vote.Validator.Address) - - // emit events... - - // We need to retrieve the stake distribution which signed the block, so we - // subtract ValidatorUpdateDelay from the block height, and subtract an - // additional 1 since this is the LastCommit. - // - // Note, that this CAN result in a negative "distributionHeight" up to - // -ValidatorUpdateDelay-1, i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block. - // That's fine since this is just used to filter unbonding delegations & redelegations. - distributionHeight := height - sdk.ValidatorUpdateDelay - 1 - - Slash(vote.Validator.Address, distributionHeight, vote.Validator.Power, SlashFractionDowntime()) - Jail(vote.Validator.Address) - - signInfo.JailedUntil = block.Time.Add(DowntimeJailDuration()) - - // We need to reset the counter & array so that the validator won't be - // immediately slashed for downtime upon rebonding. - signInfo.MissedBlocksCounter = 0 - signInfo.IndexOffset = 0 - ClearValidatorMissedBlockBitArray(vote.Validator.Address) - } - - SetValidatorSigningInfo(vote.Validator.Address, signInfo) -} -``` diff --git a/x/slashing/spec/05_hooks.md b/x/slashing/spec/05_hooks.md deleted file mode 100644 index a839689429a8..000000000000 --- a/x/slashing/spec/05_hooks.md +++ /dev/null @@ -1,45 +0,0 @@ - - -# Hooks - -This section contains a description of the module's `hooks`. Hooks are operations that are executed automatically when events are raised. - -## Staking hooks - -The slashing module implements the `StakingHooks` defined in `x/staking` and are used as record-keeping of validators information. During the app initialization, these hooks should be registered in the staking module struct. - -The following hooks impact the slashing state: - -* `AfterValidatorBonded` creates a `ValidatorSigningInfo` instance as described in the following section. -* `AfterValidatorCreated` stores a validator's consensus key. -* `AfterValidatorRemoved` removes a validator's consensus key. - -## Validator Bonded - -Upon successful first-time bonding of a new validator, we create a new `ValidatorSigningInfo` structure for the -now-bonded validator, which `StartHeight` of the current block. - -If the validator was out of the validator set and gets bonded again, its new bonded height is set. - -```go -onValidatorBonded(address sdk.ValAddress) - - signingInfo, found = GetValidatorSigningInfo(address) - if !found { - signingInfo = ValidatorSigningInfo { - StartHeight : CurrentHeight, - IndexOffset : 0, - JailedUntil : time.Unix(0, 0), - Tombstone : false, - MissedBloskCounter : 0 - } else { - signingInfo.StartHeight = CurrentHeight - } - - setValidatorSigningInfo(signingInfo) - } - - return -``` diff --git a/x/slashing/spec/06_events.md b/x/slashing/spec/06_events.md deleted file mode 100644 index e171023ddc10..000000000000 --- a/x/slashing/spec/06_events.md +++ /dev/null @@ -1,46 +0,0 @@ - - -# Events - -The slashing module emits the following events: - -## MsgServer - -### MsgUnjail - -| Type | Attribute Key | Attribute Value | -| ------- | ------------- | ------------------ | -| message | module | slashing | -| message | sender | {validatorAddress} | - -## Keeper - -## BeginBlocker: HandleValidatorSignature - -| Type | Attribute Key | Attribute Value | -| ----- | ------------- | --------------------------- | -| slash | address | {validatorConsensusAddress} | -| slash | power | {validatorPower} | -| slash | reason | {slashReason} | -| slash | jailed [0] | {validatorConsensusAddress} | -| slash | burned coins | {math.Int} | - -* [0] Only included if the validator is jailed. - -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | --------------------------- | -| liveness | address | {validatorConsensusAddress} | -| liveness | missed_blocks | {missedBlocksCounter} | -| liveness | height | {blockHeight} | - -### Slash - -* same as `"slash"` event from `HandleValidatorSignature`, but without the `jailed` attribute. - -### Jail - -| Type | Attribute Key | Attribute Value | -| ----- | ------------- | ------------------ | -| slash | jailed | {validatorAddress} | diff --git a/x/slashing/spec/07_tombstone.md b/x/slashing/spec/07_tombstone.md deleted file mode 100644 index ab06c94563ac..000000000000 --- a/x/slashing/spec/07_tombstone.md +++ /dev/null @@ -1,127 +0,0 @@ - - -# Staking Tombstone - -## Abstract - -In the current implementation of the `slashing` module, when the consensus engine -informs the state machine of a validator's consensus fault, the validator is -partially slashed, and put into a "jail period", a period of time in which they -are not allowed to rejoin the validator set. However, because of the nature of -consensus faults and ABCI, there can be a delay between an infraction occurring, -and evidence of the infraction reaching the state machine (this is one of the -primary reasons for the existence of the unbonding period). - -> Note: The tombstone concept, only applies to faults that have a delay between -> the infraction occurring and evidence reaching the state machine. For example, -> evidence of a validator double signing may take a while to reach the state machine -> due to unpredictable evidence gossip layer delays and the ability of validators to -> selectively reveal double-signatures (e.g. to infrequently-online light clients). -> Liveness slashing, on the other hand, is detected immediately as soon as the -> infraction occurs, and therefore no slashing period is needed. A validator is -> immediately put into jail period, and they cannot commit another liveness fault -> until they unjail. In the future, there may be other types of byzantine faults -> that have delays (for example, submitting evidence of an invalid proposal as a transaction). -> When implemented, it will have to be decided whether these future types of -> byzantine faults will result in a tombstoning (and if not, the slash amounts -> will not be capped by a slashing period). - -In the current system design, once a validator is put in the jail for a consensus -fault, after the `JailPeriod` they are allowed to send a transaction to `unjail` -themselves, and thus rejoin the validator set. - -One of the "design desires" of the `slashing` module is that if multiple -infractions occur before evidence is executed (and a validator is put in jail), -they should only be punished for single worst infraction, but not cumulatively. -For example, if the sequence of events is: - -1. Validator A commits Infraction 1 (worth 30% slash) -2. Validator A commits Infraction 2 (worth 40% slash) -3. Validator A commits Infraction 3 (worth 35% slash) -4. Evidence for Infraction 1 reaches state machine (and validator is put in jail) -5. Evidence for Infraction 2 reaches state machine -6. Evidence for Infraction 3 reaches state machine - -Only Infraction 2 should have its slash take effect, as it is the highest. This -is done, so that in the case of the compromise of a validator's consensus key, -they will only be punished once, even if the hacker double-signs many blocks. -Because, the unjailing has to be done with the validator's operator key, they -have a chance to re-secure their consensus key, and then signal that they are -ready using their operator key. We call this period during which we track only -the max infraction, the "slashing period". - -Once, a validator rejoins by unjailing themselves, we begin a new slashing period; -if they commit a new infraction after unjailing, it gets slashed cumulatively on -top of the worst infraction from the previous slashing period. - -However, while infractions are grouped based off of the slashing periods, because -evidence can be submitted up to an `unbondingPeriod` after the infraction, we -still have to allow for evidence to be submitted for previous slashing periods. -For example, if the sequence of events is: - -1. Validator A commits Infraction 1 (worth 30% slash) -2. Validator A commits Infraction 2 (worth 40% slash) -3. Evidence for Infraction 1 reaches state machine (and Validator A is put in jail) -4. Validator A unjails - -We are now in a new slashing period, however we still have to keep the door open -for the previous infraction, as the evidence for Infraction 2 may still come in. -As the number of slashing periods increase, it creates more complexity as we have -to keep track of the highest infraction amount for every single slashing period. - -> Note: Currently, according to the `slashing` module spec, a new slashing period -> is created every time a validator is unbonded then rebonded. This should probably -> be changed to jailed/unjailed. See issue [#3205](https://github.com/cosmos/cosmos-sdk/issues/3205) -> for further details. For the remainder of this, I will assume that we only start -> a new slashing period when a validator gets unjailed. - -The maximum number of slashing periods is the `len(UnbondingPeriod) / len(JailPeriod)`. -The current defaults in Gaia for the `UnbondingPeriod` and `JailPeriod` are 3 weeks -and 2 days, respectively. This means there could potentially be up to 11 slashing -periods concurrently being tracked per validator. If we set the `JailPeriod >= UnbondingPeriod`, -we only have to track 1 slashing period (i.e not have to track slashing periods). - -Currently, in the jail period implementation, once a validator unjails, all of -their delegators who are delegated to them (haven't unbonded / redelegated away), -stay with them. Given that consensus safety faults are so egregious -(way more so than liveness faults), it is probably prudent to have delegators not -"auto-rebond" to the validator. - -### Proposal: infinite jail - -We propose setting the "jail time" for a -validator who commits a consensus safety fault, to `infinite` (i.e. a tombstone state). -This essentially kicks the validator out of the validator set and does not allow -them to re-enter the validator set. All of their delegators (including the operator themselves) -have to either unbond or redelegate away. The validator operator can create a new -validator if they would like, with a new operator key and consensus key, but they -have to "re-earn" their delegations back. - -Implementing the tombstone system and getting rid of the slashing period tracking -will make the `slashing` module way simpler, especially because we can remove all -of the hooks defined in the `slashing` module consumed by the `staking` module -(the `slashing` module still consumes hooks defined in `staking`). - -### Single slashing amount - -Another optimization that can be made is that if we assume that all ABCI faults -for Tendermint consensus are slashed at the same level, we don't have to keep -track of "max slash". Once an ABCI fault happens, we don't have to worry about -comparing potential future ones to find the max. - -Currently the only Tendermint ABCI fault is: - -* Unjustified precommits (double signs) - -It is currently planned to include the following fault in the near future: - -* Signing a precommit when you're in unbonding phase (needed to make light client bisection safe) - -Given that these faults are both attributable byzantine faults, we will likely -want to slash them equally, and thus we can enact the above change. - -> Note: This change may make sense for current Tendermint consensus, but maybe -> not for a different consensus algorithm or future versions of Tendermint that -> may want to punish at different levels (for example, partial slashing). diff --git a/x/slashing/spec/08_params.md b/x/slashing/spec/08_params.md deleted file mode 100644 index defed189ab9e..000000000000 --- a/x/slashing/spec/08_params.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Parameters - -The slashing module contains the following parameters: - -| Key | Type | Example | -| ----------------------- | -------------- | ---------------------- | -| SignedBlocksWindow | string (int64) | "100" | -| MinSignedPerWindow | string (dec) | "0.500000000000000000" | -| DowntimeJailDuration | string (ns) | "600000000000" | -| SlashFractionDoubleSign | string (dec) | "0.050000000000000000" | -| SlashFractionDowntime | string (dec) | "0.010000000000000000" | diff --git a/x/slashing/spec/09_client.md b/x/slashing/spec/09_client.md deleted file mode 100644 index 11d82961e622..000000000000 --- a/x/slashing/spec/09_client.md +++ /dev/null @@ -1,294 +0,0 @@ - - -# CLI - -A user can query and interact with the `slashing` module using the CLI. - -## Query - -The `query` commands allow users to query `slashing` state. - -```sh -simd query slashing --help -``` - -### params - -The `params` command allows users to query genesis parameters for the slashing module. - -```sh -simd query slashing params [flags] -``` - -Example: - -```sh -simd query slashing params -``` - -Example Output: - -```yml -downtime_jail_duration: 600s -min_signed_per_window: "0.500000000000000000" -signed_blocks_window: "100" -slash_fraction_double_sign: "0.050000000000000000" -slash_fraction_downtime: "0.010000000000000000" -``` - -### signing-info - -The `signing-info` command allows users to query signing-info of the validator using consensus public key. - -```sh -simd query slashing signing-infos [flags] -``` - -Example: - -```sh -simd query slashing signing-info '{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys6jD5B6tPgC8="}' - -``` - -Example Output: - -```yml -address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c -index_offset: "2068" -jailed_until: "1970-01-01T00:00:00Z" -missed_blocks_counter: "0" -start_height: "0" -tombstoned: false -``` - -### signing-infos - -The `signing-infos` command allows users to query signing infos of all validators. - -```sh -simd query slashing signing-infos [flags] -``` - -Example: - -```sh -simd query slashing signing-infos -``` - -Example Output: - -```yml -info: -- address: cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c - index_offset: "2075" - jailed_until: "1970-01-01T00:00:00Z" - missed_blocks_counter: "0" - start_height: "0" - tombstoned: false -pagination: - next_key: null - total: "0" -``` - -## Transactions - -The `tx` commands allow users to interact with the `slashing` module. - -```bash -simd tx slashing --help -``` - -### unjail - -The `unjail` command allows users to unjail a validator previously jailed for downtime. - -```bash - simd tx slashing unjail --from mykey [flags] -``` - -Example: - -```bash -simd tx slashing unjail --from mykey -``` - -## gRPC - -A user can query the `slashing` module using gRPC endpoints. - -### Params - -The `Params` endpoint allows users to query the parameters of slashing module. - -```sh -cosmos.slashing.v1beta1.Query/Params -``` - -Example: - -```sh -grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/Params -``` - -Example Output: - -```json -{ - "params": { - "signedBlocksWindow": "100", - "minSignedPerWindow": "NTAwMDAwMDAwMDAwMDAwMDAw", - "downtimeJailDuration": "600s", - "slashFractionDoubleSign": "NTAwMDAwMDAwMDAwMDAwMDA=", - "slashFractionDowntime": "MTAwMDAwMDAwMDAwMDAwMDA=" - } -} -``` - -### SigningInfo - -The SigningInfo queries the signing info of given cons address. - -```sh -cosmos.slashing.v1beta1.Query/SigningInfo -``` - -Example: - -```sh -grpcurl -plaintext -d '{"cons_address":"cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c"}' localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfo -``` - -Example Output: - -```json -{ - "valSigningInfo": { - "address": "cosmosvalcons1nrqsld3aw6lh6t082frdqc84uwxn0t958c", - "indexOffset": "3493", - "jailedUntil": "1970-01-01T00:00:00Z" - } -} -``` - -### SigningInfos - -The SigningInfos queries signing info of all validators. - -```sh -cosmos.slashing.v1beta1.Query/SigningInfos -``` - -Example: - -```sh -grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/SigningInfos -``` - -Example Output: - -```json -{ - "info": [ - { - "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", - "indexOffset": "2467", - "jailedUntil": "1970-01-01T00:00:00Z" - } - ], - "pagination": { - "total": "1" - } -} -``` - -## REST - -A user can query the `slashing` module using REST endpoints. - -### Params - -```sh -/cosmos/slashing/v1beta1/params -``` - -Example: - -```sh -curl "localhost:1317/cosmos/slashing/v1beta1/params" -``` - -Example Output: - -```json -{ - "params": { - "signed_blocks_window": "100", - "min_signed_per_window": "0.500000000000000000", - "downtime_jail_duration": "600s", - "slash_fraction_double_sign": "0.050000000000000000", - "slash_fraction_downtime": "0.010000000000000000" -} -``` - -### signing_info - -```sh -/cosmos/slashing/v1beta1/signing_infos/%s -``` - -Example: - -```sh -curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos/cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c" -``` - -Example Output: - -```json -{ - "val_signing_info": { - "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", - "start_height": "0", - "index_offset": "4184", - "jailed_until": "1970-01-01T00:00:00Z", - "tombstoned": false, - "missed_blocks_counter": "0" - } -} -``` - -### signing_infos - -```sh -/cosmos/slashing/v1beta1/signing_infos -``` - -Example: - -```sh -curl "localhost:1317/cosmos/slashing/v1beta1/signing_infos -``` - -Example Output: - -```json -{ - "info": [ - { - "address": "cosmosvalcons1nrqslkwd3pz096lh6t082frdqc84uwxn0t958c", - "start_height": "0", - "index_offset": "4169", - "jailed_until": "1970-01-01T00:00:00Z", - "tombstoned": false, - "missed_blocks_counter": "0" - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` diff --git a/x/slashing/spec/README.md b/x/slashing/spec/README.md deleted file mode 100644 index d1988cb964d0..000000000000 --- a/x/slashing/spec/README.md +++ /dev/null @@ -1,49 +0,0 @@ - - -# `x/slashing` - -## Abstract - -This section specifies the slashing module of the Cosmos SDK, which implements functionality -first outlined in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) in June 2016. - -The slashing module enables Cosmos SDK-based blockchains to disincentivize any attributable action -by a protocol-recognized actor with value at stake by penalizing them ("slashing"). - -Penalties may include, but are not limited to: - -* Burning some amount of their stake -* Removing their ability to vote on future blocks for a period of time. - -This module will be used by the Cosmos Hub, the first hub in the Cosmos ecosystem. - -## Contents - -1. **[Concepts](01_concepts.md)** - * [States](01_concepts.md#states) - * [Tombstone Caps](01_concepts.md#tombstone-caps) - * [ASCII timelines](01_concepts.md#ascii-timelines) -2. **[State](02_state.md)** - * [Signing Info](02_state.md#signing-info) -3. **[Messages](03_messages.md)** - * [Unjail](03_messages.md#unjail) -4. **[Begin-Block](04_begin_block.md)** - * [Evidence handling](04_begin_block.md#evidence-handling) - * [Uptime tracking](04_begin_block.md#uptime-tracking) -5. **[05_hooks.md](05_hooks.md)** - * [Hooks](05_hooks.md#hooks) -6. **[Events](06_events.md)** - * [BeginBlocker](06_events.md#beginblocker) - * [Handlers](06_events.md#handlers) -7. **[Staking Tombstone](07_tombstone.md)** - * [Abstract](07_tombstone.md#abstract) -8. **[Parameters](08_params.md)** -9. **[Client](09_client.md)** - * [CLI](09_client.md#cli) - * [gRPC](09_client.md#grpc) - * [REST](09_client.md#rest) diff --git a/x/staking/README.md b/x/staking/README.md index 5736c3914943..64afbc412572 100644 --- a/x/staking/README.md +++ b/x/staking/README.md @@ -1,7 +1,2971 @@ -# Staking +# `x/staking` -* [Staking](spec/README.md) - Proof-of-Stake layer for public blockchains. +## Abstract + +This paper specifies the Staking module of the Cosmos SDK that was first +described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) +in June 2016. + +The module enables Cosmos SDK-based blockchain to support an advanced +Proof-of-Stake (PoS) system. In this system, holders of the native staking token of +the chain can become validators and can delegate tokens to validators, +ultimately determining the effective validator set for the system. + +This module is used in the Cosmos Hub, the first Hub in the Cosmos +network. + +## Contents + +* [State](#state) + * [Pool](#pool) + * [LastTotalPower](#lasttotalpower) + * [Params](#params) + * [Validator](#validator) + * [Delegation](#delegation) + * [UnbondingDelegation](#unbondingdelegation) + * [Redelegation](#redelegation) + * [Queues](#queues) + * [HistoricalInfo](#historicalinfo) +* [State Transitions](#state-transitions) + * [Validators](#validators) + * [Delegations](#delegations) + * [Slashing](#slashing) + * [How Shares are calculated](#how-shares-are-calculated) +* [Messages](#messages) + * [MsgCreateValidator](#msgcreatevalidator) + * [MsgEditValidator](#msgeditvalidator) + * [MsgDelegate](#msgdelegate) + * [MsgUndelegate](#msgundelegate) + * [MsgCancelUnbondingDelegation](#msgcancelunbondingdelegation) + * [MsgBeginRedelegate](#msgbeginredelegate) + * [MsgUpdateParams](#msgupdateparams) +* [Begin-Block](#begin-block) + * [Historical Info Tracking](#historical-info-tracking) +* [End-Block](#end-block) + * [Validator Set Changes](#validator-set-changes) +* [Hooks](#hooks) +* [Events](#events) + * [EndBlocker](#endblocker) + * [Msg's](#msgs) +* [Parameters](#parameters) +* [Client](#client) + * [CLI](#cli) + * [gRPC](#grpc) + * [REST](#rest) + + + +# State + +## Pool + +Pool is used for tracking bonded and not-bonded token supply of the bond denomination. + +## LastTotalPower + +LastTotalPower tracks the total amounts of bonded tokens recorded during the previous end block. +Store entries prefixed with "Last" must remain unchanged until EndBlock. + +* LastTotalPower: `0x12 -> ProtocolBuffer(math.Int)` + +## Params + +The staking module stores it's params in state with the prefix of `0x51`, +it can be updated with governance or the address with authority. + +* Params: `0x51 | ProtocolBuffer(Params)` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L285-L306 + +## Validator + +Validators can have one of three statuses + +* `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn + rewards. They can receive delegations. +* `Bonded`: Once the validator receives sufficient bonded tokens they automtically join the + active set during [`EndBlock`](./05_end_block.md#validator-set-changes) and their status is updated to `Bonded`. + They are signing blocks and receiving rewards. They can receive further delegations. + They can be slashed for misbehavior. Delegators to this validator who unbond their delegation + must wait the duration of the UnbondingTime, a chain-specific param, during which time + they are still slashable for offences of the source validator if those offences were committed + during the period of time that the tokens were bonded. +* `Unbonding`: When a validator leaves the active set, either by choice or due to slashing, jailing or + tombstoning, an unbonding of all their delegations begins. All delegations must then wait the UnbondingTime + before their tokens are moved to their accounts from the `BondedPool`. + +Validators objects should be primarily stored and accessed by the +`OperatorAddr`, an SDK validator address for the operator of the validator. Two +additional indices are maintained per validator object in order to fulfill +required lookups for slashing and validator-set updates. A third special index +(`LastValidatorPower`) is also maintained which however remains constant +throughout each block, unlike the first two indices which mirror the validator +records within a block. + +* Validators: `0x21 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(validator)` +* ValidatorsByConsAddr: `0x22 | ConsAddrLen (1 byte) | ConsAddr -> OperatorAddr` +* ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddrLen (1 byte) | OperatorAddr -> OperatorAddr` +* LastValidatorsPower: `0x11 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(ConsensusPower)` + +`Validators` is the primary index - it ensures that each operator can have only one +associated validator, where the public key of that validator can change in the +future. Delegators can refer to the immutable operator of the validator, without +concern for the changing public key. + +`ValidatorByConsAddr` is an additional index that enables lookups for slashing. +When Tendermint reports evidence, it provides the validator address, so this +map is needed to find the operator. Note that the `ConsAddr` corresponds to the +address which can be derived from the validator's `ConsPubKey`. + +`ValidatorsByPower` is an additional index that provides a sorted list of +potential validators to quickly determine the current active set. Here +ConsensusPower is validator.Tokens/10^6 by default. Note that all validators +where `Jailed` is true are not stored within this index. + +`LastValidatorsPower` is a special index that provides a historical list of the +last-block's bonded validators. This index remains constant during a block but +is updated during the validator set update process which takes place in [`EndBlock`](./05_end_block.md). + +Each validator's state is stored in a `Validator` struct: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L78-L127 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L24-L76 + +## Delegation + +Delegations are identified by combining `DelegatorAddr` (the address of the delegator) +with the `ValidatorAddr` Delegators are indexed in the store as follows: + +* Delegation: `0x31 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(delegation)` + +Stake holders may delegate coins to validators; under this circumstance their +funds are held in a `Delegation` data structure. It is owned by one +delegator, and is associated with the shares for one validator. The sender of +the transaction is the owner of the bond. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L187-L205 + +### Delegator Shares + +When one Delegates tokens to a Validator they are issued a number of delegator shares based on a +dynamic exchange rate, calculated as follows from the total number of tokens delegated to the +validator and the number of shares issued so far: + +`Shares per Token = validator.TotalShares() / validator.Tokens()` + +Only the number of shares received is stored on the DelegationEntry. When a delegator then +Undelegates, the token amount they receive is calculated from the number of shares they currently +hold and the inverse exchange rate: + +`Tokens per Share = validator.Tokens() / validatorShares()` + +These `Shares` are simply an accounting mechanism. They are not a fungible asset. The reason for +this mechanism is to simplify the accounting around slashing. Rather than iteratively slashing the +tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, +effectively reducing the value of each issued delegator share. + +## UnbondingDelegation + +Shares in a `Delegation` can be unbonded, but they must for some time exist as +an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is +detected. + +`UnbondingDelegation` are indexed in the store as: + +* UnbondingDelegation: `0x32 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)` +* UnbondingDelegationsFromValidator: `0x33 | ValidatorAddrLen (1 byte) | ValidatorAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` + +The first map here is used in queries, to lookup all unbonding delegations for +a given delegator, while the second map is used in slashing, to lookup all +unbonding delegations associated with a given validator that need to be +slashed. + +A UnbondingDelegation object is created every time an unbonding is initiated. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L207-L220 + +## Redelegation + +The bonded tokens worth of a `Delegation` may be instantly redelegated from a +source validator to a different validator (destination validator). However when +this occurs they must be tracked in a `Redelegation` object, whereby their +shares can be slashed if their tokens have contributed to a Byzantine fault +committed by the source validator. + +`Redelegation` are indexed in the store as: + +* Redelegations: `0x34 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)` +* RedelegationsBySrc: `0x35 | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` +* RedelegationsByDst: `0x36 | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` + +The first map here is used for queries, to lookup all redelegations for a given +delegator. The second map is used for slashing based on the `ValidatorSrcAddr`, +while the third map is for slashing based on the `ValidatorDstAddr`. + +A redelegation object is created every time a redelegation occurs. To prevent +"redelegation hopping" redelegations may not occur under the situation that: + +* the (re)delegator already has another immature redelegation in progress + with a destination to a validator (let's call it `Validator X`) +* and, the (re)delegator is attempting to create a _new_ redelegation + where the source validator for this new redelegation is `Validator X`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L245-L283 + +## Queues + +All queues objects are sorted by timestamp. The time used within any queue is +first rounded to the nearest nanosecond then sorted. The sortable time format +used is a slight modification of the RFC3339Nano and uses the format string +`"2006-01-02T15:04:05.000000000"`. Notably this format: + +* right pads all zeros +* drops the time zone info (uses UTC) + +In all cases, the stored timestamp represents the maturation time of the queue +element. + +### UnbondingDelegationQueue + +For the purpose of tracking progress of unbonding delegations the unbonding +delegations queue is kept. + +* UnbondingDelegation: `0x41 | format(time) -> []DVPair` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L151-L161 + +### RedelegationQueue + +For the purpose of tracking progress of redelegations the redelegation queue is +kept. + +* RedelegationQueue: `0x42 | format(time) -> []DVVTriplet` + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L168-L179 + +### ValidatorQueue + +For the purpose of tracking progress of unbonding validators the validator +queue is kept. + +* ValidatorQueueTime: `0x43 | format(time) -> []sdk.ValAddress` + +The stored object as each key is an array of validator operator addresses from +which the validator object can be accessed. Typically it is expected that only +a single validator record will be associated with a given timestamp however it is possible +that multiple validators exist in the queue at the same location. + +## HistoricalInfo + +HistoricalInfo objects are stored and pruned at each block such that the staking keeper persists +the `n` most recent historical info defined by staking module parameter: `HistoricalEntries`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L15-L22 + +At each BeginBlock, the staking keeper will persist the current Header and the Validators that committed +the current block in a `HistoricalInfo` object. The Validators are sorted on their address to ensure that +they are in a determisnistic order. +The oldest HistoricalEntries will be pruned to ensure that there only exist the parameter-defined number of +historical entries. + + + +# State Transitions + +This document describes the state transition operations pertaining to: + +1. [Validators](./02_state_transitions.md#validators) +2. [Delegations](./02_state_transitions.md#delegations) +3. [Slashing](./02_state_transitions.md#slashing) + +## Validators + +State transitions in validators are performed on every [`EndBlock`](./05_end_block.md#validator-set-changes) +in order to check for changes in the active `ValidatorSet`. + +A validator can be `Unbonded`, `Unbonding` or `Bonded`. `Unbonded` +and `Unbonding` are collectively called `Not Bonded`. A validator can move +directly between all the states, except for from `Bonded` to `Unbonded`. + +### Not bonded to Bonded + +The following transition occurs when a validator's ranking in the `ValidatorPowerIndex` surpasses +that of the `LastValidator`. + +* set `validator.Status` to `Bonded` +* send the `validator.Tokens` from the `NotBondedTokens` to the `BondedPool` `ModuleAccount` +* delete the existing record from `ValidatorByPowerIndex` +* add a new updated record to the `ValidatorByPowerIndex` +* update the `Validator` object for this validator +* if it exists, delete any `ValidatorQueue` record for this validator + +### Bonded to Unbonding + +When a validator begins the unbonding process the following operations occur: + +* send the `validator.Tokens` from the `BondedPool` to the `NotBondedTokens` `ModuleAccount` +* set `validator.Status` to `Unbonding` +* delete the existing record from `ValidatorByPowerIndex` +* add a new updated record to the `ValidatorByPowerIndex` +* update the `Validator` object for this validator +* insert a new record into the `ValidatorQueue` for this validator + +### Unbonding to Unbonded + +A validator moves from unbonding to unbonded when the `ValidatorQueue` object +moves from bonded to unbonded + +* update the `Validator` object for this validator +* set `validator.Status` to `Unbonded` + +### Jail/Unjail + +when a validator is jailed it is effectively removed from the Tendermint set. +this process may be also be reversed. the following operations occur: + +* set `Validator.Jailed` and update object +* if jailed delete record from `ValidatorByPowerIndex` +* if unjailed add record to `ValidatorByPowerIndex` + +Jailed validators are not present in any of the following stores: + +* the power store (from consensus power to address) + +## Delegations + +### Delegate + +When a delegation occurs both the validator and the delegation objects are affected + +* determine the delegators shares based on tokens delegated and the validator's exchange rate +* remove tokens from the sending account +* add shares the delegation object or add them to a created validator object +* add new delegator shares and update the `Validator` object +* transfer the `delegation.Amount` from the delegator's account to the `BondedPool` or the `NotBondedPool` `ModuleAccount` depending if the `validator.Status` is `Bonded` or not +* delete the existing record from `ValidatorByPowerIndex` +* add an new updated record to the `ValidatorByPowerIndex` + +### Begin Unbonding + +As a part of the Undelegate and Complete Unbonding state transitions Unbond +Delegation may be called. + +* subtract the unbonded shares from delegator +* add the unbonded tokens to an `UnbondingDelegation` Entry +* update the delegation or remove the delegation if there are no more shares +* if the delegation is the operator of the validator and no more shares exist then trigger a jail validator +* update the validator with removed the delegator shares and associated coins +* if the validator state is `Bonded`, transfer the `Coins` worth of the unbonded + shares from the `BondedPool` to the `NotBondedPool` `ModuleAccount` +* remove the validator if it is unbonded and there are no more delegation shares. + +### Cancel an `UnbondingDelegation` Entry + +When a `cancel unbond delegation` occurs both the `validator`, the `delegation` and an `UnbondingDelegationQueue` state will be updated. + +* if cancel unbonding delegation amount equals to the `UnbondingDelegation` entry `balance`, then the `UnbondingDelegation` entry deleted from `UnbondingDelegationQueue`. +* if the `cancel unbonding delegation amount is less than the `UnbondingDelegation` entry balance, then the `UnbondingDelegation` entry will be updated with new balance in the `UnbondingDelegationQueue`. +* cancel `amount` is [Delegated](02_state_transitions.md#delegations) back to the original `validator`. + +### Complete Unbonding + +For undelegations which do not complete immediately, the following operations +occur when the unbonding delegation queue element matures: + +* remove the entry from the `UnbondingDelegation` object +* transfer the tokens from the `NotBondedPool` `ModuleAccount` to the delegator `Account` + +### Begin Redelegation + +Redelegations affect the delegation, source and destination validators. + +* perform an `unbond` delegation from the source validator to retrieve the tokens worth of the unbonded shares +* using the unbonded tokens, `Delegate` them to the destination validator +* if the `sourceValidator.Status` is `Bonded`, and the `destinationValidator` is not, + transfer the newly delegated tokens from the `BondedPool` to the `NotBondedPool` `ModuleAccount` +* otherwise, if the `sourceValidator.Status` is not `Bonded`, and the `destinationValidator` + is `Bonded`, transfer the newly delegated tokens from the `NotBondedPool` to the `BondedPool` `ModuleAccount` +* record the token amount in an new entry in the relevant `Redelegation` + +From when a redelegation begins until it completes, the delegator is in a state of "pseudo-unbonding", and can still be +slashed for infractions that occured before the redelegation began. + +### Complete Redelegation + +When a redelegations complete the following occurs: + +* remove the entry from the `Redelegation` object + +## Slashing + +### Slash Validator + +When a Validator is slashed, the following occurs: + +* The total `slashAmount` is calculated as the `slashFactor` (a chain parameter) \* `TokensFromConsensusPower`, + the total number of tokens bonded to the validator at the time of the infraction. +* Every unbonding delegation and pseudo-unbonding redelegation such that the infraction occured before the unbonding or + redelegation began from the validator are slashed by the `slashFactor` percentage of the initialBalance. +* Each amount slashed from redelegations and unbonding delegations is subtracted from the + total slash amount. +* The `remaingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or + `NonBondedPool` depending on the validator's status. This reduces the total supply of tokens. + +In the case of a slash due to any infraction that requires evidence to submitted (for example double-sign), the slash +occurs at the block where the evidence is included, not at the block where the infraction occured. +Put otherwise, validators are not slashed retroactively, only when they are caught. + +### Slash Unbonding Delegation + +When a validator is slashed, so are those unbonding delegations from the validator that began unbonding +after the time of the infraction. Every entry in every unbonding delegation from the validator +is slashed by `slashFactor`. The amount slashed is calculated from the `InitialBalance` of the +delegation and is capped to prevent a resulting negative balance. Completed (or mature) unbondings are not slashed. + +### Slash Redelegation + +When a validator is slashed, so are all redelegations from the validator that began after the +infraction. Redelegations are slashed by `slashFactor`. +Redelegations that began before the infraction are not slashed. +The amount slashed is calculated from the `InitialBalance` of the delegation and is capped to +prevent a resulting negative balance. +Mature redelegations (that have completed pseudo-unbonding) are not slashed. + +## How Shares are calculated + +At any given point in time, each validator has a number of tokens, `T`, and has a number of shares issued, `S`. +Each delegator, `i`, holds a number of shares, `S_i`. +The number of tokens is the sum of all tokens delegated to the validator, plus the rewards, minus the slashes. + +The delegator is entitled to a portion of the underlying tokens proportional to their proportion of shares. +So delegator `i` is entitled to `T * S_i / S` of the validator's tokens. + +When a delegator delegates new tokens to the validator, they receive a number of shares proportional to their contribution. +So when delegator `j` delegates `T_j` tokens, they receive `S_j = S * T_j / T` shares. +The total number of tokens is now `T + T_j`, and the total number of shares is `S + S_j`. +`j`s proportion of the shares is the same as their proportion of the total tokens contributed: `(S + S_j) / S = (T + T_j) / T`. + +A special case is the initial delegation, when `T = 0` and `S = 0`, so `T_j / T` is undefined. +For the initial delegation, delegator `j` who delegates `T_j` tokens receive `S_j = T_j` shares. +So a validator that hasn't received any rewards and has not been slashed will have `T = S`. + + + +# Messages + +In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state_transitions.md) section. + +## MsgCreateValidator + +A validator is created using the `MsgCreateValidator` message. +The validator must be created with an initial delegation from the operator. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L18-L19 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L43-L65 + +This message is expected to fail if: + +* another validator with this operator address is already registered +* another validator with this pubkey is already registered +* the initial self-delegation tokens are of a denom not specified as the bonding denom +* the commission parameters are faulty, namely: + * `MaxRate` is either > 1 or < 0 + * the initial `Rate` is either negative or > `MaxRate` + * the initial `MaxChangeRate` is either negative or > `MaxRate` +* the description fields are too large + +This message creates and stores the `Validator` object at appropriate indexes. +Additionally a self-delegation is made with the initial tokens delegation +tokens `Delegation`. The validator always starts as unbonded but may be bonded +in the first end-block. + +## MsgEditValidator + +The `Description`, `CommissionRate` of a validator can be updated using the +`MsgEditValidator` message. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L21-L22 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L70-L88 + +This message is expected to fail if: + +* the initial `CommissionRate` is either negative or > `MaxRate` +* the `CommissionRate` has already been updated within the previous 24 hours +* the `CommissionRate` is > `MaxChangeRate` +* the description fields are too large + +This message stores the updated `Validator` object. + +## MsgDelegate + +Within this message the delegator provides coins, and in return receives +some amount of their validator's (newly created) delegator-shares that are +assigned to `Delegation.Shares`. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L24-L26 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L93-L104 + +This message is expected to fail if: + +* the validator does not exist +* the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` +* the exchange rate is invalid, meaning the validator has no tokens (due to slashing) but there are outstanding shares +* the amount delegated is less than the minimum allowed delegation + +If an existing `Delegation` object for provided addresses does not already +exist then it is created as part of this message otherwise the existing +`Delegation` is updated to include the newly received shares. + +The delegator receives newly minted shares at the current exchange rate. +The exchange rate is the number of existing shares in the validator divided by +the number of currently delegated tokens. + +The validator is updated in the `ValidatorByPower` index, and the delegation is +tracked in validator object in the `Validators` index. + +It is possible to delegate to a jailed validator, the only difference being it +will not be added to the power index until it is unjailed. + +![Delegation sequence](../../../docs/uml/svg/delegation_sequence.svg) + +## MsgUndelegate + +The `MsgUndelegate` message allows delegators to undelegate their tokens from +validator. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L32-L34 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L128-L139 + +This message returns a response containing the completion time of the undelegation: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L128-L144 + +This message is expected to fail if: + +* the delegation doesn't exist +* the validator doesn't exist +* the delegation has less shares than the ones worth of `Amount` +* existing `UnbondingDelegation` has maximum entries as defined by `params.MaxEntries` +* the `Amount` has a denomination different than one defined by `params.BondDenom` + +When this message is processed the following actions occur: + +* validator's `DelegatorShares` and the delegation's `Shares` are both reduced by the message `SharesAmount` +* calculate the token worth of the shares remove that amount tokens held within the validator +* with those removed tokens, if the validator is: + * `Bonded` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares. + * `Unbonding` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). + * `Unbonded` - then send the coins the message `DelegatorAddr` +* if there are no more `Shares` in the delegation, then the delegation object is removed from the store + * under this situation if the delegation is the validator's self-delegation then also jail the validator. + +![Unbond sequence](../../../docs/uml/svg/unbond_sequence.svg) + +## MsgCancelUnbondingDelegation + +The `MsgCancelUnbondingDelegation` message allows delegators to cancel the `unbondingDelegation` entry and deleagate back to a previous validator. + ++++ hhttps://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L36-L40 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L146-L165 + +This message is expected to fail if: + +* the `unbondingDelegation` entry is already processed. +* the `cancel unbonding delegation` amount is greater than the `unbondingDelegation` entry balance. +* the `cancel unbonding delegation` height doesn't exists in the `unbondingDelegationQueue` of the delegator. + +When this message is processed the following actions occur: + +* if the `unbondingDelegation` Entry balance is zero + * in this condition `unbondingDelegation` entry will be removed from `unbondingDelegationQueue`. + * otherwise `unbondingDelegationQueue` will be updated with new `unbondingDelegation` entry balance and initial balance +* the validator's `DelegatorShares` and the delegation's `Shares` are both increased by the message `Amount`. + +## MsgBeginRedelegate + +The redelegation command allows delegators to instantly switch validators. Once +the unbonding period has passed, the redelegation is automatically completed in +the EndBlocker. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L28-L30 + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L109-L121 + +This message returns a response containing the completion time of the redelegation: + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L123-L126 + +This message is expected to fail if: + +* the delegation doesn't exist +* the source or destination validators don't exist +* the delegation has less shares than the ones worth of `Amount` +* the source validator has a receiving redelegation which is not matured (aka. the redelegation may be transitive) +* existing `Redelegation` has maximum entries as defined by `params.MaxEntries` +* the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` + +When this message is processed the following actions occur: + +* the source validator's `DelegatorShares` and the delegations `Shares` are both reduced by the message `SharesAmount` +* calculate the token worth of the shares remove that amount tokens held within the source validator. +* if the source validator is: + * `Bonded` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares (this may be effectively reversed in the next step however). + * `Unbonding` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). + * `Unbonded` - no action required in this step +* Delegate the token worth to the destination validator, possibly moving tokens back to the bonded state. +* if there are no more `Shares` in the source delegation, then the source delegation object is removed from the store + * under this situation if the delegation is the validator's self-delegation then also jail the validator. + +![Begin redelegation sequence](../../../docs/uml/svg/begin_redelegation_sequence.svg) + + +## MsgUpdateParams + +The `MsgUpdateParams` update the staking module parameters. +The params are updated through a governance proposal where the signer is the gov module account address. + ++++ https://github.com/cosmos/cosmos-sdk/blob/e412ce990251768579d49947991be76a87564f7d/proto/cosmos/staking/v1beta1/tx.proto#L172-L190 + +The message handling can fail if: + +* signer is not the authority defined in the staking keeper (usually the gov module account). + + + +# Begin-Block + +Each abci begin block call, the historical info will get stored and pruned +according to the `HistoricalEntries` parameter. + +## Historical Info Tracking + +If the `HistoricalEntries` parameter is 0, then the `BeginBlock` performs a no-op. + +Otherwise, the latest historical info is stored under the key `historicalInfoKey|height`, while any entries older than `height - HistoricalEntries` is deleted. +In most cases, this results in a single entry being pruned per block. +However, if the parameter `HistoricalEntries` has changed to a lower value there will be multiple entries in the store that must be pruned. + + + +# End-Block + +Each abci end block call, the operations to update queues and validator set +changes are specified to execute. + +## Validator Set Changes + +The staking validator set is updated during this process by state transitions +that run at the end of every block. As a part of this process any updated +validators are also returned back to Tendermint for inclusion in the Tendermint +validator set which is responsible for validating Tendermint messages at the +consensus layer. Operations are as following: + +* the new validator set is taken as the top `params.MaxValidators` number of + validators retrieved from the `ValidatorsByPower` index +* the previous validator set is compared with the new validator set: + * missing validators begin unbonding and their `Tokens` are transferred from the + `BondedPool` to the `NotBondedPool` `ModuleAccount` + * new validators are instantly bonded and their `Tokens` are transferred from the + `NotBondedPool` to the `BondedPool` `ModuleAccount` + +In all cases, any validators leaving or entering the bonded validator set or +changing balances and staying within the bonded validator set incur an update +message reporting their new consensus power which is passed back to Tendermint. + +The `LastTotalPower` and `LastValidatorsPower` hold the state of the total power +and validator power from the end of the last block, and are used to check for +changes that have occured in `ValidatorsByPower` and the total new power, which +is calculated during `EndBlock`. + +## Queues + +Within staking, certain state-transitions are not instantaneous but take place +over a duration of time (typically the unbonding period). When these +transitions are mature certain operations must take place in order to complete +the state operation. This is achieved through the use of queues which are +checked/processed at the end of each block. + +### Unbonding Validators + +When a validator is kicked out of the bonded validator set (either through +being jailed, or not having sufficient bonded tokens) it begins the unbonding +process along with all its delegations begin unbonding (while still being +delegated to this validator). At this point the validator is said to be an +"unbonding validator", whereby it will mature to become an "unbonded validator" +after the unbonding period has passed. + +Each block the validator queue is to be checked for mature unbonding validators +(namely with a completion time <= current time and completion height <= current +block height). At this point any mature validators which do not have any +delegations remaining are deleted from state. For all other mature unbonding +validators that still have remaining delegations, the `validator.Status` is +switched from `types.Unbonding` to +`types.Unbonded`. + +### Unbonding Delegations + +Complete the unbonding of all mature `UnbondingDelegations.Entries` within the +`UnbondingDelegations` queue with the following procedure: + +* transfer the balance coins to the delegator's wallet address +* remove the mature entry from `UnbondingDelegation.Entries` +* remove the `UnbondingDelegation` object from the store if there are no + remaining entries. + +### Redelegations + +Complete the unbonding of all mature `Redelegation.Entries` within the +`Redelegations` queue with the following procedure: + +* remove the mature entry from `Redelegation.Entries` +* remove the `Redelegation` object from the store if there are no + remaining entries. + + + +# Hooks + +Other modules may register operations to execute when a certain event has +occurred within staking. These events can be registered to execute either +right `Before` or `After` the staking event (as per the hook name). The +following hooks can registered with staking: + +* `AfterValidatorCreated(Context, ValAddress) error` + * called when a validator is created +* `BeforeValidatorModified(Context, ValAddress) error` + * called when a validator's state is changed +* `AfterValidatorRemoved(Context, ConsAddress, ValAddress) error` + * called when a validator is deleted +* `AfterValidatorBonded(Context, ConsAddress, ValAddress) error` + * called when a validator is bonded +* `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress) error` + * called when a validator begins unbonding +* `BeforeDelegationCreated(Context, AccAddress, ValAddress) error` + * called when a delegation is created +* `BeforeDelegationSharesModified(Context, AccAddress, ValAddress) error` + * called when a delegation's shares are modified +* `AfterDelegationModified(Context, AccAddress, ValAddress) error` + * called when a delegation is created or modified +* `BeforeDelegationRemoved(Context, AccAddress, ValAddress) error` + * called when a delegation is removed + + + +# Events + +The staking module emits the following events: + +## EndBlocker + +| Type | Attribute Key | Attribute Value | +| --------------------- | --------------------- | ------------------------- | +| complete_unbonding | amount | {totalUnbondingAmount} | +| complete_unbonding | validator | {validatorAddress} | +| complete_unbonding | delegator | {delegatorAddress} | +| complete_redelegation | amount | {totalRedelegationAmount} | +| complete_redelegation | source_validator | {srcValidatorAddress} | +| complete_redelegation | destination_validator | {dstValidatorAddress} | +| complete_redelegation | delegator | {delegatorAddress} | + +## Msg's + +### MsgCreateValidator + +| Type | Attribute Key | Attribute Value | +| ---------------- | ------------- | ------------------ | +| create_validator | validator | {validatorAddress} | +| create_validator | amount | {delegationAmount} | +| message | module | staking | +| message | action | create_validator | +| message | sender | {senderAddress} | + +### MsgEditValidator + +| Type | Attribute Key | Attribute Value | +| -------------- | ------------------- | ------------------- | +| edit_validator | commission_rate | {commissionRate} | +| edit_validator | min_self_delegation | {minSelfDelegation} | +| message | module | staking | +| message | action | edit_validator | +| message | sender | {senderAddress} | + +### MsgDelegate + +| Type | Attribute Key | Attribute Value | +| -------- | ------------- | ------------------ | +| delegate | validator | {validatorAddress} | +| delegate | amount | {delegationAmount} | +| message | module | staking | +| message | action | delegate | +| message | sender | {senderAddress} | + +### MsgUndelegate + +| Type | Attribute Key | Attribute Value | +| ------- | ------------------- | ------------------ | +| unbond | validator | {validatorAddress} | +| unbond | amount | {unbondAmount} | +| unbond | completion_time [0] | {completionTime} | +| message | module | staking | +| message | action | begin_unbonding | +| message | sender | {senderAddress} | + +* [0] Time is formatted in the RFC3339 standard + +### MsgCancelUnbondingDelegation + +| Type | Attribute Key | Attribute Value | +| ----------------------------- | ------------------ | ------------------------------------| +| cancel_unbonding_delegation | validator | {validatorAddress} | +| cancel_unbonding_delegation | delegator | {delegatorAddress} | +| cancel_unbonding_delegation | amount | {cancelUnbondingDelegationAmount} | +| cancel_unbonding_delegation | creation_height | {unbondingCreationHeight} | +| message | module | staking | +| message | action | cancel_unbond | +| message | sender | {senderAddress} | + +### MsgBeginRedelegate + +| Type | Attribute Key | Attribute Value | +| ---------- | --------------------- | --------------------- | +| redelegate | source_validator | {srcValidatorAddress} | +| redelegate | destination_validator | {dstValidatorAddress} | +| redelegate | amount | {unbondAmount} | +| redelegate | completion_time [0] | {completionTime} | +| message | module | staking | +| message | action | begin_redelegate | +| message | sender | {senderAddress} | + +* [0] Time is formatted in the RFC3339 standard + + + +# Parameters + +The staking module contains the following parameters: + +| Key | Type | Example | +|-------------------|------------------|------------------------| +| UnbondingTime | string (time ns) | "259200000000000" | +| MaxValidators | uint16 | 100 | +| KeyMaxEntries | uint16 | 7 | +| HistoricalEntries | uint16 | 3 | +| BondDenom | string | "stake" | +| MinCommissionRate | string | "0.000000000000000000" | + + + +# Client + +## CLI + +A user can query and interact with the `staking` module using the CLI. + +### Query + +The `query` commands allows users to query `staking` state. + +```bash +simd query staking --help +``` + +#### delegation + +The `delegation` command allows users to query delegations for an individual delegator on an individual validator. + +Usage: + +```bash +simd query staking delegation [delegator-addr] [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +balance: + amount: "10000000000" + denom: stake +delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### delegations + +The `delegations` command allows users to query delegations for an individual delegator on all validators. + +Usage: + +```bash +simd query staking delegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +delegation_responses: +- balance: + amount: "10000000000" + denom: stake + delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- balance: + amount: "10000000000" + denom: stake + delegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + shares: "10000000000.000000000000000000" + validator_address: cosmosvaloper1x20lytyf6zkcrv5edpkfkn8sz578qg5sqfyqnp +pagination: + next_key: null + total: "0" +``` + +#### delegations-to + +The `delegations-to` command allows users to query delegations on an individual validator. + +Usage: + +```bash +simd query staking delegations-to [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking delegations-to cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +- balance: + amount: "504000000" + denom: stake + delegation: + delegator_address: cosmos1q2qwwynhv8kh3lu5fkeex4awau9x8fwt45f5cp + shares: "504000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- balance: + amount: "78125000000" + denom: uixo + delegation: + delegator_address: cosmos1qvppl3479hw4clahe0kwdlfvf8uvjtcd99m2ca + shares: "78125000000.000000000000000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +pagination: + next_key: null + total: "0" +``` + +#### historical-info + +The `historical-info` command allows users to query historical information at given height. + +Usage: + +```bash +simd query staking historical-info [height] [flags] +``` + +Example: + +```bash +simd query staking historical-info 10 +``` + +Example Output: + +```bash +header: + app_hash: Lbx8cXpI868wz8sgp4qPYVrlaKjevR5WP/IjUxwp3oo= + chain_id: testnet + consensus_hash: BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8= + data_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + evidence_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + height: "10" + last_block_id: + hash: RFbkpu6pWfSThXxKKl6EZVDnBSm16+U0l0xVjTX08Fk= + part_set_header: + hash: vpIvXD4rxD5GM4MXGz0Sad9I7//iVYLzZsEU4BVgWIU= + total: 1 + last_commit_hash: Ne4uXyx4QtNp4Zx89kf9UK7oG9QVbdB6e7ZwZkhy8K0= + last_results_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= + next_validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= + proposer_address: mMEP2c2IRPLr99LedSRtBg9eONM= + time: "2021-10-01T06:00:49.785790894Z" + validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= + version: + app: "0" + block: "11" +valset: +- commission: + commission_rates: + max_change_rate: "0.010000000000000000" + max_rate: "0.200000000000000000" + rate: "0.100000000000000000" + update_time: "2021-10-01T05:52:50.380144238Z" + consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8= + delegator_shares: "10000000.000000000000000000" + description: + details: "" + identity: "" + moniker: myvalidator + security_contact: "" + website: "" + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc + status: BOND_STATUS_BONDED + tokens: "10000000" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +``` + +#### params + +The `params` command allows users to query values set as staking parameters. + +Usage: + +```bash +simd query staking params [flags] +``` + +Example: + +```bash +simd query staking params +``` + +Example Output: + +```bash +bond_denom: stake +historical_entries: 10000 +max_entries: 7 +max_validators: 50 +unbonding_time: 1814400s +``` + +#### pool + +The `pool` command allows users to query values for amounts stored in the staking pool. + +Usage: + +```bash +simd q staking pool [flags] +``` + +Example: + +```bash +simd q staking pool +``` + +Example Output: + +```bash +bonded_tokens: "10000000" +not_bonded_tokens: "0" +``` + +#### redelegation + +The `redelegation` command allows users to query a redelegation record based on delegator and a source and destination validator address. + +Usage: + +```bash +simd query staking redelegation [delegator-addr] [src-validator-addr] [dst-validator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +pagination: null +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm + validator_src_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm +``` + +#### redelegations + +The `redelegations` command allows users to query all redelegation records for an individual delegator. + +Usage: + +```bash +simd query staking redelegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp +- entries: + - balance: "562770000000" + redelegation_entry: + completion_time: "2021-10-25T21:42:07.336911677Z" + creation_height: 2.39735e+06 + initial_balance: "562770000000" + shares_dst: "562770000000.000000000000000000" + redelegation: + delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp +``` + +#### redelegations-from + +The `redelegations-from` command allows users to query delegations that are redelegating _from_ a validator. + +Usage: + +```bash +simd query staking redelegations-from [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking redelegations-from cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +redelegation_responses: +- entries: + - balance: "50000000" + redelegation_entry: + completion_time: "2021-10-24T20:33:21.960084845Z" + creation_height: 2.382847e+06 + initial_balance: "50000000" + shares_dst: "50000000.000000000000000000" + - balance: "5000000000" + redelegation_entry: + completion_time: "2021-10-25T21:33:54.446846862Z" + creation_height: 2.397271e+06 + initial_balance: "5000000000" + shares_dst: "5000000000.000000000000000000" + redelegation: + delegator_address: cosmos1pm6e78p4pgn0da365plzl4t56pxy8hwtqp2mph + entries: null + validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm + validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +- entries: + - balance: "221000000" + redelegation_entry: + completion_time: "2021-10-05T21:05:45.669420544Z" + creation_height: 2.120693e+06 + initial_balance: "221000000" + shares_dst: "221000000.000000000000000000" + redelegation: + delegator_address: cosmos1zqv8qxy2zgn4c58fz8jt8jmhs3d0attcussrf6 + entries: null + validator_dst_address: cosmosvaloper10mseqwnwtjaqfrwwp2nyrruwmjp6u5jhah4c3y + validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy +``` + +#### unbonding-delegation + +The `unbonding-delegation` command allows users to query unbonding delegations for an individual delegator on an individual validator. + +Usage: + +```bash +simd query staking unbonding-delegation [delegator-addr] [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +entries: +- balance: "52000000" + completion_time: "2021-11-02T11:35:55.391594709Z" + creation_height: "55078" + initial_balance: "52000000" +validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### unbonding-delegations + +The `unbonding-delegations` command allows users to query all unbonding-delegations records for one delegator. + +Usage: + +```bash +simd query staking unbonding-delegations [delegator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +unbonding_responses: +- delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p + entries: + - balance: "52000000" + completion_time: "2021-11-02T11:35:55.391594709Z" + creation_height: "55078" + initial_balance: "52000000" + validator_address: cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa + +``` + +#### unbonding-delegations-from + +The `unbonding-delegations-from` command allows users to query delegations that are unbonding _from_ a validator. + +Usage: + +```bash +simd query staking unbonding-delegations-from [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking unbonding-delegations-from cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +pagination: + next_key: null + total: "0" +unbonding_responses: +- delegator_address: cosmos1qqq9txnw4c77sdvzx0tkedsafl5s3vk7hn53fn + entries: + - balance: "150000000" + completion_time: "2021-11-01T21:41:13.098141574Z" + creation_height: "46823" + initial_balance: "150000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +- delegator_address: cosmos1peteje73eklqau66mr7h7rmewmt2vt99y24f5z + entries: + - balance: "24000000" + completion_time: "2021-10-31T02:57:18.192280361Z" + creation_height: "21516" + initial_balance: "24000000" + validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +#### validator + +The `validator` command allows users to query details about an individual validator. + +Usage: + +```bash +simd query staking validator [validator-addr] [flags] +``` + +Example: + +```bash +simd query staking validator cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +``` + +Example Output: + +```bash +commission: + commission_rates: + max_change_rate: "0.020000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-01T19:24:52.663191049Z" +consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= +delegator_shares: "32948270000.000000000000000000" +description: + details: Witval is the validator arm from Vitwit. Vitwit is into software consulting + and services business since 2015. We are working closely with Cosmos ecosystem + since 2018. We are also building tools for the ecosystem, Aneka is our explorer + for the cosmos ecosystem. + identity: 51468B615127273A + moniker: Witval + security_contact: "" + website: "" +jailed: false +min_self_delegation: "1" +operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +status: BOND_STATUS_BONDED +tokens: "32948270000" +unbonding_height: "0" +unbonding_time: "1970-01-01T00:00:00Z" +``` + +#### validators + +The `validators` command allows users to query details about all validators on a network. + +Usage: + +```bash +simd query staking validators [flags] +``` + +Example: + +```bash +simd query staking validators +``` + +Example Output: + +```bash +pagination: + next_key: FPTi7TKAjN63QqZh+BaXn6gBmD5/ + total: "0" +validators: +commission: + commission_rates: + max_change_rate: "0.020000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-01T19:24:52.663191049Z" +consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= +delegator_shares: "32948270000.000000000000000000" +description: + details: Witval is the validator arm from Vitwit. Vitwit is into software consulting + and services business since 2015. We are working closely with Cosmos ecosystem + since 2018. We are also building tools for the ecosystem, Aneka is our explorer + for the cosmos ecosystem. + identity: 51468B615127273A + moniker: Witval + security_contact: "" + website: "" + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj + status: BOND_STATUS_BONDED + tokens: "32948270000" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +- commission: + commission_rates: + max_change_rate: "0.100000000000000000" + max_rate: "0.200000000000000000" + rate: "0.050000000000000000" + update_time: "2021-10-04T18:02:21.446645619Z" + consensus_pubkey: + '@type': /cosmos.crypto.ed25519.PubKey + key: GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA= + delegator_shares: "559343421.000000000000000000" + description: + details: Noderunners is a professional validator in POS networks. We have a huge + node running experience, reliable soft and hardware. Our commissions are always + low, our support to delegators is always full. Stake with us and start receiving + your Cosmos rewards now! + identity: 812E82D12FEA3493 + moniker: Noderunners + security_contact: info@noderunners.biz + website: http://noderunners.biz + jailed: false + min_self_delegation: "1" + operator_address: cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7 + status: BOND_STATUS_BONDED + tokens: "559343421" + unbonding_height: "0" + unbonding_time: "1970-01-01T00:00:00Z" +``` + +### Transactions + +The `tx` commands allows users to interact with the `staking` module. + +```bash +simd tx staking --help +``` + +#### create-validator + +The command `create-validator` allows users to create new validator initialized with a self-delegation to it. + +Usage: + +```bash +simd tx staking create-validator [flags] +``` + +Example: + +```bash +simd tx staking create-validator \ + --amount=1000000stake \ + --pubkey=$(simd tendermint show-validator) \ + --moniker="my-moniker" \ + --website="https://myweb.site" \ + --details="description of your validator" \ + --chain-id="name_of_chain_id" \ + --commission-rate="0.10" \ + --commission-max-rate="0.20" \ + --commission-max-change-rate="0.01" \ + --min-self-delegation="1" \ + --gas="auto" \ + --gas-adjustment="1.2" \ + --gas-prices="0.025stake" \ + --from=mykey +``` + +#### delegate + +The command `delegate` allows users to delegate liquid tokens to a validator. + +Usage: + +```bash +simd tx staking delegate [validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey +``` + +#### edit-validator + +The command `edit-validator` allows users to edit an existing validator account. + +Usage: + +```bash +simd tx staking edit-validator [flags] +``` + +Example: + +```bash +simd tx staking edit-validator --moniker "new_moniker_name" --website "new_webiste_url" --from mykey +``` + +#### redelegate + +The command `redelegate` allows users to redelegate illiquid tokens from one validator to another. + +Usage: + +```bash +simd tx staking redelegate [src-validator-addr] [dst-validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey +``` + +#### unbond + +The command `unbond` allows users to unbond shares from a validator. + +Usage: + +```bash +simd tx staking unbond [validator-addr] [amount] [flags] +``` + +Example: + +```bash +simd tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey +``` + +#### cancel unbond + +The command `cancel-unbond` allow users to cancel the unbonding delegation entry and delegate back to the original validator. + +Usage: + +```bash +simd tx staking cancel-unbond [validator-addr] [amount] [creation-height] +``` + +Example: + +```bash +simd tx staking cancel-unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake 123123 --from mykey +``` + + +## gRPC + +A user can query the `staking` module using gRPC endpoints. + +### Validators + +The `Validators` endpoint queries all validators that match the given status. + +```bash +cosmos.staking.v1beta1.Query/Validators +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Validators +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, + "status": "BOND_STATUS_BONDED", + "tokens": "10000000", + "delegatorShares": "10000000000000000000000000", + "description": { + "moniker": "myvalidator" + }, + "unbondingTime": "1970-01-01T00:00:00Z", + "commission": { + "commissionRates": { + "rate": "100000000000000000", + "maxRate": "200000000000000000", + "maxChangeRate": "10000000000000000" + }, + "updateTime": "2021-10-01T05:52:50.380144238Z" + }, + "minSelfDelegation": "1" + } + ], + "pagination": { + "total": "1" + } +} +``` + +### Validator + +The `Validator` endpoint queries validator information for given validator address. + +```bash +cosmos.staking.v1beta1.Query/Validator +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Validator +``` + +Example Output: + +```bash +{ + "validator": { + "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, + "status": "BOND_STATUS_BONDED", + "tokens": "10000000", + "delegatorShares": "10000000000000000000000000", + "description": { + "moniker": "myvalidator" + }, + "unbondingTime": "1970-01-01T00:00:00Z", + "commission": { + "commissionRates": { + "rate": "100000000000000000", + "maxRate": "200000000000000000", + "maxChangeRate": "10000000000000000" + }, + "updateTime": "2021-10-01T05:52:50.380144238Z" + }, + "minSelfDelegation": "1" + } +} +``` + +### ValidatorDelegations + +The `ValidatorDelegations` endpoint queries delegate information for given validator. + +```bash +cosmos.staking.v1beta1.Query/ValidatorDelegations +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/ValidatorDelegations +``` + +Example Output: + +```bash +{ + "delegationResponses": [ + { + "delegation": { + "delegatorAddress": "cosmos1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgy3ua5t", + "validatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "shares": "10000000000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "10000000" + } + } + ], + "pagination": { + "total": "1" + } +} +``` + +### ValidatorUnbondingDelegations + +The `ValidatorUnbondingDelegations` endpoint queries delegate information for given validator. + +```bash +cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations +``` + +Example: + +```bash +grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1z3pzzw84d6xn00pw9dy3yapqypfde7vg6965fy", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "25325", + "completion_time": "2021-10-31T09:24:36.797320636Z", + "initial_balance": "20000000", + "balance": "20000000" + } + ] + }, + { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "13100", + "completion_time": "2021-10-30T12:53:02.272266791Z", + "initial_balance": "1000000", + "balance": "1000000" + } + ] + }, + ], + "pagination": { + "next_key": null, + "total": "8" + } +} +``` + +### Delegation + +The `Delegation` endpoint queries delegate information for given validator delegator pair. + +```bash +cosmos.staking.v1beta1.Query/Delegation +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Delegation +``` + +Example Output: + +```bash +{ + "delegation_response": + { + "delegation": + { + "delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "shares":"25083119936.000000000000000000" + }, + "balance": + { + "denom":"stake", + "amount":"25083119936" + } + } +} +``` + +### UnbondingDelegation + +The `UnbondingDelegation` endpoint queries unbonding information for given validator delegator. + +```bash +cosmos.staking.v1beta1.Query/UnbondingDelegation +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/UnbondingDelegation +``` + +Example Output: + +```bash +{ + "unbond": { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", + "entries": [ + { + "creation_height": "136984", + "completion_time": "2021-11-08T05:38:47.505593891Z", + "initial_balance": "400000000", + "balance": "400000000" + }, + { + "creation_height": "137005", + "completion_time": "2021-11-08T05:40:53.526196312Z", + "initial_balance": "385000000", + "balance": "385000000" + } + ] + } +} +``` + +### DelegatorDelegations + +The `DelegatorDelegations` endpoint queries all delegations of a given delegator address. + +```bash +cosmos.staking.v1beta1.Query/DelegatorDelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorDelegations +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + {"delegation":{"delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77","validator_address":"cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8","shares":"25083339023.000000000000000000"},"balance":{"denom":"stake","amount":"25083339023"}} + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorUnbondingDelegations + +The `DelegatorUnbondingDelegations` endpoint queries all unbonding delegations of a given delegator address. + +```bash +cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", + "validator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9uxyejze", + "entries": [ + { + "creation_height": "136984", + "completion_time": "2021-11-08T05:38:47.505593891Z", + "initial_balance": "400000000", + "balance": "400000000" + }, + { + "creation_height": "137005", + "completion_time": "2021-11-08T05:40:53.526196312Z", + "initial_balance": "385000000", + "balance": "385000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### Redelegations + +The `Redelegations` endpoint queries redelegations of given address. + +```bash +cosmos.staking.v1beta1.Query/Redelegations +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", "src_validator_addr" : "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", "dst_validator_addr" : "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/Redelegations +``` + +Example Output: + +```bash +{ + "redelegation_responses": [ + { + "redelegation": { + "delegator_address": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", + "validator_src_address": "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", + "validator_dst_address": "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse", + "entries": null + }, + "entries": [ + { + "redelegation_entry": { + "creation_height": 135932, + "completion_time": "2021-11-08T03:52:55.299147901Z", + "initial_balance": "2900000", + "shares_dst": "2900000.000000000000000000" + }, + "balance": "2900000" + } + ] + } + ], + "pagination": null +} +``` + +### DelegatorValidators + +The `DelegatorValidators` endpoint queries all validators information for given delegator. + +```bash +cosmos.staking.v1beta1.Query/DelegatorValidators +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidators +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "347260647559", + "delegator_shares": "347260647559.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "security_contact": "", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.150000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidator + +The `DelegatorValidator` endpoint queries validator information for given delegator validator + +```bash +cosmos.staking.v1beta1.Query/DelegatorValidator +``` + +Example: + +```bash +grpcurl -plaintext \ +-d '{"delegator_addr": "cosmos1eh5mwu044gd5ntkkc2xgfg8247mgc56f3n8rr7", "validator_addr": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8"}' \ +localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidator +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "347262754841", + "delegator_shares": "347262754841.000000000000000000", + "description": { + "moniker": "BouBouNode", + "identity": "", + "website": "https://boubounode.com", + "security_contact": "", + "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.061000000000000000", + "max_rate": "0.300000000000000000", + "max_change_rate": "0.150000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } +} +``` + +### HistoricalInfo + +```bash +cosmos.staking.v1beta1.Query/HistoricalInfo +``` + +Example: + +```bash +grpcurl -plaintext -d '{"height" : 1}' localhost:9090 cosmos.staking.v1beta1.Query/HistoricalInfo +``` + +Example Output: + +```bash +{ + "hist": { + "header": { + "version": { + "block": "11", + "app": "0" + }, + "chain_id": "simd-1", + "height": "140142", + "time": "2021-10-11T10:56:29.720079569Z", + "last_block_id": { + "hash": "9gri/4LLJUBFqioQ3NzZIP9/7YHR9QqaM6B2aJNQA7o=", + "part_set_header": { + "total": 1, + "hash": "Hk1+C864uQkl9+I6Zn7IurBZBKUevqlVtU7VqaZl1tc=" + } + }, + "last_commit_hash": "VxrcS27GtvGruS3I9+AlpT7udxIT1F0OrRklrVFSSKc=", + "data_hash": "80BjOrqNYUOkTnmgWyz9AQ8n7SoEmPVi4QmAe8RbQBY=", + "validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", + "next_validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", + "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", + "app_hash": "ZZaxnSY3E6Ex5Bvkm+RigYCK82g8SSUL53NymPITeOE=", + "last_results_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "proposer_address": "aH6dO428B+ItuoqPq70efFHrSMY=" + }, + "valset": [ + { + "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1426045203613", + "delegator_shares": "1426045203613.000000000000000000", + "description": { + "moniker": "SG-1", + "identity": "48608633F99D1B60", + "website": "https://sg-1.online", + "security_contact": "", + "details": "SG-1 - your favorite validator on Witval. We offer 100% Soft Slash protection." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.037500000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + } + ] + } +} + +``` + +### Pool + +The `Pool` endpoint queries the pool information. + +```bash +cosmos.staking.v1beta1.Query/Pool +``` + +Example: + +```bash +grpcurl -plaintext -d localhost:9090 cosmos.staking.v1beta1.Query/Pool +``` + +Example Output: + +```bash +{ + "pool": { + "not_bonded_tokens": "369054400189", + "bonded_tokens": "15657192425623" + } +} +``` + +### Params + +The `Params` endpoint queries the pool information. + +```bash +cosmos.staking.v1beta1.Query/Params +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Params +``` + +Example Output: + +```bash +{ + "params": { + "unbondingTime": "1814400s", + "maxValidators": 100, + "maxEntries": 7, + "historicalEntries": 10000, + "bondDenom": "stake" + } +} +``` + +## REST + +A user can query the `staking` module using REST endpoints. + +### DelegatorDelegations + +The `DelegtaorDelegations` REST endpoint queries all delegations of a given delegator address. + +```bash +/cosmos/staking/v1beta1/delegations/{delegatorAddr} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/delegations/cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + { + "delegation": { + "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", + "validator_address": "cosmosvaloper1quqxfrxkycr0uzt4yk0d57tcq3zk7srm7sm6r8", + "shares": "256250000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "256250000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", + "validator_address": "cosmosvaloper194v8uwee2fvs2s8fa5k7j03ktwc87h5ym39jfv", + "shares": "255150000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "255150000" + } + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` + +### Redelegations + +The `Redelegations` REST endpoint queries redelegations of given address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/redelegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e/redelegations?srcValidatorAddr=cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf&dstValidatorAddr=cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "redelegation_responses": [ + { + "redelegation": { + "delegator_address": "cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e", + "validator_src_address": "cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf", + "validator_dst_address": "cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4", + "entries": null + }, + "entries": [ + { + "redelegation_entry": { + "creation_height": 151523, + "completion_time": "2021-11-09T06:03:25.640682116Z", + "initial_balance": "200000000", + "shares_dst": "200000000.000000000000000000" + }, + "balance": "200000000" + } + ] + } + ], + "pagination": null +} +``` + +### DelegatorUnbondingDelegations + +The `DelegatorUnbondingDelegations` REST endpoint queries all unbonding delegations of a given delegator address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/unbonding_delegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll/unbonding_delegations" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll", + "validator_address": "cosmosvaloper1e7mvqlz50ch6gw4yjfemsc069wfre4qwmw53kq", + "entries": [ + { + "creation_height": "2442278", + "completion_time": "2021-10-12T10:59:03.797335857Z", + "initial_balance": "50000000000", + "balance": "50000000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidators + +The `DelegatorValidators` REST endpoint queries all validators information for given delegator address. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "21592843799", + "delegator_shares": "21592843799.000000000000000000", + "description": { + "moniker": "jabbey", + "identity": "", + "website": "https://twitter.com/JoeAbbey", + "security_contact": "", + "details": "just another dad in the cosmos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-09T19:03:54.984821705Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": null, + "total": "1" + } +} +``` + +### DelegatorValidator + +The `DelegatorValidator` REST endpoint queries validator information for given delegator validator pair. + +```bash +/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators/{validatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators/cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "21592843799", + "delegator_shares": "21592843799.000000000000000000", + "description": { + "moniker": "jabbey", + "identity": "", + "website": "https://twitter.com/JoeAbbey", + "security_contact": "", + "details": "just another dad in the cosmos" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.100000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-09T19:03:54.984821705Z" + }, + "min_self_delegation": "1" + } +} +``` + +### HistoricalInfo + +The `HistoricalInfo` REST endpoint queries the historical information for given height. + +```bash +/cosmos/staking/v1beta1/historical_info/{height} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/historical_info/153332" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "hist": { + "header": { + "version": { + "block": "11", + "app": "0" + }, + "chain_id": "cosmos-1", + "height": "153332", + "time": "2021-10-12T09:05:35.062230221Z", + "last_block_id": { + "hash": "NX8HevR5khb7H6NGKva+jVz7cyf0skF1CrcY9A0s+d8=", + "part_set_header": { + "total": 1, + "hash": "zLQ2FiKM5tooL3BInt+VVfgzjlBXfq0Hc8Iux/xrhdg=" + } + }, + "last_commit_hash": "P6IJrK8vSqU3dGEyRHnAFocoDGja0bn9euLuy09s350=", + "data_hash": "eUd+6acHWrNXYju8Js449RJ99lOYOs16KpqQl4SMrEM=", + "validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", + "next_validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", + "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", + "app_hash": "fuELArKRK+CptnZ8tu54h6xEleSWenHNmqC84W866fU=", + "last_results_hash": "p/BPexV4LxAzlVcPRvW+lomgXb6Yze8YLIQUo/4Kdgc=", + "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", + "proposer_address": "G0MeY8xQx7ooOsni8KE/3R/Ib3Q=" + }, + "valset": [ + { + "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1416521659632", + "delegator_shares": "1416521659632.000000000000000000", + "description": { + "moniker": "SG-1", + "identity": "48608633F99D1B60", + "website": "https://sg-1.online", + "security_contact": "", + "details": "SG-1 - your favorite validator on cosmos. We offer 100% Soft Slash protection." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.037500000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.030000000000000000" + }, + "update_time": "2021-10-01T15:00:00Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "uExZyjNLtr2+FFIhNDAMcQ8+yTrqE7ygYTsI7khkA5Y=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "1348298958808", + "delegator_shares": "1348298958808.000000000000000000", + "description": { + "moniker": "Cosmostation", + "identity": "AE4C403A6E7AA1AC", + "website": "https://www.cosmostation.io", + "security_contact": "admin@stamper.network", + "details": "Cosmostation validator node. Delegate your tokens and Start Earning Staking Rewards" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "1.000000000000000000", + "max_change_rate": "0.200000000000000000" + }, + "update_time": "2021-10-01T15:06:38.821314287Z" + }, + "min_self_delegation": "1" + } + ] + } +} +``` + +### Parameters + +The `Parameters` REST endpoint queries the staking parameters. + +```bash +/cosmos/staking/v1beta1/params +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/params" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "params": { + "unbonding_time": "2419200s", + "max_validators": 100, + "max_entries": 7, + "historical_entries": 10000, + "bond_denom": "stake" + } +} +``` + +### Pool + +The `Pool` REST endpoint queries the pool information. + +```bash +/cosmos/staking/v1beta1/pool +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/pool" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "pool": { + "not_bonded_tokens": "432805737458", + "bonded_tokens": "15783637712645" + } +} +``` + +### Validators + +The `Validators` REST endpoint queries all validators that match the given status. + +```bash +/cosmos/staking/v1beta1/validators +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validators": [ + { + "operator_address": "cosmosvaloper1q3jsx9dpfhtyqqgetwpe5tmk8f0ms5qywje8tw", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "N7BPyek2aKuNZ0N/8YsrqSDhGZmgVaYUBuddY8pwKaE=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "383301887799", + "delegator_shares": "383301887799.000000000000000000", + "description": { + "moniker": "SmartNodes", + "identity": "D372724899D1EDC8", + "website": "https://smartnodes.co", + "security_contact": "", + "details": "Earn Rewards with Crypto Staking & Node Deployment" + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-01T15:51:31.596618510Z" + }, + "min_self_delegation": "1" + }, + { + "operator_address": "cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA=" + }, + "jailed": false, + "status": "BOND_STATUS_UNBONDING", + "tokens": "1017819654", + "delegator_shares": "1017819654.000000000000000000", + "description": { + "moniker": "Noderunners", + "identity": "812E82D12FEA3493", + "website": "http://noderunners.biz", + "security_contact": "info@noderunners.biz", + "details": "Noderunners is a professional validator in POS networks. We have a huge node running experience, reliable soft and hardware. Our commissions are always low, our support to delegators is always full. Stake with us and start receiving your cosmos rewards now!" + }, + "unbonding_height": "147302", + "unbonding_time": "2021-11-08T22:58:53.718662452Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.100000000000000000" + }, + "update_time": "2021-10-04T18:02:21.446645619Z" + }, + "min_self_delegation": "1" + } + ], + "pagination": { + "next_key": "FONDBFkE4tEEf7yxWWKOD49jC2NK", + "total": "2" + } +} +``` + +### Validator + +The `Validator` REST endpoint queries validator information for given validator address. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "validator": { + "operator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "consensus_pubkey": { + "@type": "/cosmos.crypto.ed25519.PubKey", + "key": "sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc=" + }, + "jailed": false, + "status": "BOND_STATUS_BONDED", + "tokens": "33027900000", + "delegator_shares": "33027900000.000000000000000000", + "description": { + "moniker": "Witval", + "identity": "51468B615127273A", + "website": "", + "security_contact": "", + "details": "Witval is the validator arm from Vitwit. Vitwit is into software consulting and services business since 2015. We are working closely with Cosmos ecosystem since 2018. We are also building tools for the ecosystem, Aneka is our explorer for the cosmos ecosystem." + }, + "unbonding_height": "0", + "unbonding_time": "1970-01-01T00:00:00Z", + "commission": { + "commission_rates": { + "rate": "0.050000000000000000", + "max_rate": "0.200000000000000000", + "max_change_rate": "0.020000000000000000" + }, + "update_time": "2021-10-01T19:24:52.663191049Z" + }, + "min_self_delegation": "1" + } +} +``` + +### ValidatorDelegations + +The `ValidatorDelegations` REST endpoint queries delegate information for given validator. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_responses": [ + { + "delegation": { + "delegator_address": "cosmos190g5j8aszqhvtg7cprmev8xcxs6csra7xnk3n3", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "31000000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "31000000000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1ddle9tczl87gsvmeva3c48nenyng4n56qwq4ee", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "628470000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "628470000" + } + }, + { + "delegation": { + "delegator_address": "cosmos10fdvkczl76m040smd33lh9xn9j0cf26kk4s2nw", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "838120000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "838120000" + } + }, + { + "delegation": { + "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "500000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "500000000" + } + }, + { + "delegation": { + "delegator_address": "cosmos16msryt3fqlxtvsy8u5ay7wv2p8mglfg9hrek2e", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "61310000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "61310000" + } + } + ], + "pagination": { + "next_key": null, + "total": "5" + } +} +``` + +### Delegation + +The `Delegation` REST endpoint queries delegate information for given validator delegator pair. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr} +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations/cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "delegation_response": { + "delegation": { + "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", + "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", + "shares": "500000000.000000000000000000" + }, + "balance": { + "denom": "stake", + "amount": "500000000" + } + } +} +``` + +### UnbondingDelegation + +The `UnbondingDelegation` REST endpoint queries unbonding information for given validator delegator pair. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr}/unbonding_delegation +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/delegations/cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm/unbonding_delegation" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbond": { + "delegator_address": "cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "153687", + "completion_time": "2021-11-09T09:41:18.352401903Z", + "initial_balance": "525111", + "balance": "525111" + } + ] + } +} +``` + +### ValidatorUnbondingDelegations + +The `ValidatorUnbondingDelegations` REST endpoint queries unbonding delegations of a validator. + +```bash +/cosmos/staking/v1beta1/validators/{validatorAddr}/unbonding_delegations +``` + +Example: + +```bash +curl -X GET \ +"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/unbonding_delegations" \ +-H "accept: application/json" +``` + +Example Output: + +```bash +{ + "unbonding_responses": [ + { + "delegator_address": "cosmos1q9snn84jfrd9ge8t46kdcggpe58dua82vnj7uy", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "90998", + "completion_time": "2021-11-05T00:14:37.005841058Z", + "initial_balance": "24000000", + "balance": "24000000" + } + ] + }, + { + "delegator_address": "cosmos1qf36e6wmq9h4twhdvs6pyq9qcaeu7ye0s3dqq2", + "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", + "entries": [ + { + "creation_height": "47478", + "completion_time": "2021-11-01T22:47:26.714116854Z", + "initial_balance": "8000000", + "balance": "8000000" + } + ] + } + ], + "pagination": { + "next_key": null, + "total": "2" + } +} +``` diff --git a/x/staking/spec/01_state.md b/x/staking/spec/01_state.md deleted file mode 100644 index d550d7bfbce3..000000000000 --- a/x/staking/spec/01_state.md +++ /dev/null @@ -1,217 +0,0 @@ - - -# State - -## Pool - -Pool is used for tracking bonded and not-bonded token supply of the bond denomination. - -## LastTotalPower - -LastTotalPower tracks the total amounts of bonded tokens recorded during the previous end block. -Store entries prefixed with "Last" must remain unchanged until EndBlock. - -* LastTotalPower: `0x12 -> ProtocolBuffer(math.Int)` - -## Params - -The staking module stores it's params in state with the prefix of `0x51`, -it can be updated with governance or the address with authority. - -* Params: `0x51 | ProtocolBuffer(Params)` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L285-L306 - -## Validator - -Validators can have one of three statuses - -* `Unbonded`: The validator is not in the active set. They cannot sign blocks and do not earn - rewards. They can receive delegations. -* `Bonded`: Once the validator receives sufficient bonded tokens they automtically join the - active set during [`EndBlock`](./05_end_block.md#validator-set-changes) and their status is updated to `Bonded`. - They are signing blocks and receiving rewards. They can receive further delegations. - They can be slashed for misbehavior. Delegators to this validator who unbond their delegation - must wait the duration of the UnbondingTime, a chain-specific param, during which time - they are still slashable for offences of the source validator if those offences were committed - during the period of time that the tokens were bonded. -* `Unbonding`: When a validator leaves the active set, either by choice or due to slashing, jailing or - tombstoning, an unbonding of all their delegations begins. All delegations must then wait the UnbondingTime - before their tokens are moved to their accounts from the `BondedPool`. - -Validators objects should be primarily stored and accessed by the -`OperatorAddr`, an SDK validator address for the operator of the validator. Two -additional indices are maintained per validator object in order to fulfill -required lookups for slashing and validator-set updates. A third special index -(`LastValidatorPower`) is also maintained which however remains constant -throughout each block, unlike the first two indices which mirror the validator -records within a block. - -* Validators: `0x21 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(validator)` -* ValidatorsByConsAddr: `0x22 | ConsAddrLen (1 byte) | ConsAddr -> OperatorAddr` -* ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddrLen (1 byte) | OperatorAddr -> OperatorAddr` -* LastValidatorsPower: `0x11 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(ConsensusPower)` - -`Validators` is the primary index - it ensures that each operator can have only one -associated validator, where the public key of that validator can change in the -future. Delegators can refer to the immutable operator of the validator, without -concern for the changing public key. - -`ValidatorByConsAddr` is an additional index that enables lookups for slashing. -When Tendermint reports evidence, it provides the validator address, so this -map is needed to find the operator. Note that the `ConsAddr` corresponds to the -address which can be derived from the validator's `ConsPubKey`. - -`ValidatorsByPower` is an additional index that provides a sorted list of -potential validators to quickly determine the current active set. Here -ConsensusPower is validator.Tokens/10^6 by default. Note that all validators -where `Jailed` is true are not stored within this index. - -`LastValidatorsPower` is a special index that provides a historical list of the -last-block's bonded validators. This index remains constant during a block but -is updated during the validator set update process which takes place in [`EndBlock`](./05_end_block.md). - -Each validator's state is stored in a `Validator` struct: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L78-L127 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L24-L76 - -## Delegation - -Delegations are identified by combining `DelegatorAddr` (the address of the delegator) -with the `ValidatorAddr` Delegators are indexed in the store as follows: - -* Delegation: `0x31 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(delegation)` - -Stake holders may delegate coins to validators; under this circumstance their -funds are held in a `Delegation` data structure. It is owned by one -delegator, and is associated with the shares for one validator. The sender of -the transaction is the owner of the bond. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L187-L205 - -### Delegator Shares - -When one Delegates tokens to a Validator they are issued a number of delegator shares based on a -dynamic exchange rate, calculated as follows from the total number of tokens delegated to the -validator and the number of shares issued so far: - -`Shares per Token = validator.TotalShares() / validator.Tokens()` - -Only the number of shares received is stored on the DelegationEntry. When a delegator then -Undelegates, the token amount they receive is calculated from the number of shares they currently -hold and the inverse exchange rate: - -`Tokens per Share = validator.Tokens() / validatorShares()` - -These `Shares` are simply an accounting mechanism. They are not a fungible asset. The reason for -this mechanism is to simplify the accounting around slashing. Rather than iteratively slashing the -tokens of every delegation entry, instead the Validators total bonded tokens can be slashed, -effectively reducing the value of each issued delegator share. - -## UnbondingDelegation - -Shares in a `Delegation` can be unbonded, but they must for some time exist as -an `UnbondingDelegation`, where shares can be reduced if Byzantine behavior is -detected. - -`UnbondingDelegation` are indexed in the store as: - -* UnbondingDelegation: `0x32 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)` -* UnbondingDelegationsFromValidator: `0x33 | ValidatorAddrLen (1 byte) | ValidatorAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` - -The first map here is used in queries, to lookup all unbonding delegations for -a given delegator, while the second map is used in slashing, to lookup all -unbonding delegations associated with a given validator that need to be -slashed. - -A UnbondingDelegation object is created every time an unbonding is initiated. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L207-L220 - -## Redelegation - -The bonded tokens worth of a `Delegation` may be instantly redelegated from a -source validator to a different validator (destination validator). However when -this occurs they must be tracked in a `Redelegation` object, whereby their -shares can be slashed if their tokens have contributed to a Byzantine fault -committed by the source validator. - -`Redelegation` are indexed in the store as: - -* Redelegations: `0x34 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)` -* RedelegationsBySrc: `0x35 | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` -* RedelegationsByDst: `0x36 | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil` - -The first map here is used for queries, to lookup all redelegations for a given -delegator. The second map is used for slashing based on the `ValidatorSrcAddr`, -while the third map is for slashing based on the `ValidatorDstAddr`. - -A redelegation object is created every time a redelegation occurs. To prevent -"redelegation hopping" redelegations may not occur under the situation that: - -* the (re)delegator already has another immature redelegation in progress - with a destination to a validator (let's call it `Validator X`) -* and, the (re)delegator is attempting to create a _new_ redelegation - where the source validator for this new redelegation is `Validator X`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L245-L283 - -## Queues - -All queues objects are sorted by timestamp. The time used within any queue is -first rounded to the nearest nanosecond then sorted. The sortable time format -used is a slight modification of the RFC3339Nano and uses the format string -`"2006-01-02T15:04:05.000000000"`. Notably this format: - -* right pads all zeros -* drops the time zone info (uses UTC) - -In all cases, the stored timestamp represents the maturation time of the queue -element. - -### UnbondingDelegationQueue - -For the purpose of tracking progress of unbonding delegations the unbonding -delegations queue is kept. - -* UnbondingDelegation: `0x41 | format(time) -> []DVPair` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L151-L161 - -### RedelegationQueue - -For the purpose of tracking progress of redelegations the redelegation queue is -kept. - -* RedelegationQueue: `0x42 | format(time) -> []DVVTriplet` - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L168-L179 - -### ValidatorQueue - -For the purpose of tracking progress of unbonding validators the validator -queue is kept. - -* ValidatorQueueTime: `0x43 | format(time) -> []sdk.ValAddress` - -The stored object as each key is an array of validator operator addresses from -which the validator object can be accessed. Typically it is expected that only -a single validator record will be associated with a given timestamp however it is possible -that multiple validators exist in the queue at the same location. - -## HistoricalInfo - -HistoricalInfo objects are stored and pruned at each block such that the staking keeper persists -the `n` most recent historical info defined by staking module parameter: `HistoricalEntries`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/staking.proto#L15-L22 - -At each BeginBlock, the staking keeper will persist the current Header and the Validators that committed -the current block in a `HistoricalInfo` object. The Validators are sorted on their address to ensure that -they are in a determisnistic order. -The oldest HistoricalEntries will be pruned to ensure that there only exist the parameter-defined number of -historical entries. diff --git a/x/staking/spec/02_state_transitions.md b/x/staking/spec/02_state_transitions.md deleted file mode 100644 index 9e9efffaeaa2..000000000000 --- a/x/staking/spec/02_state_transitions.md +++ /dev/null @@ -1,180 +0,0 @@ - - -# State Transitions - -This document describes the state transition operations pertaining to: - -1. [Validators](./02_state_transitions.md#validators) -2. [Delegations](./02_state_transitions.md#delegations) -3. [Slashing](./02_state_transitions.md#slashing) - -## Validators - -State transitions in validators are performed on every [`EndBlock`](./05_end_block.md#validator-set-changes) -in order to check for changes in the active `ValidatorSet`. - -A validator can be `Unbonded`, `Unbonding` or `Bonded`. `Unbonded` -and `Unbonding` are collectively called `Not Bonded`. A validator can move -directly between all the states, except for from `Bonded` to `Unbonded`. - -### Not bonded to Bonded - -The following transition occurs when a validator's ranking in the `ValidatorPowerIndex` surpasses -that of the `LastValidator`. - -* set `validator.Status` to `Bonded` -* send the `validator.Tokens` from the `NotBondedTokens` to the `BondedPool` `ModuleAccount` -* delete the existing record from `ValidatorByPowerIndex` -* add a new updated record to the `ValidatorByPowerIndex` -* update the `Validator` object for this validator -* if it exists, delete any `ValidatorQueue` record for this validator - -### Bonded to Unbonding - -When a validator begins the unbonding process the following operations occur: - -* send the `validator.Tokens` from the `BondedPool` to the `NotBondedTokens` `ModuleAccount` -* set `validator.Status` to `Unbonding` -* delete the existing record from `ValidatorByPowerIndex` -* add a new updated record to the `ValidatorByPowerIndex` -* update the `Validator` object for this validator -* insert a new record into the `ValidatorQueue` for this validator - -### Unbonding to Unbonded - -A validator moves from unbonding to unbonded when the `ValidatorQueue` object -moves from bonded to unbonded - -* update the `Validator` object for this validator -* set `validator.Status` to `Unbonded` - -### Jail/Unjail - -when a validator is jailed it is effectively removed from the Tendermint set. -this process may be also be reversed. the following operations occur: - -* set `Validator.Jailed` and update object -* if jailed delete record from `ValidatorByPowerIndex` -* if unjailed add record to `ValidatorByPowerIndex` - -Jailed validators are not present in any of the following stores: - -* the power store (from consensus power to address) - -## Delegations - -### Delegate - -When a delegation occurs both the validator and the delegation objects are affected - -* determine the delegators shares based on tokens delegated and the validator's exchange rate -* remove tokens from the sending account -* add shares the delegation object or add them to a created validator object -* add new delegator shares and update the `Validator` object -* transfer the `delegation.Amount` from the delegator's account to the `BondedPool` or the `NotBondedPool` `ModuleAccount` depending if the `validator.Status` is `Bonded` or not -* delete the existing record from `ValidatorByPowerIndex` -* add an new updated record to the `ValidatorByPowerIndex` - -### Begin Unbonding - -As a part of the Undelegate and Complete Unbonding state transitions Unbond -Delegation may be called. - -* subtract the unbonded shares from delegator -* add the unbonded tokens to an `UnbondingDelegation` Entry -* update the delegation or remove the delegation if there are no more shares -* if the delegation is the operator of the validator and no more shares exist then trigger a jail validator -* update the validator with removed the delegator shares and associated coins -* if the validator state is `Bonded`, transfer the `Coins` worth of the unbonded - shares from the `BondedPool` to the `NotBondedPool` `ModuleAccount` -* remove the validator if it is unbonded and there are no more delegation shares. - -### Cancel an `UnbondingDelegation` Entry -When a `cancel unbond delegation` occurs both the `validator`, the `delegation` and an `UnbondingDelegationQueue` state will be updated. -* if cancel unbonding delegation amount equals to the `UnbondingDelegation` entry `balance`, then the `UnbondingDelegation` entry deleted from `UnbondingDelegationQueue`. -* if the `cancel unbonding delegation amount is less than the `UnbondingDelegation` entry balance, then the `UnbondingDelegation` entry will be updated with new balance in the `UnbondingDelegationQueue`. -* cancel `amount` is [Delegated](02_state_transitions.md#delegations) back to the original `validator`. - -### Complete Unbonding - -For undelegations which do not complete immediately, the following operations -occur when the unbonding delegation queue element matures: - -* remove the entry from the `UnbondingDelegation` object -* transfer the tokens from the `NotBondedPool` `ModuleAccount` to the delegator `Account` - -### Begin Redelegation - -Redelegations affect the delegation, source and destination validators. - -* perform an `unbond` delegation from the source validator to retrieve the tokens worth of the unbonded shares -* using the unbonded tokens, `Delegate` them to the destination validator -* if the `sourceValidator.Status` is `Bonded`, and the `destinationValidator` is not, - transfer the newly delegated tokens from the `BondedPool` to the `NotBondedPool` `ModuleAccount` -* otherwise, if the `sourceValidator.Status` is not `Bonded`, and the `destinationValidator` - is `Bonded`, transfer the newly delegated tokens from the `NotBondedPool` to the `BondedPool` `ModuleAccount` -* record the token amount in an new entry in the relevant `Redelegation` - -From when a redelegation begins until it completes, the delegator is in a state of "pseudo-unbonding", and can still be -slashed for infractions that occured before the redelegation began. - -### Complete Redelegation - -When a redelegations complete the following occurs: - -* remove the entry from the `Redelegation` object - -## Slashing - -### Slash Validator - -When a Validator is slashed, the following occurs: - -* The total `slashAmount` is calculated as the `slashFactor` (a chain parameter) \* `TokensFromConsensusPower`, - the total number of tokens bonded to the validator at the time of the infraction. -* Every unbonding delegation and pseudo-unbonding redelegation such that the infraction occured before the unbonding or - redelegation began from the validator are slashed by the `slashFactor` percentage of the initialBalance. -* Each amount slashed from redelegations and unbonding delegations is subtracted from the - total slash amount. -* The `remaingSlashAmount` is then slashed from the validator's tokens in the `BondedPool` or - `NonBondedPool` depending on the validator's status. This reduces the total supply of tokens. - -In the case of a slash due to any infraction that requires evidence to submitted (for example double-sign), the slash -occurs at the block where the evidence is included, not at the block where the infraction occured. -Put otherwise, validators are not slashed retroactively, only when they are caught. - -### Slash Unbonding Delegation - -When a validator is slashed, so are those unbonding delegations from the validator that began unbonding -after the time of the infraction. Every entry in every unbonding delegation from the validator -is slashed by `slashFactor`. The amount slashed is calculated from the `InitialBalance` of the -delegation and is capped to prevent a resulting negative balance. Completed (or mature) unbondings are not slashed. - -### Slash Redelegation - -When a validator is slashed, so are all redelegations from the validator that began after the -infraction. Redelegations are slashed by `slashFactor`. -Redelegations that began before the infraction are not slashed. -The amount slashed is calculated from the `InitialBalance` of the delegation and is capped to -prevent a resulting negative balance. -Mature redelegations (that have completed pseudo-unbonding) are not slashed. - -## How Shares are calculated - -At any given point in time, each validator has a number of tokens, `T`, and has a number of shares issued, `S`. -Each delegator, `i`, holds a number of shares, `S_i`. -The number of tokens is the sum of all tokens delegated to the validator, plus the rewards, minus the slashes. - -The delegator is entitled to a portion of the underlying tokens proportional to their proportion of shares. -So delegator `i` is entitled to `T * S_i / S` of the validator's tokens. - -When a delegator delegates new tokens to the validator, they receive a number of shares proportional to their contribution. -So when delegator `j` delegates `T_j` tokens, they receive `S_j = S * T_j / T` shares. -The total number of tokens is now `T + T_j`, and the total number of shares is `S + S_j`. -`j`s proportion of the shares is the same as their proportion of the total tokens contributed: `(S + S_j) / S = (T + T_j) / T`. - -A special case is the initial delegation, when `T = 0` and `S = 0`, so `T_j / T` is undefined. -For the initial delegation, delegator `j` who delegates `T_j` tokens receive `S_j = T_j` shares. -So a validator that hasn't received any rewards and has not been slashed will have `T = S`. diff --git a/x/staking/spec/03_messages.md b/x/staking/spec/03_messages.md deleted file mode 100644 index 967401e17a67..000000000000 --- a/x/staking/spec/03_messages.md +++ /dev/null @@ -1,187 +0,0 @@ - - -# Messages - -In this section we describe the processing of the staking messages and the corresponding updates to the state. All created/modified state objects specified by each message are defined within the [state](./02_state_transitions.md) section. - -## MsgCreateValidator - -A validator is created using the `MsgCreateValidator` message. -The validator must be created with an initial delegation from the operator. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L18-L19 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L43-L65 - -This message is expected to fail if: - -* another validator with this operator address is already registered -* another validator with this pubkey is already registered -* the initial self-delegation tokens are of a denom not specified as the bonding denom -* the commission parameters are faulty, namely: - * `MaxRate` is either > 1 or < 0 - * the initial `Rate` is either negative or > `MaxRate` - * the initial `MaxChangeRate` is either negative or > `MaxRate` -* the description fields are too large - -This message creates and stores the `Validator` object at appropriate indexes. -Additionally a self-delegation is made with the initial tokens delegation -tokens `Delegation`. The validator always starts as unbonded but may be bonded -in the first end-block. - -## MsgEditValidator - -The `Description`, `CommissionRate` of a validator can be updated using the -`MsgEditValidator` message. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L21-L22 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L70-L88 - -This message is expected to fail if: - -* the initial `CommissionRate` is either negative or > `MaxRate` -* the `CommissionRate` has already been updated within the previous 24 hours -* the `CommissionRate` is > `MaxChangeRate` -* the description fields are too large - -This message stores the updated `Validator` object. - -## MsgDelegate - -Within this message the delegator provides coins, and in return receives -some amount of their validator's (newly created) delegator-shares that are -assigned to `Delegation.Shares`. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L24-L26 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L93-L104 - -This message is expected to fail if: - -* the validator does not exist -* the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` -* the exchange rate is invalid, meaning the validator has no tokens (due to slashing) but there are outstanding shares -* the amount delegated is less than the minimum allowed delegation - -If an existing `Delegation` object for provided addresses does not already -exist then it is created as part of this message otherwise the existing -`Delegation` is updated to include the newly received shares. - -The delegator receives newly minted shares at the current exchange rate. -The exchange rate is the number of existing shares in the validator divided by -the number of currently delegated tokens. - -The validator is updated in the `ValidatorByPower` index, and the delegation is -tracked in validator object in the `Validators` index. - -It is possible to delegate to a jailed validator, the only difference being it -will not be added to the power index until it is unjailed. - -![Delegation sequence](../../../docs/uml/svg/delegation_sequence.svg) - -## MsgUndelegate - -The `MsgUndelegate` message allows delegators to undelegate their tokens from -validator. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L32-L34 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L128-L139 - -This message returns a response containing the completion time of the undelegation: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L128-L144 - -This message is expected to fail if: - -* the delegation doesn't exist -* the validator doesn't exist -* the delegation has less shares than the ones worth of `Amount` -* existing `UnbondingDelegation` has maximum entries as defined by `params.MaxEntries` -* the `Amount` has a denomination different than one defined by `params.BondDenom` - -When this message is processed the following actions occur: - -* validator's `DelegatorShares` and the delegation's `Shares` are both reduced by the message `SharesAmount` -* calculate the token worth of the shares remove that amount tokens held within the validator -* with those removed tokens, if the validator is: - * `Bonded` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares. - * `Unbonding` - add them to an entry in `UnbondingDelegation` (create `UnbondingDelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). - * `Unbonded` - then send the coins the message `DelegatorAddr` -* if there are no more `Shares` in the delegation, then the delegation object is removed from the store - * under this situation if the delegation is the validator's self-delegation then also jail the validator. - -![Unbond sequence](../../../docs/uml/svg/unbond_sequence.svg) - -## MsgCancelUnbondingDelegation - -The `MsgCancelUnbondingDelegation` message allows delegators to cancel the `unbondingDelegation` entry and deleagate back to a previous validator. - -+++ hhttps://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L36-L40 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L146-L165 - -This message is expected to fail if: - -* the `unbondingDelegation` entry is already processed. -* the `cancel unbonding delegation` amount is greater than the `unbondingDelegation` entry balance. -* the `cancel unbonding delegation` height doesn't exists in the `unbondingDelegationQueue` of the delegator. - -When this message is processed the following actions occur: - -* if the `unbondingDelegation` Entry balance is zero - * in this condition `unbondingDelegation` entry will be removed from `unbondingDelegationQueue`. - * otherwise `unbondingDelegationQueue` will be updated with new `unbondingDelegation` entry balance and initial balance -* the validator's `DelegatorShares` and the delegation's `Shares` are both increased by the message `Amount`. - -## MsgBeginRedelegate - -The redelegation command allows delegators to instantly switch validators. Once -the unbonding period has passed, the redelegation is automatically completed in -the EndBlocker. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L28-L30 - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L109-L121 - -This message returns a response containing the completion time of the redelegation: - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/staking/v1beta1/tx.proto#L123-L126 - -This message is expected to fail if: - -* the delegation doesn't exist -* the source or destination validators don't exist -* the delegation has less shares than the ones worth of `Amount` -* the source validator has a receiving redelegation which is not matured (aka. the redelegation may be transitive) -* existing `Redelegation` has maximum entries as defined by `params.MaxEntries` -* the `Amount` `Coin` has a denomination different than one defined by `params.BondDenom` - -When this message is processed the following actions occur: - -* the source validator's `DelegatorShares` and the delegations `Shares` are both reduced by the message `SharesAmount` -* calculate the token worth of the shares remove that amount tokens held within the source validator. -* if the source validator is: - * `Bonded` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with a completion time a full unbonding period from the current time. Update pool shares to reduce BondedTokens and increase NotBondedTokens by token worth of the shares (this may be effectively reversed in the next step however). - * `Unbonding` - add an entry to the `Redelegation` (create `Redelegation` if it doesn't exist) with the same completion time as the validator (`UnbondingMinTime`). - * `Unbonded` - no action required in this step -* Delegate the token worth to the destination validator, possibly moving tokens back to the bonded state. -* if there are no more `Shares` in the source delegation, then the source delegation object is removed from the store - * under this situation if the delegation is the validator's self-delegation then also jail the validator. - -![Begin redelegation sequence](../../../docs/uml/svg/begin_redelegation_sequence.svg) - - -## MsgUpdateParams - -The `MsgUpdateParams` update the staking module parameters. -The params are updated through a governance proposal where the signer is the gov module account address. - -+++ https://github.com/cosmos/cosmos-sdk/blob/e412ce990251768579d49947991be76a87564f7d/proto/cosmos/staking/v1beta1/tx.proto#L172-L190 - -The message handling can fail if: - -* signer is not the authority defined in the staking keeper (usually the gov module account). \ No newline at end of file diff --git a/x/staking/spec/04_begin_block.md b/x/staking/spec/04_begin_block.md deleted file mode 100644 index 3ba615b5de4a..000000000000 --- a/x/staking/spec/04_begin_block.md +++ /dev/null @@ -1,16 +0,0 @@ - - -# Begin-Block - -Each abci begin block call, the historical info will get stored and pruned -according to the `HistoricalEntries` parameter. - -## Historical Info Tracking - -If the `HistoricalEntries` parameter is 0, then the `BeginBlock` performs a no-op. - -Otherwise, the latest historical info is stored under the key `historicalInfoKey|height`, while any entries older than `height - HistoricalEntries` is deleted. -In most cases, this results in a single entry being pruned per block. -However, if the parameter `HistoricalEntries` has changed to a lower value there will be multiple entries in the store that must be pruned. diff --git a/x/staking/spec/05_end_block.md b/x/staking/spec/05_end_block.md deleted file mode 100644 index 7eb01421182f..000000000000 --- a/x/staking/spec/05_end_block.md +++ /dev/null @@ -1,77 +0,0 @@ - - -# End-Block - -Each abci end block call, the operations to update queues and validator set -changes are specified to execute. - -## Validator Set Changes - -The staking validator set is updated during this process by state transitions -that run at the end of every block. As a part of this process any updated -validators are also returned back to Tendermint for inclusion in the Tendermint -validator set which is responsible for validating Tendermint messages at the -consensus layer. Operations are as following: - -* the new validator set is taken as the top `params.MaxValidators` number of - validators retrieved from the `ValidatorsByPower` index -* the previous validator set is compared with the new validator set: - * missing validators begin unbonding and their `Tokens` are transferred from the - `BondedPool` to the `NotBondedPool` `ModuleAccount` - * new validators are instantly bonded and their `Tokens` are transferred from the - `NotBondedPool` to the `BondedPool` `ModuleAccount` - -In all cases, any validators leaving or entering the bonded validator set or -changing balances and staying within the bonded validator set incur an update -message reporting their new consensus power which is passed back to Tendermint. - -The `LastTotalPower` and `LastValidatorsPower` hold the state of the total power -and validator power from the end of the last block, and are used to check for -changes that have occured in `ValidatorsByPower` and the total new power, which -is calculated during `EndBlock`. - -## Queues - -Within staking, certain state-transitions are not instantaneous but take place -over a duration of time (typically the unbonding period). When these -transitions are mature certain operations must take place in order to complete -the state operation. This is achieved through the use of queues which are -checked/processed at the end of each block. - -### Unbonding Validators - -When a validator is kicked out of the bonded validator set (either through -being jailed, or not having sufficient bonded tokens) it begins the unbonding -process along with all its delegations begin unbonding (while still being -delegated to this validator). At this point the validator is said to be an -"unbonding validator", whereby it will mature to become an "unbonded validator" -after the unbonding period has passed. - -Each block the validator queue is to be checked for mature unbonding validators -(namely with a completion time <= current time and completion height <= current -block height). At this point any mature validators which do not have any -delegations remaining are deleted from state. For all other mature unbonding -validators that still have remaining delegations, the `validator.Status` is -switched from `types.Unbonding` to -`types.Unbonded`. - -### Unbonding Delegations - -Complete the unbonding of all mature `UnbondingDelegations.Entries` within the -`UnbondingDelegations` queue with the following procedure: - -* transfer the balance coins to the delegator's wallet address -* remove the mature entry from `UnbondingDelegation.Entries` -* remove the `UnbondingDelegation` object from the store if there are no - remaining entries. - -### Redelegations - -Complete the unbonding of all mature `Redelegation.Entries` within the -`Redelegations` queue with the following procedure: - -* remove the mature entry from `Redelegation.Entries` -* remove the `Redelegation` object from the store if there are no - remaining entries. diff --git a/x/staking/spec/06_hooks.md b/x/staking/spec/06_hooks.md deleted file mode 100644 index 5c98e5e6a00d..000000000000 --- a/x/staking/spec/06_hooks.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# Hooks - -Other modules may register operations to execute when a certain event has -occurred within staking. These events can be registered to execute either -right `Before` or `After` the staking event (as per the hook name). The -following hooks can registered with staking: - -* `AfterValidatorCreated(Context, ValAddress) error` - * called when a validator is created -* `BeforeValidatorModified(Context, ValAddress) error` - * called when a validator's state is changed -* `AfterValidatorRemoved(Context, ConsAddress, ValAddress) error` - * called when a validator is deleted -* `AfterValidatorBonded(Context, ConsAddress, ValAddress) error` - * called when a validator is bonded -* `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress) error` - * called when a validator begins unbonding -* `BeforeDelegationCreated(Context, AccAddress, ValAddress) error` - * called when a delegation is created -* `BeforeDelegationSharesModified(Context, AccAddress, ValAddress) error` - * called when a delegation's shares are modified -* `AfterDelegationModified(Context, AccAddress, ValAddress) error` - * called when a delegation is created or modified -* `BeforeDelegationRemoved(Context, AccAddress, ValAddress) error` - * called when a delegation is removed diff --git a/x/staking/spec/07_events.md b/x/staking/spec/07_events.md deleted file mode 100644 index eeeb84c4b902..000000000000 --- a/x/staking/spec/07_events.md +++ /dev/null @@ -1,90 +0,0 @@ - - -# Events - -The staking module emits the following events: - -## EndBlocker - -| Type | Attribute Key | Attribute Value | -| --------------------- | --------------------- | ------------------------- | -| complete_unbonding | amount | {totalUnbondingAmount} | -| complete_unbonding | validator | {validatorAddress} | -| complete_unbonding | delegator | {delegatorAddress} | -| complete_redelegation | amount | {totalRedelegationAmount} | -| complete_redelegation | source_validator | {srcValidatorAddress} | -| complete_redelegation | destination_validator | {dstValidatorAddress} | -| complete_redelegation | delegator | {delegatorAddress} | - -## Msg's - -### MsgCreateValidator - -| Type | Attribute Key | Attribute Value | -| ---------------- | ------------- | ------------------ | -| create_validator | validator | {validatorAddress} | -| create_validator | amount | {delegationAmount} | -| message | module | staking | -| message | action | create_validator | -| message | sender | {senderAddress} | - -### MsgEditValidator - -| Type | Attribute Key | Attribute Value | -| -------------- | ------------------- | ------------------- | -| edit_validator | commission_rate | {commissionRate} | -| edit_validator | min_self_delegation | {minSelfDelegation} | -| message | module | staking | -| message | action | edit_validator | -| message | sender | {senderAddress} | - -### MsgDelegate - -| Type | Attribute Key | Attribute Value | -| -------- | ------------- | ------------------ | -| delegate | validator | {validatorAddress} | -| delegate | amount | {delegationAmount} | -| message | module | staking | -| message | action | delegate | -| message | sender | {senderAddress} | - -### MsgUndelegate - -| Type | Attribute Key | Attribute Value | -| ------- | ------------------- | ------------------ | -| unbond | validator | {validatorAddress} | -| unbond | amount | {unbondAmount} | -| unbond | completion_time [0] | {completionTime} | -| message | module | staking | -| message | action | begin_unbonding | -| message | sender | {senderAddress} | - -* [0] Time is formatted in the RFC3339 standard - -### MsgCancelUnbondingDelegation - -| Type | Attribute Key | Attribute Value | -| ----------------------------- | ------------------ | ------------------------------------| -| cancel_unbonding_delegation | validator | {validatorAddress} | -| cancel_unbonding_delegation | delegator | {delegatorAddress} | -| cancel_unbonding_delegation | amount | {cancelUnbondingDelegationAmount} | -| cancel_unbonding_delegation | creation_height | {unbondingCreationHeight} | -| message | module | staking | -| message | action | cancel_unbond | -| message | sender | {senderAddress} | - -### MsgBeginRedelegate - -| Type | Attribute Key | Attribute Value | -| ---------- | --------------------- | --------------------- | -| redelegate | source_validator | {srcValidatorAddress} | -| redelegate | destination_validator | {dstValidatorAddress} | -| redelegate | amount | {unbondAmount} | -| redelegate | completion_time [0] | {completionTime} | -| message | module | staking | -| message | action | begin_redelegate | -| message | sender | {senderAddress} | - -* [0] Time is formatted in the RFC3339 standard diff --git a/x/staking/spec/08_params.md b/x/staking/spec/08_params.md deleted file mode 100644 index e4a56ab3fac2..000000000000 --- a/x/staking/spec/08_params.md +++ /dev/null @@ -1,16 +0,0 @@ - - -# Parameters - -The staking module contains the following parameters: - -| Key | Type | Example | -|-------------------|------------------|------------------------| -| UnbondingTime | string (time ns) | "259200000000000" | -| MaxValidators | uint16 | 100 | -| KeyMaxEntries | uint16 | 7 | -| HistoricalEntries | uint16 | 3 | -| BondDenom | string | "stake" | -| MinCommissionRate | string | "0.000000000000000000" | diff --git a/x/staking/spec/09_client.md b/x/staking/spec/09_client.md deleted file mode 100644 index 0c3383d01446..000000000000 --- a/x/staking/spec/09_client.md +++ /dev/null @@ -1,2101 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `staking` module using the CLI. - -### Query - -The `query` commands allows users to query `staking` state. - -```bash -simd query staking --help -``` - -#### delegation - -The `delegation` command allows users to query delegations for an individual delegator on an individual validator. - -Usage: - -```bash -simd query staking delegation [delegator-addr] [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -balance: - amount: "10000000000" - denom: stake -delegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - shares: "10000000000.000000000000000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -#### delegations - -The `delegations` command allows users to query delegations for an individual delegator on all validators. - -Usage: - -```bash -simd query staking delegations [delegator-addr] [flags] -``` - -Example: - -```bash -simd query staking delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -``` - -Example Output: - -```bash -delegation_responses: -- balance: - amount: "10000000000" - denom: stake - delegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - shares: "10000000000.000000000000000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -- balance: - amount: "10000000000" - denom: stake - delegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - shares: "10000000000.000000000000000000" - validator_address: cosmosvaloper1x20lytyf6zkcrv5edpkfkn8sz578qg5sqfyqnp -pagination: - next_key: null - total: "0" -``` - -#### delegations-to - -The `delegations-to` command allows users to query delegations on an individual validator. - -Usage: - -```bash -simd query staking delegations-to [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking delegations-to cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -- balance: - amount: "504000000" - denom: stake - delegation: - delegator_address: cosmos1q2qwwynhv8kh3lu5fkeex4awau9x8fwt45f5cp - shares: "504000000.000000000000000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -- balance: - amount: "78125000000" - denom: uixo - delegation: - delegator_address: cosmos1qvppl3479hw4clahe0kwdlfvf8uvjtcd99m2ca - shares: "78125000000.000000000000000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -pagination: - next_key: null - total: "0" -``` - -#### historical-info - -The `historical-info` command allows users to query historical information at given height. - -Usage: - -```bash -simd query staking historical-info [height] [flags] -``` - -Example: - -```bash -simd query staking historical-info 10 -``` - -Example Output: - -```bash -header: - app_hash: Lbx8cXpI868wz8sgp4qPYVrlaKjevR5WP/IjUxwp3oo= - chain_id: testnet - consensus_hash: BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8= - data_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= - evidence_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= - height: "10" - last_block_id: - hash: RFbkpu6pWfSThXxKKl6EZVDnBSm16+U0l0xVjTX08Fk= - part_set_header: - hash: vpIvXD4rxD5GM4MXGz0Sad9I7//iVYLzZsEU4BVgWIU= - total: 1 - last_commit_hash: Ne4uXyx4QtNp4Zx89kf9UK7oG9QVbdB6e7ZwZkhy8K0= - last_results_hash: 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU= - next_validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= - proposer_address: mMEP2c2IRPLr99LedSRtBg9eONM= - time: "2021-10-01T06:00:49.785790894Z" - validators_hash: nGBgKeWBjoxeKFti00CxHsnULORgKY4LiuQwBuUrhCs= - version: - app: "0" - block: "11" -valset: -- commission: - commission_rates: - max_change_rate: "0.010000000000000000" - max_rate: "0.200000000000000000" - rate: "0.100000000000000000" - update_time: "2021-10-01T05:52:50.380144238Z" - consensus_pubkey: - '@type': /cosmos.crypto.ed25519.PubKey - key: Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8= - delegator_shares: "10000000.000000000000000000" - description: - details: "" - identity: "" - moniker: myvalidator - security_contact: "" - website: "" - jailed: false - min_self_delegation: "1" - operator_address: cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc - status: BOND_STATUS_BONDED - tokens: "10000000" - unbonding_height: "0" - unbonding_time: "1970-01-01T00:00:00Z" -``` - -#### params - -The `params` command allows users to query values set as staking parameters. - -Usage: - -```bash -simd query staking params [flags] -``` - -Example: - -```bash -simd query staking params -``` - -Example Output: - -```bash -bond_denom: stake -historical_entries: 10000 -max_entries: 7 -max_validators: 50 -unbonding_time: 1814400s -``` - -#### pool - -The `pool` command allows users to query values for amounts stored in the staking pool. - -Usage: - -```bash -simd q staking pool [flags] -``` - -Example: - -```bash -simd q staking pool -``` - -Example Output: - -```bash -bonded_tokens: "10000000" -not_bonded_tokens: "0" -``` - -#### redelegation - -The `redelegation` command allows users to query a redelegation record based on delegator and a source and destination validator address. - -Usage: - -```bash -simd query staking redelegation [delegator-addr] [src-validator-addr] [dst-validator-addr] [flags] -``` - -Example: - -```bash -simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -pagination: null -redelegation_responses: -- entries: - - balance: "50000000" - redelegation_entry: - completion_time: "2021-10-24T20:33:21.960084845Z" - creation_height: 2.382847e+06 - initial_balance: "50000000" - shares_dst: "50000000.000000000000000000" - - balance: "5000000000" - redelegation_entry: - completion_time: "2021-10-25T21:33:54.446846862Z" - creation_height: 2.397271e+06 - initial_balance: "5000000000" - shares_dst: "5000000000.000000000000000000" - redelegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - entries: null - validator_dst_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm - validator_src_address: cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm -``` - -#### redelegations - -The `redelegations` command allows users to query all redelegation records for an individual delegator. - -Usage: - -```bash -simd query staking redelegations [delegator-addr] [flags] -``` - -Example: - -```bash -simd query staking redelegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -redelegation_responses: -- entries: - - balance: "50000000" - redelegation_entry: - completion_time: "2021-10-24T20:33:21.960084845Z" - creation_height: 2.382847e+06 - initial_balance: "50000000" - shares_dst: "50000000.000000000000000000" - - balance: "5000000000" - redelegation_entry: - completion_time: "2021-10-25T21:33:54.446846862Z" - creation_height: 2.397271e+06 - initial_balance: "5000000000" - shares_dst: "5000000000.000000000000000000" - redelegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - entries: null - validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm - validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp -- entries: - - balance: "562770000000" - redelegation_entry: - completion_time: "2021-10-25T21:42:07.336911677Z" - creation_height: 2.39735e+06 - initial_balance: "562770000000" - shares_dst: "562770000000.000000000000000000" - redelegation: - delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - entries: null - validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm - validator_src_address: cosmosvaloper1zppjyal5emta5cquje8ndkpz0rs046m7zqxrpp -``` - -#### redelegations-from - -The `redelegations-from` command allows users to query delegations that are redelegating _from_ a validator. - -Usage: - -```bash -simd query staking redelegations-from [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking redelegations-from cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -redelegation_responses: -- entries: - - balance: "50000000" - redelegation_entry: - completion_time: "2021-10-24T20:33:21.960084845Z" - creation_height: 2.382847e+06 - initial_balance: "50000000" - shares_dst: "50000000.000000000000000000" - - balance: "5000000000" - redelegation_entry: - completion_time: "2021-10-25T21:33:54.446846862Z" - creation_height: 2.397271e+06 - initial_balance: "5000000000" - shares_dst: "5000000000.000000000000000000" - redelegation: - delegator_address: cosmos1pm6e78p4pgn0da365plzl4t56pxy8hwtqp2mph - entries: null - validator_dst_address: cosmosvaloper1uccl5ugxrm7vqlzwqr04pjd320d2fz0z3hc6vm - validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy -- entries: - - balance: "221000000" - redelegation_entry: - completion_time: "2021-10-05T21:05:45.669420544Z" - creation_height: 2.120693e+06 - initial_balance: "221000000" - shares_dst: "221000000.000000000000000000" - redelegation: - delegator_address: cosmos1zqv8qxy2zgn4c58fz8jt8jmhs3d0attcussrf6 - entries: null - validator_dst_address: cosmosvaloper10mseqwnwtjaqfrwwp2nyrruwmjp6u5jhah4c3y - validator_src_address: cosmosvaloper1y4rzzrgl66eyhzt6gse2k7ej3zgwmngeleucjy -``` - -#### unbonding-delegation - -The `unbonding-delegation` command allows users to query unbonding delegations for an individual delegator on an individual validator. - -Usage: - -```bash -simd query staking unbonding-delegation [delegator-addr] [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking unbonding-delegation cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -entries: -- balance: "52000000" - completion_time: "2021-11-02T11:35:55.391594709Z" - creation_height: "55078" - initial_balance: "52000000" -validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -#### unbonding-delegations - -The `unbonding-delegations` command allows users to query all unbonding-delegations records for one delegator. - -Usage: - -```bash -simd query staking unbonding-delegations [delegator-addr] [flags] -``` - -Example: - -```bash -simd query staking unbonding-delegations cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -unbonding_responses: -- delegator_address: cosmos1gghjut3ccd8ay0zduzj64hwre2fxs9ld75ru9p - entries: - - balance: "52000000" - completion_time: "2021-11-02T11:35:55.391594709Z" - creation_height: "55078" - initial_balance: "52000000" - validator_address: cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa - -``` - -#### unbonding-delegations-from - -The `unbonding-delegations-from` command allows users to query delegations that are unbonding _from_ a validator. - -Usage: - -```bash -simd query staking unbonding-delegations-from [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking unbonding-delegations-from cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -pagination: - next_key: null - total: "0" -unbonding_responses: -- delegator_address: cosmos1qqq9txnw4c77sdvzx0tkedsafl5s3vk7hn53fn - entries: - - balance: "150000000" - completion_time: "2021-11-01T21:41:13.098141574Z" - creation_height: "46823" - initial_balance: "150000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -- delegator_address: cosmos1peteje73eklqau66mr7h7rmewmt2vt99y24f5z - entries: - - balance: "24000000" - completion_time: "2021-10-31T02:57:18.192280361Z" - creation_height: "21516" - initial_balance: "24000000" - validator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -#### validator - -The `validator` command allows users to query details about an individual validator. - -Usage: - -```bash -simd query staking validator [validator-addr] [flags] -``` - -Example: - -```bash -simd query staking validator cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -``` - -Example Output: - -```bash -commission: - commission_rates: - max_change_rate: "0.020000000000000000" - max_rate: "0.200000000000000000" - rate: "0.050000000000000000" - update_time: "2021-10-01T19:24:52.663191049Z" -consensus_pubkey: - '@type': /cosmos.crypto.ed25519.PubKey - key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= -delegator_shares: "32948270000.000000000000000000" -description: - details: Witval is the validator arm from Vitwit. Vitwit is into software consulting - and services business since 2015. We are working closely with Cosmos ecosystem - since 2018. We are also building tools for the ecosystem, Aneka is our explorer - for the cosmos ecosystem. - identity: 51468B615127273A - moniker: Witval - security_contact: "" - website: "" -jailed: false -min_self_delegation: "1" -operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj -status: BOND_STATUS_BONDED -tokens: "32948270000" -unbonding_height: "0" -unbonding_time: "1970-01-01T00:00:00Z" -``` - -#### validators - -The `validators` command allows users to query details about all validators on a network. - -Usage: - -```bash -simd query staking validators [flags] -``` - -Example: - -```bash -simd query staking validators -``` - -Example Output: - -```bash -pagination: - next_key: FPTi7TKAjN63QqZh+BaXn6gBmD5/ - total: "0" -validators: -commission: - commission_rates: - max_change_rate: "0.020000000000000000" - max_rate: "0.200000000000000000" - rate: "0.050000000000000000" - update_time: "2021-10-01T19:24:52.663191049Z" -consensus_pubkey: - '@type': /cosmos.crypto.ed25519.PubKey - key: sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc= -delegator_shares: "32948270000.000000000000000000" -description: - details: Witval is the validator arm from Vitwit. Vitwit is into software consulting - and services business since 2015. We are working closely with Cosmos ecosystem - since 2018. We are also building tools for the ecosystem, Aneka is our explorer - for the cosmos ecosystem. - identity: 51468B615127273A - moniker: Witval - security_contact: "" - website: "" - jailed: false - min_self_delegation: "1" - operator_address: cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj - status: BOND_STATUS_BONDED - tokens: "32948270000" - unbonding_height: "0" - unbonding_time: "1970-01-01T00:00:00Z" -- commission: - commission_rates: - max_change_rate: "0.100000000000000000" - max_rate: "0.200000000000000000" - rate: "0.050000000000000000" - update_time: "2021-10-04T18:02:21.446645619Z" - consensus_pubkey: - '@type': /cosmos.crypto.ed25519.PubKey - key: GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA= - delegator_shares: "559343421.000000000000000000" - description: - details: Noderunners is a professional validator in POS networks. We have a huge - node running experience, reliable soft and hardware. Our commissions are always - low, our support to delegators is always full. Stake with us and start receiving - your Cosmos rewards now! - identity: 812E82D12FEA3493 - moniker: Noderunners - security_contact: info@noderunners.biz - website: http://noderunners.biz - jailed: false - min_self_delegation: "1" - operator_address: cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7 - status: BOND_STATUS_BONDED - tokens: "559343421" - unbonding_height: "0" - unbonding_time: "1970-01-01T00:00:00Z" -``` - -### Transactions - -The `tx` commands allows users to interact with the `staking` module. - -```bash -simd tx staking --help -``` - -#### create-validator - -The command `create-validator` allows users to create new validator initialized with a self-delegation to it. - -Usage: - -```bash -simd tx staking create-validator [flags] -``` - -Example: - -```bash -simd tx staking create-validator \ - --amount=1000000stake \ - --pubkey=$(simd tendermint show-validator) \ - --moniker="my-moniker" \ - --website="https://myweb.site" \ - --details="description of your validator" \ - --chain-id="name_of_chain_id" \ - --commission-rate="0.10" \ - --commission-max-rate="0.20" \ - --commission-max-change-rate="0.01" \ - --min-self-delegation="1" \ - --gas="auto" \ - --gas-adjustment="1.2" \ - --gas-prices="0.025stake" \ - --from=mykey -``` - -#### delegate - -The command `delegate` allows users to delegate liquid tokens to a validator. - -Usage: - -```bash -simd tx staking delegate [validator-addr] [amount] [flags] -``` - -Example: - -```bash -simd tx staking delegate cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 1000stake --from mykey -``` - -#### edit-validator - -The command `edit-validator` allows users to edit an existing validator account. - -Usage: - -```bash -simd tx staking edit-validator [flags] -``` - -Example: - -```bash -simd tx staking edit-validator --moniker "new_moniker_name" --website "new_webiste_url" --from mykey -``` - -#### redelegate - -The command `redelegate` allows users to redelegate illiquid tokens from one validator to another. - -Usage: - -```bash -simd tx staking redelegate [src-validator-addr] [dst-validator-addr] [amount] [flags] -``` - -Example: - -```bash -simd tx staking redelegate cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj cosmosvaloper1l2rsakp388kuv9k8qzq6lrm9taddae7fpx59wm 100stake --from mykey -``` - -#### unbond - -The command `unbond` allows users to unbond shares from a validator. - -Usage: - -```bash -simd tx staking unbond [validator-addr] [amount] [flags] -``` - -Example: - -```bash -simd tx staking unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake --from mykey -``` -#### cancel unbond -The command `cancel-unbond` allow users to cancel the unbonding delegation entry and delegate back to the original validator. - -Usage: -```bash -simd tx staking cancel-unbond [validator-addr] [amount] [creation-height] -``` - -Example: -```bash -simd tx staking cancel-unbond cosmosvaloper1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj 100stake 123123 --from mykey -``` - - -## gRPC - -A user can query the `staking` module using gRPC endpoints. - -### Validators - -The `Validators` endpoint queries all validators that match the given status. - -```bash -cosmos.staking.v1beta1.Query/Validators -``` - -Example: - -```bash -grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Validators -``` - -Example Output: - -```bash -{ - "validators": [ - { - "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, - "status": "BOND_STATUS_BONDED", - "tokens": "10000000", - "delegatorShares": "10000000000000000000000000", - "description": { - "moniker": "myvalidator" - }, - "unbondingTime": "1970-01-01T00:00:00Z", - "commission": { - "commissionRates": { - "rate": "100000000000000000", - "maxRate": "200000000000000000", - "maxChangeRate": "10000000000000000" - }, - "updateTime": "2021-10-01T05:52:50.380144238Z" - }, - "minSelfDelegation": "1" - } - ], - "pagination": { - "total": "1" - } -} -``` - -### Validator - -The `Validator` endpoint queries validator information for given validator address. - -```bash -cosmos.staking.v1beta1.Query/Validator -``` - -Example: - -```bash -grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/Validator -``` - -Example Output: - -```bash -{ - "validator": { - "operatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "consensusPubkey": {"@type":"/cosmos.crypto.ed25519.PubKey","key":"Auxs3865HpB/EfssYOzfqNhEJjzys2Fo6jD5B8tPgC8="}, - "status": "BOND_STATUS_BONDED", - "tokens": "10000000", - "delegatorShares": "10000000000000000000000000", - "description": { - "moniker": "myvalidator" - }, - "unbondingTime": "1970-01-01T00:00:00Z", - "commission": { - "commissionRates": { - "rate": "100000000000000000", - "maxRate": "200000000000000000", - "maxChangeRate": "10000000000000000" - }, - "updateTime": "2021-10-01T05:52:50.380144238Z" - }, - "minSelfDelegation": "1" - } -} -``` - -### ValidatorDelegations - -The `ValidatorDelegations` endpoint queries delegate information for given validator. - -```bash -cosmos.staking.v1beta1.Query/ValidatorDelegations -``` - -Example: - -```bash -grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/ValidatorDelegations -``` - -Example Output: - -```bash -{ - "delegationResponses": [ - { - "delegation": { - "delegatorAddress": "cosmos1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgy3ua5t", - "validatorAddress": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "shares": "10000000000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "10000000" - } - } - ], - "pagination": { - "total": "1" - } -} -``` - -### ValidatorUnbondingDelegations - -The `ValidatorUnbondingDelegations` endpoint queries delegate information for given validator. - -```bash -cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations -``` - -Example: - -```bash -grpcurl -plaintext -d '{"validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/ValidatorUnbondingDelegations -``` - -Example Output: - -```bash -{ - "unbonding_responses": [ - { - "delegator_address": "cosmos1z3pzzw84d6xn00pw9dy3yapqypfde7vg6965fy", - "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "entries": [ - { - "creation_height": "25325", - "completion_time": "2021-10-31T09:24:36.797320636Z", - "initial_balance": "20000000", - "balance": "20000000" - } - ] - }, - { - "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", - "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "entries": [ - { - "creation_height": "13100", - "completion_time": "2021-10-30T12:53:02.272266791Z", - "initial_balance": "1000000", - "balance": "1000000" - } - ] - }, - ], - "pagination": { - "next_key": null, - "total": "8" - } -} -``` - -### Delegation - -The `Delegation` endpoint queries delegate information for given validator delegator pair. - -```bash -cosmos.staking.v1beta1.Query/Delegation -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/Delegation -``` - -Example Output: - -```bash -{ - "delegation_response": - { - "delegation": - { - "delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", - "validator_address":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "shares":"25083119936.000000000000000000" - }, - "balance": - { - "denom":"stake", - "amount":"25083119936" - } - } -} -``` - -### UnbondingDelegation - -The `UnbondingDelegation` endpoint queries unbonding information for given validator delegator. - -```bash -cosmos.staking.v1beta1.Query/UnbondingDelegation -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", validator_addr":"cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/UnbondingDelegation -``` - -Example Output: - -```bash -{ - "unbond": { - "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", - "validator_address": "cosmosvaloper1rne8lgs98p0jqe82sgt0qr4rdn4hgvmgp9ggcc", - "entries": [ - { - "creation_height": "136984", - "completion_time": "2021-11-08T05:38:47.505593891Z", - "initial_balance": "400000000", - "balance": "400000000" - }, - { - "creation_height": "137005", - "completion_time": "2021-11-08T05:40:53.526196312Z", - "initial_balance": "385000000", - "balance": "385000000" - } - ] - } -} -``` - -### DelegatorDelegations - -The `DelegatorDelegations` endpoint queries all delegations of a given delegator address. - -```bash -cosmos.staking.v1beta1.Query/DelegatorDelegations -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/DelegatorDelegations -``` - -Example Output: - -```bash -{ - "delegation_responses": [ - {"delegation":{"delegator_address":"cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77","validator_address":"cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8","shares":"25083339023.000000000000000000"},"balance":{"denom":"stake","amount":"25083339023"}} - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### DelegatorUnbondingDelegations - -The `DelegatorUnbondingDelegations` endpoint queries all unbonding delegations of a given delegator address. - -```bash -cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/DelegatorUnbondingDelegations -``` - -Example Output: - -```bash -{ - "unbonding_responses": [ - { - "delegator_address": "cosmos1y8nyfvmqh50p6ldpzljk3yrglppdv3t8phju77", - "validator_address": "cosmosvaloper1sjllsnramtg3ewxqwwrwjxfgc4n4ef9uxyejze", - "entries": [ - { - "creation_height": "136984", - "completion_time": "2021-11-08T05:38:47.505593891Z", - "initial_balance": "400000000", - "balance": "400000000" - }, - { - "creation_height": "137005", - "completion_time": "2021-11-08T05:40:53.526196312Z", - "initial_balance": "385000000", - "balance": "385000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### Redelegations - -The `Redelegations` endpoint queries redelegations of given address. - -```bash -cosmos.staking.v1beta1.Query/Redelegations -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", "src_validator_addr" : "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", "dst_validator_addr" : "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/Redelegations -``` - -Example Output: - -```bash -{ - "redelegation_responses": [ - { - "redelegation": { - "delegator_address": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf", - "validator_src_address": "cosmosvaloper1j7euyj85fv2jugejrktj540emh9353ltgppc3g", - "validator_dst_address": "cosmosvaloper1yy3tnegzmkdcm7czzcy3flw5z0zyr9vkkxrfse", - "entries": null - }, - "entries": [ - { - "redelegation_entry": { - "creation_height": 135932, - "completion_time": "2021-11-08T03:52:55.299147901Z", - "initial_balance": "2900000", - "shares_dst": "2900000.000000000000000000" - }, - "balance": "2900000" - } - ] - } - ], - "pagination": null -} -``` - -### DelegatorValidators - -The `DelegatorValidators` endpoint queries all validators information for given delegator. - -```bash -cosmos.staking.v1beta1.Query/DelegatorValidators -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1ld5p7hn43yuh8ht28gm9pfjgj2fctujp2tgwvf"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidators -``` - -Example Output: - -```bash -{ - "validators": [ - { - "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "347260647559", - "delegator_shares": "347260647559.000000000000000000", - "description": { - "moniker": "BouBouNode", - "identity": "", - "website": "https://boubounode.com", - "security_contact": "", - "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.061000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.150000000000000000" - }, - "update_time": "2021-10-01T15:00:00Z" - }, - "min_self_delegation": "1" - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### DelegatorValidator - -The `DelegatorValidator` endpoint queries validator information for given delegator validator - -```bash -cosmos.staking.v1beta1.Query/DelegatorValidator -``` - -Example: - -```bash -grpcurl -plaintext \ --d '{"delegator_addr": "cosmos1eh5mwu044gd5ntkkc2xgfg8247mgc56f3n8rr7", "validator_addr": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8"}' \ -localhost:9090 cosmos.staking.v1beta1.Query/DelegatorValidator -``` - -Example Output: - -```bash -{ - "validator": { - "operator_address": "cosmosvaloper1eh5mwu044gd5ntkkc2xgfg8247mgc56fww3vc8", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "UPwHWxH1zHJWGOa/m6JB3f5YjHMvPQPkVbDqqi+U7Uw=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "347262754841", - "delegator_shares": "347262754841.000000000000000000", - "description": { - "moniker": "BouBouNode", - "identity": "", - "website": "https://boubounode.com", - "security_contact": "", - "details": "AI-based Validator. #1 AI Validator on Game of Stakes. Fairly priced. Don't trust (humans), verify. Made with BouBou love." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.061000000000000000", - "max_rate": "0.300000000000000000", - "max_change_rate": "0.150000000000000000" - }, - "update_time": "2021-10-01T15:00:00Z" - }, - "min_self_delegation": "1" - } -} -``` - -### HistoricalInfo - -```bash -cosmos.staking.v1beta1.Query/HistoricalInfo -``` - -Example: - -```bash -grpcurl -plaintext -d '{"height" : 1}' localhost:9090 cosmos.staking.v1beta1.Query/HistoricalInfo -``` - -Example Output: - -```bash -{ - "hist": { - "header": { - "version": { - "block": "11", - "app": "0" - }, - "chain_id": "simd-1", - "height": "140142", - "time": "2021-10-11T10:56:29.720079569Z", - "last_block_id": { - "hash": "9gri/4LLJUBFqioQ3NzZIP9/7YHR9QqaM6B2aJNQA7o=", - "part_set_header": { - "total": 1, - "hash": "Hk1+C864uQkl9+I6Zn7IurBZBKUevqlVtU7VqaZl1tc=" - } - }, - "last_commit_hash": "VxrcS27GtvGruS3I9+AlpT7udxIT1F0OrRklrVFSSKc=", - "data_hash": "80BjOrqNYUOkTnmgWyz9AQ8n7SoEmPVi4QmAe8RbQBY=", - "validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", - "next_validators_hash": "95W49n2hw8RWpr1GPTAO5MSPi6w6Wjr3JjjS7AjpBho=", - "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", - "app_hash": "ZZaxnSY3E6Ex5Bvkm+RigYCK82g8SSUL53NymPITeOE=", - "last_results_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", - "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", - "proposer_address": "aH6dO428B+ItuoqPq70efFHrSMY=" - }, - "valset": [ - { - "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "1426045203613", - "delegator_shares": "1426045203613.000000000000000000", - "description": { - "moniker": "SG-1", - "identity": "48608633F99D1B60", - "website": "https://sg-1.online", - "security_contact": "", - "details": "SG-1 - your favorite validator on Witval. We offer 100% Soft Slash protection." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.037500000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.030000000000000000" - }, - "update_time": "2021-10-01T15:00:00Z" - }, - "min_self_delegation": "1" - } - ] - } -} - -``` - -### Pool - -The `Pool` endpoint queries the pool information. - -```bash -cosmos.staking.v1beta1.Query/Pool -``` - -Example: - -```bash -grpcurl -plaintext -d localhost:9090 cosmos.staking.v1beta1.Query/Pool -``` - -Example Output: - -```bash -{ - "pool": { - "not_bonded_tokens": "369054400189", - "bonded_tokens": "15657192425623" - } -} -``` - -### Params - -The `Params` endpoint queries the pool information. - -```bash -cosmos.staking.v1beta1.Query/Params -``` - -Example: - -```bash -grpcurl -plaintext localhost:9090 cosmos.staking.v1beta1.Query/Params -``` - -Example Output: - -```bash -{ - "params": { - "unbondingTime": "1814400s", - "maxValidators": 100, - "maxEntries": 7, - "historicalEntries": 10000, - "bondDenom": "stake" - } -} -``` - -## REST - -A user can query the `staking` module using REST endpoints. - -### DelegatorDelegations - -The `DelegtaorDelegations` REST endpoint queries all delegations of a given delegator address. - -```bash -/cosmos/staking/v1beta1/delegations/{delegatorAddr} -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/delegations/cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "delegation_responses": [ - { - "delegation": { - "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", - "validator_address": "cosmosvaloper1quqxfrxkycr0uzt4yk0d57tcq3zk7srm7sm6r8", - "shares": "256250000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "256250000" - } - }, - { - "delegation": { - "delegator_address": "cosmos1vcs68xf2tnqes5tg0khr0vyevm40ff6zdxatp5", - "validator_address": "cosmosvaloper194v8uwee2fvs2s8fa5k7j03ktwc87h5ym39jfv", - "shares": "255150000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "255150000" - } - } - ], - "pagination": { - "next_key": null, - "total": "2" - } -} -``` - -### Redelegations - -The `Redelegations` REST endpoint queries redelegations of given address. - -```bash -/cosmos/staking/v1beta1/delegators/{delegatorAddr}/redelegations -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e/redelegations?srcValidatorAddr=cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf&dstValidatorAddr=cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "redelegation_responses": [ - { - "redelegation": { - "delegator_address": "cosmos1thfntksw0d35n2tkr0k8v54fr8wxtxwxl2c56e", - "validator_src_address": "cosmosvaloper1lzhlnpahvznwfv4jmay2tgaha5kmz5qx4cuznf", - "validator_dst_address": "cosmosvaloper1vq8tw77kp8lvxq9u3c8eeln9zymn68rng8pgt4", - "entries": null - }, - "entries": [ - { - "redelegation_entry": { - "creation_height": 151523, - "completion_time": "2021-11-09T06:03:25.640682116Z", - "initial_balance": "200000000", - "shares_dst": "200000000.000000000000000000" - }, - "balance": "200000000" - } - ] - } - ], - "pagination": null -} -``` - -### DelegatorUnbondingDelegations - -The `DelegatorUnbondingDelegations` REST endpoint queries all unbonding delegations of a given delegator address. - -```bash -/cosmos/staking/v1beta1/delegators/{delegatorAddr}/unbonding_delegations -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll/unbonding_delegations" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "unbonding_responses": [ - { - "delegator_address": "cosmos1nxv42u3lv642q0fuzu2qmrku27zgut3n3z7lll", - "validator_address": "cosmosvaloper1e7mvqlz50ch6gw4yjfemsc069wfre4qwmw53kq", - "entries": [ - { - "creation_height": "2442278", - "completion_time": "2021-10-12T10:59:03.797335857Z", - "initial_balance": "50000000000", - "balance": "50000000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### DelegatorValidators - -The `DelegatorValidators` REST endpoint queries all validators information for given delegator address. - -```bash -/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "validators": [ - { - "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "21592843799", - "delegator_shares": "21592843799.000000000000000000", - "description": { - "moniker": "jabbey", - "identity": "", - "website": "https://twitter.com/JoeAbbey", - "security_contact": "", - "details": "just another dad in the cosmos" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2021-10-09T19:03:54.984821705Z" - }, - "min_self_delegation": "1" - } - ], - "pagination": { - "next_key": null, - "total": "1" - } -} -``` - -### DelegatorValidator - -The `DelegatorValidator` REST endpoint queries validator information for given delegator validator pair. - -```bash -/cosmos/staking/v1beta1/delegators/{delegatorAddr}/validators/{validatorAddr} -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/delegators/cosmos1xwazl8ftks4gn00y5x3c47auquc62ssune9ppv/validators/cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "validator": { - "operator_address": "cosmosvaloper1xwazl8ftks4gn00y5x3c47auquc62ssuvynw64", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "5v4n3px3PkfNnKflSgepDnsMQR1hiNXnqOC11Y72/PQ=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "21592843799", - "delegator_shares": "21592843799.000000000000000000", - "description": { - "moniker": "jabbey", - "identity": "", - "website": "https://twitter.com/JoeAbbey", - "security_contact": "", - "details": "just another dad in the cosmos" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.100000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2021-10-09T19:03:54.984821705Z" - }, - "min_self_delegation": "1" - } -} -``` - -### HistoricalInfo - -The `HistoricalInfo` REST endpoint queries the historical information for given height. - -```bash -/cosmos/staking/v1beta1/historical_info/{height} -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/historical_info/153332" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "hist": { - "header": { - "version": { - "block": "11", - "app": "0" - }, - "chain_id": "cosmos-1", - "height": "153332", - "time": "2021-10-12T09:05:35.062230221Z", - "last_block_id": { - "hash": "NX8HevR5khb7H6NGKva+jVz7cyf0skF1CrcY9A0s+d8=", - "part_set_header": { - "total": 1, - "hash": "zLQ2FiKM5tooL3BInt+VVfgzjlBXfq0Hc8Iux/xrhdg=" - } - }, - "last_commit_hash": "P6IJrK8vSqU3dGEyRHnAFocoDGja0bn9euLuy09s350=", - "data_hash": "eUd+6acHWrNXYju8Js449RJ99lOYOs16KpqQl4SMrEM=", - "validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", - "next_validators_hash": "mB4pravvMsJKgi+g8aYdSeNlt0kPjnRFyvtAQtaxcfw=", - "consensus_hash": "BICRvH3cKD93v7+R1zxE2ljD34qcvIZ0Bdi389qtoi8=", - "app_hash": "fuELArKRK+CptnZ8tu54h6xEleSWenHNmqC84W866fU=", - "last_results_hash": "p/BPexV4LxAzlVcPRvW+lomgXb6Yze8YLIQUo/4Kdgc=", - "evidence_hash": "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", - "proposer_address": "G0MeY8xQx7ooOsni8KE/3R/Ib3Q=" - }, - "valset": [ - { - "operator_address": "cosmosvaloper196ax4vc0lwpxndu9dyhvca7jhxp70rmcqcnylw", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "/O7BtNW0pafwfvomgR4ZnfldwPXiFfJs9mHg3gwfv5Q=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "1416521659632", - "delegator_shares": "1416521659632.000000000000000000", - "description": { - "moniker": "SG-1", - "identity": "48608633F99D1B60", - "website": "https://sg-1.online", - "security_contact": "", - "details": "SG-1 - your favorite validator on cosmos. We offer 100% Soft Slash protection." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.037500000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.030000000000000000" - }, - "update_time": "2021-10-01T15:00:00Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1t8ehvswxjfn3ejzkjtntcyrqwvmvuknzmvtaaa", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "uExZyjNLtr2+FFIhNDAMcQ8+yTrqE7ygYTsI7khkA5Y=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "1348298958808", - "delegator_shares": "1348298958808.000000000000000000", - "description": { - "moniker": "Cosmostation", - "identity": "AE4C403A6E7AA1AC", - "website": "https://www.cosmostation.io", - "security_contact": "admin@stamper.network", - "details": "Cosmostation validator node. Delegate your tokens and Start Earning Staking Rewards" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "1.000000000000000000", - "max_change_rate": "0.200000000000000000" - }, - "update_time": "2021-10-01T15:06:38.821314287Z" - }, - "min_self_delegation": "1" - } - ] - } -} -``` - -### Parameters - -The `Parameters` REST endpoint queries the staking parameters. - -```bash -/cosmos/staking/v1beta1/params -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/params" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "params": { - "unbonding_time": "2419200s", - "max_validators": 100, - "max_entries": 7, - "historical_entries": 10000, - "bond_denom": "stake" - } -} -``` - -### Pool - -The `Pool` REST endpoint queries the pool information. - -```bash -/cosmos/staking/v1beta1/pool -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/pool" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "pool": { - "not_bonded_tokens": "432805737458", - "bonded_tokens": "15783637712645" - } -} -``` - -### Validators - -The `Validators` REST endpoint queries all validators that match the given status. - -```bash -/cosmos/staking/v1beta1/validators -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "validators": [ - { - "operator_address": "cosmosvaloper1q3jsx9dpfhtyqqgetwpe5tmk8f0ms5qywje8tw", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "N7BPyek2aKuNZ0N/8YsrqSDhGZmgVaYUBuddY8pwKaE=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "383301887799", - "delegator_shares": "383301887799.000000000000000000", - "description": { - "moniker": "SmartNodes", - "identity": "D372724899D1EDC8", - "website": "https://smartnodes.co", - "security_contact": "", - "details": "Earn Rewards with Crypto Staking & Node Deployment" - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2021-10-01T15:51:31.596618510Z" - }, - "min_self_delegation": "1" - }, - { - "operator_address": "cosmosvaloper1q5ku90atkhktze83j9xjaks2p7uruag5zp6wt7", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "GDNpuKDmCg9GnhnsiU4fCWktuGUemjNfvpCZiqoRIYA=" - }, - "jailed": false, - "status": "BOND_STATUS_UNBONDING", - "tokens": "1017819654", - "delegator_shares": "1017819654.000000000000000000", - "description": { - "moniker": "Noderunners", - "identity": "812E82D12FEA3493", - "website": "http://noderunners.biz", - "security_contact": "info@noderunners.biz", - "details": "Noderunners is a professional validator in POS networks. We have a huge node running experience, reliable soft and hardware. Our commissions are always low, our support to delegators is always full. Stake with us and start receiving your cosmos rewards now!" - }, - "unbonding_height": "147302", - "unbonding_time": "2021-11-08T22:58:53.718662452Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.100000000000000000" - }, - "update_time": "2021-10-04T18:02:21.446645619Z" - }, - "min_self_delegation": "1" - } - ], - "pagination": { - "next_key": "FONDBFkE4tEEf7yxWWKOD49jC2NK", - "total": "2" - } -} -``` - -### Validator - -The `Validator` REST endpoint queries validator information for given validator address. - -```bash -/cosmos/staking/v1beta1/validators/{validatorAddr} -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "validator": { - "operator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "consensus_pubkey": { - "@type": "/cosmos.crypto.ed25519.PubKey", - "key": "sIiexdJdYWn27+7iUHQJDnkp63gq/rzUq1Y+fxoGjXc=" - }, - "jailed": false, - "status": "BOND_STATUS_BONDED", - "tokens": "33027900000", - "delegator_shares": "33027900000.000000000000000000", - "description": { - "moniker": "Witval", - "identity": "51468B615127273A", - "website": "", - "security_contact": "", - "details": "Witval is the validator arm from Vitwit. Vitwit is into software consulting and services business since 2015. We are working closely with Cosmos ecosystem since 2018. We are also building tools for the ecosystem, Aneka is our explorer for the cosmos ecosystem." - }, - "unbonding_height": "0", - "unbonding_time": "1970-01-01T00:00:00Z", - "commission": { - "commission_rates": { - "rate": "0.050000000000000000", - "max_rate": "0.200000000000000000", - "max_change_rate": "0.020000000000000000" - }, - "update_time": "2021-10-01T19:24:52.663191049Z" - }, - "min_self_delegation": "1" - } -} -``` - -### ValidatorDelegations - -The `ValidatorDelegations` REST endpoint queries delegate information for given validator. - -```bash -/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "delegation_responses": [ - { - "delegation": { - "delegator_address": "cosmos190g5j8aszqhvtg7cprmev8xcxs6csra7xnk3n3", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "31000000000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "31000000000" - } - }, - { - "delegation": { - "delegator_address": "cosmos1ddle9tczl87gsvmeva3c48nenyng4n56qwq4ee", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "628470000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "628470000" - } - }, - { - "delegation": { - "delegator_address": "cosmos10fdvkczl76m040smd33lh9xn9j0cf26kk4s2nw", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "838120000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "838120000" - } - }, - { - "delegation": { - "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "500000000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "500000000" - } - }, - { - "delegation": { - "delegator_address": "cosmos16msryt3fqlxtvsy8u5ay7wv2p8mglfg9hrek2e", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "61310000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "61310000" - } - } - ], - "pagination": { - "next_key": null, - "total": "5" - } -} -``` - -### Delegation - -The `Delegation` REST endpoint queries delegate information for given validator delegator pair. - -```bash -/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr} -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q/delegations/cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "delegation_response": { - "delegation": { - "delegator_address": "cosmos1n8f5fknsv2yt7a8u6nrx30zqy7lu9jfm0t5lq8", - "validator_address": "cosmosvaloper16msryt3fqlxtvsy8u5ay7wv2p8mglfg9g70e3q", - "shares": "500000000.000000000000000000" - }, - "balance": { - "denom": "stake", - "amount": "500000000" - } - } -} -``` - -### UnbondingDelegation - -The `UnbondingDelegation` REST endpoint queries unbonding information for given validator delegator pair. - -```bash -/cosmos/staking/v1beta1/validators/{validatorAddr}/delegations/{delegatorAddr}/unbonding_delegation -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/delegations/cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm/unbonding_delegation" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "unbond": { - "delegator_address": "cosmos1ze2ye5u5k3qdlexvt2e0nn0508p04094ya0qpm", - "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", - "entries": [ - { - "creation_height": "153687", - "completion_time": "2021-11-09T09:41:18.352401903Z", - "initial_balance": "525111", - "balance": "525111" - } - ] - } -} -``` - -### ValidatorUnbondingDelegations - -The `ValidatorUnbondingDelegations` REST endpoint queries unbonding delegations of a validator. - -```bash -/cosmos/staking/v1beta1/validators/{validatorAddr}/unbonding_delegations -``` - -Example: - -```bash -curl -X GET \ -"http://localhost:1317/cosmos/staking/v1beta1/validators/cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu/unbonding_delegations" \ --H "accept: application/json" -``` - -Example Output: - -```bash -{ - "unbonding_responses": [ - { - "delegator_address": "cosmos1q9snn84jfrd9ge8t46kdcggpe58dua82vnj7uy", - "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", - "entries": [ - { - "creation_height": "90998", - "completion_time": "2021-11-05T00:14:37.005841058Z", - "initial_balance": "24000000", - "balance": "24000000" - } - ] - }, - { - "delegator_address": "cosmos1qf36e6wmq9h4twhdvs6pyq9qcaeu7ye0s3dqq2", - "validator_address": "cosmosvaloper13v4spsah85ps4vtrw07vzea37gq5la5gktlkeu", - "entries": [ - { - "creation_height": "47478", - "completion_time": "2021-11-01T22:47:26.714116854Z", - "initial_balance": "8000000", - "balance": "8000000" - } - ] - } - ], - "pagination": { - "next_key": null, - "total": "2" - } -} -``` diff --git a/x/staking/spec/README.md b/x/staking/spec/README.md deleted file mode 100644 index 08c21234e427..000000000000 --- a/x/staking/spec/README.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# `staking` - -## Abstract - -This paper specifies the Staking module of the Cosmos SDK that was first -described in the [Cosmos Whitepaper](https://cosmos.network/about/whitepaper) -in June 2016. - -The module enables Cosmos SDK-based blockchain to support an advanced -Proof-of-Stake (PoS) system. In this system, holders of the native staking token of -the chain can become validators and can delegate tokens to validators, -ultimately determining the effective validator set for the system. - -This module is used in the Cosmos Hub, the first Hub in the Cosmos -network. - -## Contents - -1. **[State](01_state.md)** - * [Pool](01_state.md#pool) - * [LastTotalPower](01_state.md#lasttotalpower) - * [Params](01_state.md#params) - * [Validator](01_state.md#validator) - * [Delegation](01_state.md#delegation) - * [UnbondingDelegation](01_state.md#unbondingdelegation) - * [Redelegation](01_state.md#redelegation) - * [Queues](01_state.md#queues) - * [HistoricalInfo](01_state.md#historicalinfo) -2. **[State Transitions](02_state_transitions.md)** - * [Validators](02_state_transitions.md#validators) - * [Delegations](02_state_transitions.md#delegations) - * [Slashing](02_state_transitions.md#slashing) -3. **[Messages](03_messages.md)** - * [MsgCreateValidator](03_messages.md#msgcreatevalidator) - * [MsgEditValidator](03_messages.md#msgeditvalidator) - * [MsgDelegate](03_messages.md#msgdelegate) - * [MsgUndelegate](03_messages.md#msgundelegate) - * [MsgCancelUnbondingDelegation](03_messages.md#msgcancelunbondingdelegation) - * [MsgBeginRedelegate](03_messages.md#msgbeginredelegate) -4. **[Begin-Block](04_begin_block.md)** - * [Historical Info Tracking](04_begin_block.md#historical-info-tracking) -5. **[End-Block](05_end_block.md)** - * [Validator Set Changes](05_end_block.md#validator-set-changes) - * [Queues](05_end_block.md#queues-) -6. **[Hooks](06_hooks.md)** -7. **[Events](07_events.md)** - * [EndBlocker](07_events.md#endblocker) - * [Msg's](07_events.md#msg's) -8. **[Parameters](08_params.md)** diff --git a/x/upgrade/README.md b/x/upgrade/README.md index 9363acd5c96d..beb563583562 100644 --- a/x/upgrade/README.md +++ b/x/upgrade/README.md @@ -1,7 +1,624 @@ -# Upgrade +# `x/upgrade` -* [Upgrade](spec/README.md) - Software upgrades handling and coordination. +## Abstract + +`x/upgrade` is an implementation of a Cosmos SDK module that facilitates smoothly +upgrading a live Cosmos chain to a new (breaking) software version. It accomplishes this by +providing a `BeginBlocker` hook that prevents the blockchain state machine from +proceeding once a pre-defined upgrade block height has been reached. + +The module does not prescribe anything regarding how governance decides to do an +upgrade, but just the mechanism for coordinating the upgrade safely. Without software +support for upgrades, upgrading a live chain is risky because all of the validators +need to pause their state machines at exactly the same point in the process. If +this is not done correctly, there can be state inconsistencies which are hard to +recover from. + +* [Concepts](#concepts) +* [State](#state) +* [Events](#events) +* [Client](#client) + * [CLI](#cli) + * [REST](#rest) + * [gRPC](#grpc) +* [Resources](#resources) + +# Concepts + +## Plan + +The `x/upgrade` module defines a `Plan` type in which a live upgrade is scheduled +to occur. A `Plan` can be scheduled at a specific block height. +A `Plan` is created once a (frozen) release candidate along with an appropriate upgrade +`Handler` (see below) is agreed upon, where the `Name` of a `Plan` corresponds to a +specific `Handler`. Typically, a `Plan` is created through a governance proposal +process, where if voted upon and passed, will be scheduled. The `Info` of a `Plan` +may contain various metadata about the upgrade, typically application specific +upgrade info to be included on-chain such as a git commit that validators could +automatically upgrade to. + +### Sidecar Process + +If an operator running the application binary also runs a sidecar process to assist +in the automatic download and upgrade of a binary, the `Info` allows this process to +be seamless. Namely, the `x/upgrade` module fulfills the +[cosmosd Upgradeable Binary Specification](https://github.com/regen-network/cosmosd#upgradeable-binary-specification) +specification and `cosmosd` can optionally be used to fully automate the upgrade +process for node operators. By populating the `Info` field with the necessary information, +binaries can automatically be downloaded. See [here](https://github.com/regen-network/cosmosd#auto-download) +for more info. + +```go +type Plan struct { + Name string + Height int64 + Info string +} +``` + +## Handler + +The `x/upgrade` module facilitates upgrading from major version X to major version Y. To +accomplish this, node operators must first upgrade their current binary to a new +binary that has a corresponding `Handler` for the new version Y. It is assumed that +this version has fully been tested and approved by the community at large. This +`Handler` defines what state migrations need to occur before the new binary Y +can successfully run the chain. Naturally, this `Handler` is application specific +and not defined on a per-module basis. Registering a `Handler` is done via +`Keeper#SetUpgradeHandler` in the application. + +```go +type UpgradeHandler func(Context, Plan, VersionMap) (VersionMap, error) +``` + +During each `EndBlock` execution, the `x/upgrade` module checks if there exists a +`Plan` that should execute (is scheduled at that height). If so, the corresponding +`Handler` is executed. If the `Plan` is expected to execute but no `Handler` is registered +or if the binary was upgraded too early, the node will gracefully panic and exit. + +## StoreLoader + +The `x/upgrade` module also facilitates store migrations as part of the upgrade. The +`StoreLoader` sets the migrations that need to occur before the new binary can +successfully run the chain. This `StoreLoader` is also application specific and +not defined on a per-module basis. Registering this `StoreLoader` is done via +`app#SetStoreLoader` in the application. + +```go +func UpgradeStoreLoader (upgradeHeight int64, storeUpgrades *store.StoreUpgrades) baseapp.StoreLoader +``` + +If there's a planned upgrade and the upgrade height is reached, the old binary writes `Plan` to the disk before panicking. + +This information is critical to ensure the `StoreUpgrades` happens smoothly at correct height and +expected upgrade. It eliminiates the chances for the new binary to execute `StoreUpgrades` multiple +times everytime on restart. Also if there are multiple upgrades planned on same height, the `Name` +will ensure these `StoreUpgrades` takes place only in planned upgrade handler. + +## Proposal + +Typically, a `Plan` is proposed and submitted through governance via a proposal +containing a `MsgSoftwareUpgrade` message. +This proposal prescribes to the standard governance process. If the proposal passes, +the `Plan`, which targets a specific `Handler`, is persisted and scheduled. The +upgrade can be delayed or hastened by updating the `Plan.Height` in a new proposal. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/upgrade/v1beta1/tx.proto#L24-L36 + +### Cancelling Upgrade Proposals + +Upgrade proposals can be cancelled. There exists a gov-enabled `MsgCancelUpgrade` +message type, which can be embedded in a proposal, voted on and, if passed, will +remove the scheduled upgrade `Plan`. +Of course this requires that the upgrade was known to be a bad idea well before the +upgrade itself, to allow time for a vote. + ++++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/upgrade/v1beta1/tx.proto#L43-L51 + +If such a possibility is desired, the upgrade height is to be +`2 * (VotingPeriod + DepositPeriod) + (SafetyDelta)` from the beginning of the +upgrade proposal. The `SafetyDelta` is the time available from the success of an +upgrade proposal and the realization it was a bad idea (due to external social consensus). + +A `MsgCancelUpgrade` proposal can also be made while the original +`MsgSoftwareUpgrade` proposal is still being voted upon, as long as the `VotingPeriod` +ends after the `MsgSoftwareUpgrade` proposal. + + + +# State + +The internal state of the `x/upgrade` module is relatively minimal and simple. The +state contains the currently active upgrade `Plan` (if one exists) by key +`0x0` and if a `Plan` is marked as "done" by key `0x1`. The state +contains the consensus versions of all app modules in the application. The versions +are stored as big endian `uint64`, and can be accessed with prefix `0x2` appended +by the corresponding module name of type `string`. The state maintains a +`Protocol Version` which can be accessed by key `0x3`. + +* Plan: `0x0 -> Plan` +* Done: `0x1 | byte(plan name) -> BigEndian(Block Height)` +* ConsensusVersion: `0x2 | byte(module name) -> BigEndian(Module Consensus Version)` +* ProtocolVersion: `0x3 -> BigEndian(Protocol Version)` + +The `x/upgrade` module contains no genesis state. + + + +# Events + +The `x/upgrade` does not emit any events by itself. Any and all proposal related +events are emitted through the `x/gov` module. + + + +# Client + +## CLI + +A user can query and interact with the `upgrade` module using the CLI. + +### Query + +The `query` commands allow users to query `upgrade` state. + +```bash +simd query upgrade --help +``` + +#### applied + +The `applied` command allows users to query the block header for height at which a completed upgrade was applied. + +```bash +simd query upgrade applied [upgrade-name] [flags] +``` + +If upgrade-name was previously executed on the chain, this returns the header for the block at which it was applied. +This helps a client determine which binary was valid over a given range of blocks, as well as more context to understand past migrations. + +Example: + +```bash +simd query upgrade applied "test-upgrade" +``` + +Example Output: + +```bash +"block_id": { + "hash": "A769136351786B9034A5F196DC53F7E50FCEB53B48FA0786E1BFC45A0BB646B5", + "parts": { + "total": 1, + "hash": "B13CBD23011C7480E6F11BE4594EE316548648E6A666B3575409F8F16EC6939E" + } + }, + "block_size": "7213", + "header": { + "version": { + "block": "11" + }, + "chain_id": "testnet-2", + "height": "455200", + "time": "2021-04-10T04:37:57.085493838Z", + "last_block_id": { + "hash": "0E8AD9309C2DC411DF98217AF59E044A0E1CCEAE7C0338417A70338DF50F4783", + "parts": { + "total": 1, + "hash": "8FE572A48CD10BC2CBB02653CA04CA247A0F6830FF19DC972F64D339A355E77D" + } + }, + "last_commit_hash": "DE890239416A19E6164C2076B837CC1D7F7822FC214F305616725F11D2533140", + "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", + "next_validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", + "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", + "app_hash": "28ECC486AFC332BA6CC976706DBDE87E7D32441375E3F10FD084CD4BAF0DA021", + "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", + "proposer_address": "2ABC4854B1A1C5AA8403C4EA853A81ACA901CC76" + }, + "num_txs": "0" +} +``` + +#### module versions + +The `module_versions` command gets a list of module names and their respective consensus versions. + +Following the command with a specific module name will return only +that module's information. + +```bash +simd query upgrade module_versions [optional module_name] [flags] +``` + +Example: + +```bash +simd query upgrade module_versions +``` + +Example Output: + +```bash +module_versions: +- name: auth + version: "2" +- name: authz + version: "1" +- name: bank + version: "2" +- name: capability + version: "1" +- name: crisis + version: "1" +- name: distribution + version: "2" +- name: evidence + version: "1" +- name: feegrant + version: "1" +- name: genutil + version: "1" +- name: gov + version: "2" +- name: ibc + version: "2" +- name: mint + version: "1" +- name: params + version: "1" +- name: slashing + version: "2" +- name: staking + version: "2" +- name: transfer + version: "1" +- name: upgrade + version: "1" +- name: vesting + version: "1" +``` + +Example: + +```bash +regen query upgrade module_versions ibc +``` + +Example Output: + +```bash +module_versions: +- name: ibc + version: "2" +``` + +#### plan + +The `plan` command gets the currently scheduled upgrade plan, if one exists. + +```bash +regen query upgrade plan [flags] +``` + +Example: + +```bash +simd query upgrade plan +``` + +Example Output: + +```bash +height: "130" +info: "" +name: test-upgrade +time: "0001-01-01T00:00:00Z" +upgraded_client_state: null +``` + +## REST + +A user can query the `upgrade` module using REST endpoints. + +### Applied Plan + +`AppliedPlan` queries a previously applied upgrade plan by its name. + +```bash +/cosmos/upgrade/v1beta1/applied_plan/{name} +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/applied_plan/v2.0-upgrade" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "height": "30" +} +``` + +### Current Plan + +`CurrentPlan` queries the current upgrade plan. + +```bash +/cosmos/upgrade/v1beta1/current_plan +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/current_plan" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "plan": "v2.1-upgrade" +} +``` + +### Module versions + +`ModuleVersions` queries the list of module versions from state. + +```bash +/cosmos/upgrade/v1beta1/module_versions +``` + +Example: + +```bash +curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/module_versions" -H "accept: application/json" +``` + +Example Output: + +```bash +{ + "module_versions": [ + { + "name": "auth", + "version": "2" + }, + { + "name": "authz", + "version": "1" + }, + { + "name": "bank", + "version": "2" + }, + { + "name": "capability", + "version": "1" + }, + { + "name": "crisis", + "version": "1" + }, + { + "name": "distribution", + "version": "2" + }, + { + "name": "evidence", + "version": "1" + }, + { + "name": "feegrant", + "version": "1" + }, + { + "name": "genutil", + "version": "1" + }, + { + "name": "gov", + "version": "2" + }, + { + "name": "ibc", + "version": "2" + }, + { + "name": "mint", + "version": "1" + }, + { + "name": "params", + "version": "1" + }, + { + "name": "slashing", + "version": "2" + }, + { + "name": "staking", + "version": "2" + }, + { + "name": "transfer", + "version": "1" + }, + { + "name": "upgrade", + "version": "1" + }, + { + "name": "vesting", + "version": "1" + } + ] +} +``` + +## gRPC + +A user can query the `upgrade` module using gRPC endpoints. + +### Applied Plan + +`AppliedPlan` queries a previously applied upgrade plan by its name. + +```bash +cosmos.upgrade.v1beta1.Query/AppliedPlan +``` + +Example: + +```bash +grpcurl -plaintext \ + -d '{"name":"v2.0-upgrade"}' \ + localhost:9090 \ + cosmos.upgrade.v1beta1.Query/AppliedPlan +``` + +Example Output: + +```bash +{ + "height": "30" +} +``` + +### Current Plan + +`CurrentPlan` queries the current upgrade plan. + +```bash +cosmos.upgrade.v1beta1.Query/CurrentPlan +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/CurrentPlan +``` + +Example Output: + +```bash +{ + "plan": "v2.1-upgrade" +} +``` + +### Module versions + +`ModuleVersions` queries the list of module versions from state. + +```bash +cosmos.upgrade.v1beta1.Query/ModuleVersions +``` + +Example: + +```bash +grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/ModuleVersions +``` + +Example Output: + +```bash +{ + "module_versions": [ + { + "name": "auth", + "version": "2" + }, + { + "name": "authz", + "version": "1" + }, + { + "name": "bank", + "version": "2" + }, + { + "name": "capability", + "version": "1" + }, + { + "name": "crisis", + "version": "1" + }, + { + "name": "distribution", + "version": "2" + }, + { + "name": "evidence", + "version": "1" + }, + { + "name": "feegrant", + "version": "1" + }, + { + "name": "genutil", + "version": "1" + }, + { + "name": "gov", + "version": "2" + }, + { + "name": "ibc", + "version": "2" + }, + { + "name": "mint", + "version": "1" + }, + { + "name": "params", + "version": "1" + }, + { + "name": "slashing", + "version": "2" + }, + { + "name": "staking", + "version": "2" + }, + { + "name": "transfer", + "version": "1" + }, + { + "name": "upgrade", + "version": "1" + }, + { + "name": "vesting", + "version": "1" + } + ] +} +``` + + + +# Resources + +A list of (external) resources to learn more about the `x/upgrade` module. + +* [Cosmos Dev Series: Cosmos Blockchain Upgrade](https://medium.com/web3-surfers/cosmos-dev-series-cosmos-sdk-based-blockchain-upgrade-b5e99181554c) - The blog post that explains how software upgrades work in detail. diff --git a/x/upgrade/spec/01_concepts.md b/x/upgrade/spec/01_concepts.md deleted file mode 100644 index e00d8ec37e5f..000000000000 --- a/x/upgrade/spec/01_concepts.md +++ /dev/null @@ -1,104 +0,0 @@ - - -# Concepts - -## Plan - -The `x/upgrade` module defines a `Plan` type in which a live upgrade is scheduled -to occur. A `Plan` can be scheduled at a specific block height. -A `Plan` is created once a (frozen) release candidate along with an appropriate upgrade -`Handler` (see below) is agreed upon, where the `Name` of a `Plan` corresponds to a -specific `Handler`. Typically, a `Plan` is created through a governance proposal -process, where if voted upon and passed, will be scheduled. The `Info` of a `Plan` -may contain various metadata about the upgrade, typically application specific -upgrade info to be included on-chain such as a git commit that validators could -automatically upgrade to. - -### Sidecar Process - -If an operator running the application binary also runs a sidecar process to assist -in the automatic download and upgrade of a binary, the `Info` allows this process to -be seamless. Namely, the `x/upgrade` module fulfills the -[cosmosd Upgradeable Binary Specification](https://github.com/regen-network/cosmosd#upgradeable-binary-specification) -specification and `cosmosd` can optionally be used to fully automate the upgrade -process for node operators. By populating the `Info` field with the necessary information, -binaries can automatically be downloaded. See [here](https://github.com/regen-network/cosmosd#auto-download) -for more info. - -```go -type Plan struct { - Name string - Height int64 - Info string -} -``` - -## Handler - -The `x/upgrade` module facilitates upgrading from major version X to major version Y. To -accomplish this, node operators must first upgrade their current binary to a new -binary that has a corresponding `Handler` for the new version Y. It is assumed that -this version has fully been tested and approved by the community at large. This -`Handler` defines what state migrations need to occur before the new binary Y -can successfully run the chain. Naturally, this `Handler` is application specific -and not defined on a per-module basis. Registering a `Handler` is done via -`Keeper#SetUpgradeHandler` in the application. - -```go -type UpgradeHandler func(Context, Plan, VersionMap) (VersionMap, error) -``` - -During each `EndBlock` execution, the `x/upgrade` module checks if there exists a -`Plan` that should execute (is scheduled at that height). If so, the corresponding -`Handler` is executed. If the `Plan` is expected to execute but no `Handler` is registered -or if the binary was upgraded too early, the node will gracefully panic and exit. - -## StoreLoader - -The `x/upgrade` module also facilitates store migrations as part of the upgrade. The -`StoreLoader` sets the migrations that need to occur before the new binary can -successfully run the chain. This `StoreLoader` is also application specific and -not defined on a per-module basis. Registering this `StoreLoader` is done via -`app#SetStoreLoader` in the application. - -```go -func UpgradeStoreLoader (upgradeHeight int64, storeUpgrades *store.StoreUpgrades) baseapp.StoreLoader -``` - -If there's a planned upgrade and the upgrade height is reached, the old binary writes `Plan` to the disk before panicking. - -This information is critical to ensure the `StoreUpgrades` happens smoothly at correct height and -expected upgrade. It eliminiates the chances for the new binary to execute `StoreUpgrades` multiple -times everytime on restart. Also if there are multiple upgrades planned on same height, the `Name` -will ensure these `StoreUpgrades` takes place only in planned upgrade handler. - -## Proposal - -Typically, a `Plan` is proposed and submitted through governance via a proposal -containing a `MsgSoftwareUpgrade` message. -This proposal prescribes to the standard governance process. If the proposal passes, -the `Plan`, which targets a specific `Handler`, is persisted and scheduled. The -upgrade can be delayed or hastened by updating the `Plan.Height` in a new proposal. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/upgrade/v1beta1/tx.proto#L24-L36 - -### Cancelling Upgrade Proposals - -Upgrade proposals can be cancelled. There exists a gov-enabled `MsgCancelUpgrade` -message type, which can be embedded in a proposal, voted on and, if passed, will -remove the scheduled upgrade `Plan`. -Of course this requires that the upgrade was known to be a bad idea well before the -upgrade itself, to allow time for a vote. - -+++ https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/upgrade/v1beta1/tx.proto#L43-L51 - -If such a possibility is desired, the upgrade height is to be -`2 * (VotingPeriod + DepositPeriod) + (SafetyDelta)` from the beginning of the -upgrade proposal. The `SafetyDelta` is the time available from the success of an -upgrade proposal and the realization it was a bad idea (due to external social consensus). - -A `MsgCancelUpgrade` proposal can also be made while the original -`MsgSoftwareUpgrade` proposal is still being voted upon, as long as the `VotingPeriod` -ends after the `MsgSoftwareUpgrade` proposal. diff --git a/x/upgrade/spec/02_state.md b/x/upgrade/spec/02_state.md deleted file mode 100644 index 7508b292924b..000000000000 --- a/x/upgrade/spec/02_state.md +++ /dev/null @@ -1,20 +0,0 @@ - - -# State - -The internal state of the `x/upgrade` module is relatively minimal and simple. The -state contains the currently active upgrade `Plan` (if one exists) by key -`0x0` and if a `Plan` is marked as "done" by key `0x1`. The state -contains the consensus versions of all app modules in the application. The versions -are stored as big endian `uint64`, and can be accessed with prefix `0x2` appended -by the corresponding module name of type `string`. The state maintains a -`Protocol Version` which can be accessed by key `0x3`. - -* Plan: `0x0 -> Plan` -* Done: `0x1 | byte(plan name) -> BigEndian(Block Height)` -* ConsensusVersion: `0x2 | byte(module name) -> BigEndian(Module Consensus Version)` -* ProtocolVersion: `0x3 -> BigEndian(Protocol Version)` - -The `x/upgrade` module contains no genesis state. diff --git a/x/upgrade/spec/03_events.md b/x/upgrade/spec/03_events.md deleted file mode 100644 index e4e0e6d5fc26..000000000000 --- a/x/upgrade/spec/03_events.md +++ /dev/null @@ -1,8 +0,0 @@ - - -# Events - -The `x/upgrade` does not emit any events by itself. Any and all proposal related -events are emitted through the `x/gov` module. diff --git a/x/upgrade/spec/04_client.md b/x/upgrade/spec/04_client.md deleted file mode 100644 index da55709ee712..000000000000 --- a/x/upgrade/spec/04_client.md +++ /dev/null @@ -1,459 +0,0 @@ - - -# Client - -## CLI - -A user can query and interact with the `upgrade` module using the CLI. - -### Query - -The `query` commands allow users to query `upgrade` state. - -```bash -simd query upgrade --help -``` - -#### applied - -The `applied` command allows users to query the block header for height at which a completed upgrade was applied. - -```bash -simd query upgrade applied [upgrade-name] [flags] -``` - -If upgrade-name was previously executed on the chain, this returns the header for the block at which it was applied. -This helps a client determine which binary was valid over a given range of blocks, as well as more context to understand past migrations. - -Example: - -```bash -simd query upgrade applied "test-upgrade" -``` - -Example Output: - -```bash -"block_id": { - "hash": "A769136351786B9034A5F196DC53F7E50FCEB53B48FA0786E1BFC45A0BB646B5", - "parts": { - "total": 1, - "hash": "B13CBD23011C7480E6F11BE4594EE316548648E6A666B3575409F8F16EC6939E" - } - }, - "block_size": "7213", - "header": { - "version": { - "block": "11" - }, - "chain_id": "testnet-2", - "height": "455200", - "time": "2021-04-10T04:37:57.085493838Z", - "last_block_id": { - "hash": "0E8AD9309C2DC411DF98217AF59E044A0E1CCEAE7C0338417A70338DF50F4783", - "parts": { - "total": 1, - "hash": "8FE572A48CD10BC2CBB02653CA04CA247A0F6830FF19DC972F64D339A355E77D" - } - }, - "last_commit_hash": "DE890239416A19E6164C2076B837CC1D7F7822FC214F305616725F11D2533140", - "data_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", - "validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", - "next_validators_hash": "A31047ADE54AE9072EE2A12FF260A8990BA4C39F903EAF5636B50D58DBA72582", - "consensus_hash": "048091BC7DDC283F77BFBF91D73C44DA58C3DF8A9CBC867405D8B7F3DAADA22F", - "app_hash": "28ECC486AFC332BA6CC976706DBDE87E7D32441375E3F10FD084CD4BAF0DA021", - "last_results_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", - "evidence_hash": "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855", - "proposer_address": "2ABC4854B1A1C5AA8403C4EA853A81ACA901CC76" - }, - "num_txs": "0" -} -``` - -#### module versions - -The `module_versions` command gets a list of module names and their respective consensus versions. - -Following the command with a specific module name will return only -that module's information. - -```bash -simd query upgrade module_versions [optional module_name] [flags] -``` - -Example: - -```bash -simd query upgrade module_versions -``` - -Example Output: - -```bash -module_versions: -- name: auth - version: "2" -- name: authz - version: "1" -- name: bank - version: "2" -- name: capability - version: "1" -- name: crisis - version: "1" -- name: distribution - version: "2" -- name: evidence - version: "1" -- name: feegrant - version: "1" -- name: genutil - version: "1" -- name: gov - version: "2" -- name: ibc - version: "2" -- name: mint - version: "1" -- name: params - version: "1" -- name: slashing - version: "2" -- name: staking - version: "2" -- name: transfer - version: "1" -- name: upgrade - version: "1" -- name: vesting - version: "1" -``` - -Example: - -```bash -regen query upgrade module_versions ibc -``` - -Example Output: - -```bash -module_versions: -- name: ibc - version: "2" -``` - -#### plan - -The `plan` command gets the currently scheduled upgrade plan, if one exists. - -```bash -regen query upgrade plan [flags] -``` - -Example: - -```bash -simd query upgrade plan -``` - -Example Output: - -```bash -height: "130" -info: "" -name: test-upgrade -time: "0001-01-01T00:00:00Z" -upgraded_client_state: null -``` - -## REST - -A user can query the `upgrade` module using REST endpoints. - -### Applied Plan - -`AppliedPlan` queries a previously applied upgrade plan by its name. - -```bash -/cosmos/upgrade/v1beta1/applied_plan/{name} -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/applied_plan/v2.0-upgrade" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "height": "30" -} -``` - -### Current Plan - -`CurrentPlan` queries the current upgrade plan. - -```bash -/cosmos/upgrade/v1beta1/current_plan -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/current_plan" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "plan": "v2.1-upgrade" -} -``` - -### Module versions - -`ModuleVersions` queries the list of module versions from state. - -```bash -/cosmos/upgrade/v1beta1/module_versions -``` - -Example: - -```bash -curl -X GET "http://localhost:1317/cosmos/upgrade/v1beta1/module_versions" -H "accept: application/json" -``` - -Example Output: - -```bash -{ - "module_versions": [ - { - "name": "auth", - "version": "2" - }, - { - "name": "authz", - "version": "1" - }, - { - "name": "bank", - "version": "2" - }, - { - "name": "capability", - "version": "1" - }, - { - "name": "crisis", - "version": "1" - }, - { - "name": "distribution", - "version": "2" - }, - { - "name": "evidence", - "version": "1" - }, - { - "name": "feegrant", - "version": "1" - }, - { - "name": "genutil", - "version": "1" - }, - { - "name": "gov", - "version": "2" - }, - { - "name": "ibc", - "version": "2" - }, - { - "name": "mint", - "version": "1" - }, - { - "name": "params", - "version": "1" - }, - { - "name": "slashing", - "version": "2" - }, - { - "name": "staking", - "version": "2" - }, - { - "name": "transfer", - "version": "1" - }, - { - "name": "upgrade", - "version": "1" - }, - { - "name": "vesting", - "version": "1" - } - ] -} -``` - -## gRPC - -A user can query the `upgrade` module using gRPC endpoints. - -### Applied Plan - -`AppliedPlan` queries a previously applied upgrade plan by its name. - -```bash -cosmos.upgrade.v1beta1.Query/AppliedPlan -``` - -Example: - -```bash -grpcurl -plaintext \ - -d '{"name":"v2.0-upgrade"}' \ - localhost:9090 \ - cosmos.upgrade.v1beta1.Query/AppliedPlan -``` - -Example Output: - -```bash -{ - "height": "30" -} -``` - -### Current Plan - -`CurrentPlan` queries the current upgrade plan. - -```bash -cosmos.upgrade.v1beta1.Query/CurrentPlan -``` - -Example: - -```bash -grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/CurrentPlan -``` - -Example Output: - -```bash -{ - "plan": "v2.1-upgrade" -} -``` - -### Module versions - -`ModuleVersions` queries the list of module versions from state. - -```bash -cosmos.upgrade.v1beta1.Query/ModuleVersions -``` - -Example: - -```bash -grpcurl -plaintext localhost:9090 cosmos.slashing.v1beta1.Query/ModuleVersions -``` - -Example Output: - -```bash -{ - "module_versions": [ - { - "name": "auth", - "version": "2" - }, - { - "name": "authz", - "version": "1" - }, - { - "name": "bank", - "version": "2" - }, - { - "name": "capability", - "version": "1" - }, - { - "name": "crisis", - "version": "1" - }, - { - "name": "distribution", - "version": "2" - }, - { - "name": "evidence", - "version": "1" - }, - { - "name": "feegrant", - "version": "1" - }, - { - "name": "genutil", - "version": "1" - }, - { - "name": "gov", - "version": "2" - }, - { - "name": "ibc", - "version": "2" - }, - { - "name": "mint", - "version": "1" - }, - { - "name": "params", - "version": "1" - }, - { - "name": "slashing", - "version": "2" - }, - { - "name": "staking", - "version": "2" - }, - { - "name": "transfer", - "version": "1" - }, - { - "name": "upgrade", - "version": "1" - }, - { - "name": "vesting", - "version": "1" - } - ] -} -``` diff --git a/x/upgrade/spec/05_resources.md b/x/upgrade/spec/05_resources.md deleted file mode 100644 index 7652ca7cc40f..000000000000 --- a/x/upgrade/spec/05_resources.md +++ /dev/null @@ -1,9 +0,0 @@ - - -# Resources - -A list of (external) resources to learn more about the `x/upgrade` module. - -- [Cosmos Dev Series: Cosmos Blockchain Upgrade](https://medium.com/web3-surfers/cosmos-dev-series-cosmos-sdk-based-blockchain-upgrade-b5e99181554c) - The blog post that explains how software upgrades work in detail. \ No newline at end of file diff --git a/x/upgrade/spec/README.md b/x/upgrade/spec/README.md deleted file mode 100644 index 3fa09906eabd..000000000000 --- a/x/upgrade/spec/README.md +++ /dev/null @@ -1,32 +0,0 @@ - - -# `upgrade` - -## Abstract - -`x/upgrade` is an implementation of a Cosmos SDK module that facilitates smoothly -upgrading a live Cosmos chain to a new (breaking) software version. It accomplishes this by -providing a `BeginBlocker` hook that prevents the blockchain state machine from -proceeding once a pre-defined upgrade block height has been reached. - -The module does not prescribe anything regarding how governance decides to do an -upgrade, but just the mechanism for coordinating the upgrade safely. Without software -support for upgrades, upgrading a live chain is risky because all of the validators -need to pause their state machines at exactly the same point in the process. If -this is not done correctly, there can be state inconsistencies which are hard to -recover from. - - -1. **[Concepts](01_concepts.md)** -2. **[State](02_state.md)** -3. **[Events](03_events.md)** -4. **[Client](04_client.md)** - * [CLI](04_client.md#cli) - * [REST](04_client.md#rest) - * [gRPC](04_client.md#grpc) -5. **[Resources](05_resources.md)** From de436c231d3b0379e1ee8704826c916ac3909afc Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 5 Sep 2022 15:46:30 +0200 Subject: [PATCH 17/24] ci: add `csplit` for documetation building (#13154) --- .github/workflows/deploy-docs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 68e90124acba..4ae01c38a90a 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -9,6 +9,7 @@ on: paths: - "docs/**" - "x/**/*.md" + - .github/workflows/deploy-docs.yml permissions: contents: read @@ -29,7 +30,7 @@ jobs: - name: Install and Build πŸ”§ run: | - apk add rsync + apk add rsync csplit make build-docs LEDGER_ENABLED=false - name: Deploy πŸš€ From 8579bdd17ea8d46db5b09124b55ed46279c7d2a5 Mon Sep 17 00:00:00 2001 From: Rano | Ranadeep Date: Mon, 5 Sep 2022 16:02:43 +0200 Subject: [PATCH 18/24] feat: List HRP prefixes in Bech32 addresses (#13064) --- CHANGELOG.md | 1 + client/debug/main.go | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ef913933cb..3105c7fcc88c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (testutil) [#12973](https://github.com/cosmos/cosmos-sdk/pull/12973) Add generic `testutil.RandSliceElem` function which selects a random element from the list. * (client) [#12936](https://github.com/cosmos/cosmos-sdk/pull/12936) Add capability to preprocess transactions before broadcasting from a higher level chain. * (x/authz) [#13047](https://github.com/cosmos/cosmos-sdk/pull/13047) Add a GetAuthorization function to the keeper. +* (cli) [#13064](https://github.com/cosmos/cosmos-sdk/pull/13064) Add `debug prefixes` to list supported HRP prefixes via . * (cli) [#12742](https://github.com/cosmos/cosmos-sdk/pull/12742) Add the `prune` CLI cmd to manually prune app store history versions based on the pruning options. ### Improvements diff --git a/client/debug/main.go b/client/debug/main.go index df21d31c82b7..645e6fe36ee8 100644 --- a/client/debug/main.go +++ b/client/debug/main.go @@ -37,6 +37,7 @@ func Cmd() *cobra.Command { cmd.AddCommand(PubkeyRawCmd()) cmd.AddCommand(AddrCmd()) cmd.AddCommand(RawBytesCmd()) + cmd.AddCommand(PrefixesCmd()) return cmd } @@ -257,3 +258,18 @@ $ %s debug raw-bytes [72 101 108 108 111 44 32 112 108 97 121 103 114 111 117 11 }, } } + +func PrefixesCmd() *cobra.Command { + return &cobra.Command{ + Use: "prefixes", + Short: "List prefixes used for Human-Readable Part (HRP) in Bech32", + Long: "List prefixes used in Bech32 addresses.", + Example: fmt.Sprintf("$ %s debug prefixes", version.AppName), + RunE: func(cmd *cobra.Command, args []string) error { + cmd.Printf("Bech32 Acc: %s\n", sdk.GetConfig().GetBech32AccountAddrPrefix()) + cmd.Printf("Bech32 Val: %s\n", sdk.GetConfig().GetBech32ValidatorAddrPrefix()) + cmd.Printf("Bech32 Con: %s\n", sdk.GetConfig().GetBech32ConsensusAddrPrefix()) + return nil + }, + } +} From 2efee04e4fe44a57f7cf99d9d4b300566432475e Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Mon, 5 Sep 2022 20:01:30 +0530 Subject: [PATCH 19/24] refactor(group): CLI tests using Tendermint Mock (#13067) --- .../group/{client/testutil => }/cli_test.go | 5 +- .../testutil => tests/e2e/group}/query.go | 2 +- .../client/testutil => tests/e2e/group}/tx.go | 2 +- x/group/client/cli/tx_test.go | 1838 +++++++++++++++++ 4 files changed, 1842 insertions(+), 5 deletions(-) rename tests/e2e/group/{client/testutil => }/cli_test.go (67%) rename {x/group/client/testutil => tests/e2e/group}/query.go (99%) rename {x/group/client/testutil => tests/e2e/group}/tx.go (99%) create mode 100644 x/group/client/cli/tx_test.go diff --git a/tests/e2e/group/client/testutil/cli_test.go b/tests/e2e/group/cli_test.go similarity index 67% rename from tests/e2e/group/client/testutil/cli_test.go rename to tests/e2e/group/cli_test.go index fc26405b7c79..029b52615516 100644 --- a/tests/e2e/group/client/testutil/cli_test.go +++ b/tests/e2e/group/cli_test.go @@ -1,14 +1,13 @@ //go:build e2e // +build e2e -package testutil +package group import ( "testing" "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/testutil/network" - clienttestutil "github.com/cosmos/cosmos-sdk/x/group/client/testutil" "github.com/stretchr/testify/suite" ) @@ -16,5 +15,5 @@ import ( func TestIntegrationTestSuite(t *testing.T) { cfg := network.DefaultConfig(simapp.NewTestNetworkFixture) cfg.NumValidators = 2 - suite.Run(t, clienttestutil.NewIntegrationTestSuite(cfg)) + suite.Run(t, NewIntegrationTestSuite(cfg)) } diff --git a/x/group/client/testutil/query.go b/tests/e2e/group/query.go similarity index 99% rename from x/group/client/testutil/query.go rename to tests/e2e/group/query.go index 74c152b50978..306d62bb8140 100644 --- a/x/group/client/testutil/query.go +++ b/tests/e2e/group/query.go @@ -1,4 +1,4 @@ -package testutil +package group import ( "fmt" diff --git a/x/group/client/testutil/tx.go b/tests/e2e/group/tx.go similarity index 99% rename from x/group/client/testutil/tx.go rename to tests/e2e/group/tx.go index fb606d223e57..b123fde6e31d 100644 --- a/x/group/client/testutil/tx.go +++ b/tests/e2e/group/tx.go @@ -1,4 +1,4 @@ -package testutil +package group import ( "encoding/base64" diff --git a/x/group/client/cli/tx_test.go b/x/group/client/cli/tx_test.go new file mode 100644 index 000000000000..55e3c39a669c --- /dev/null +++ b/x/group/client/cli/tx_test.go @@ -0,0 +1,1838 @@ +package cli_test + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + tmbytes "github.com/tendermint/tendermint/libs/bytes" + rpcclient "github.com/tendermint/tendermint/rpc/client" + rpcclientmock "github.com/tendermint/tendermint/rpc/client/mock" + coretypes "github.com/tendermint/tendermint/rpc/core/types" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/crypto/hd" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + testutilmod "github.com/cosmos/cosmos-sdk/types/module/testutil" + "github.com/cosmos/cosmos-sdk/x/group" + groupcli "github.com/cosmos/cosmos-sdk/x/group/client/cli" + groupmodule "github.com/cosmos/cosmos-sdk/x/group/module" +) + +const validMetadata = "metadata" + +var tooLongMetadata = strings.Repeat("A", 256) + +var _ client.TendermintRPC = (*mockTendermintRPC)(nil) + +type mockTendermintRPC struct { + rpcclientmock.Client + + responseQuery abci.ResponseQuery +} + +func newMockTendermintRPC(respQuery abci.ResponseQuery) mockTendermintRPC { + return mockTendermintRPC{responseQuery: respQuery} +} + +func (_ mockTendermintRPC) BroadcastTxCommit(_ context.Context, _ tmtypes.Tx) (*coretypes.ResultBroadcastTxCommit, error) { + return &coretypes.ResultBroadcastTxCommit{}, nil +} + +func (m mockTendermintRPC) ABCIQueryWithOptions( + _ context.Context, + _ string, _ tmbytes.HexBytes, + _ rpcclient.ABCIQueryOptions, +) (*coretypes.ResultABCIQuery, error) { + return &coretypes.ResultABCIQuery{Response: m.responseQuery}, nil +} + +type CLITestSuite struct { + suite.Suite + + kr keyring.Keyring + encCfg testutilmod.TestEncodingConfig + baseCtx client.Context + + group *group.GroupInfo + commonFlags []string +} + +func TestCLITestSuite(t *testing.T) { + suite.Run(t, new(CLITestSuite)) +} + +func (s *CLITestSuite) SetupSuite() { + s.encCfg = testutilmod.MakeTestEncodingConfig(groupmodule.AppModuleBasic{}) + s.kr = keyring.NewInMemory(s.encCfg.Codec) + s.baseCtx = client.Context{}. + WithKeyring(s.kr). + WithTxConfig(s.encCfg.TxConfig). + WithCodec(s.encCfg.Codec). + WithClient(mockTendermintRPC{Client: rpcclientmock.Client{}}). + WithAccountRetriever(client.MockAccountRetriever{}). + WithOutput(io.Discard). + WithChainID("test-chain") + + s.commonFlags = []string{ + fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))).String()), + } + + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + val := accounts[0] + + var outBuf bytes.Buffer + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + } + clientCtx := ctxGen().WithOutput(&outBuf) + + // create a new account + info, _, err := clientCtx.Keyring.NewMnemonic("NewValidator", keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1) + s.Require().NoError(err) + + pk, err := info.GetPubKey() + s.Require().NoError(err) + + account := sdk.AccAddress(pk.Address()) + _, err = cli.MsgSendExec( + clientCtx, + val.Address, + account, + sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(2000))), fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation), + fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock), + fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(10))).String()), + ) + s.Require().NoError(err) + + memberWeight := "3" + // create a group + validMembers := fmt.Sprintf(` + { + "members": [ + { + "address": "%s", + "weight": "%s", + "metadata": "%s" + } + ] + }`, val.Address.String(), memberWeight, validMetadata) + validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) + out, err := cli.ExecTestCLICmd(clientCtx, groupcli.MsgCreateGroupCmd(), + append( + []string{ + val.Address.String(), + validMetadata, + validMembersFile.Name(), + }, + s.commonFlags..., + ), + ) + + s.Require().NoError(err, out.String()) + txResp := sdk.TxResponse{} + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &txResp), out.String()) + s.Require().Equal(uint32(0), txResp.Code, out.String()) + + s.group = &group.GroupInfo{Id: 1, Admin: val.Address.String(), Metadata: validMetadata, TotalWeight: "3", Version: 1} +} + +func (s *CLITestSuite) TestTxCreateGroup() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + cmd := groupcli.MsgCreateGroupCmd() + cmd.SetOutput(io.Discard) + + validMembers := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "1", + "metadata": "%s" + }]}`, accounts[0].Address.String(), validMetadata) + validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) + + invalidMembersAddress := `{"members": [{ + "address": "", + "weight": "1" + }]}` + invalidMembersAddressFile := testutil.WriteToNewTempFile(s.T(), invalidMembersAddress) + + invalidMembersWeight := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "0" + }]}`, accounts[0].Address.String()) + invalidMembersWeightFile := testutil.WriteToNewTempFile(s.T(), invalidMembersWeight) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + respType proto.Message + expCmdOutput string + expectErr bool + expectErrMsg string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "", + validMembersFile.Name(), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "", validMembersFile.Name()), + false, + "", + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "", + validMembersFile.Name(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "", validMembersFile.Name()), + false, + "", + }, + { + "invalid members address", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "null", + invalidMembersAddressFile.Name(), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "null", invalidMembersAddressFile.Name()), + true, + "message validation failed: address: empty address string is not allowed", + }, + { + "invalid members weight", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "null", + invalidMembersWeightFile.Name(), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "null", invalidMembersWeightFile.Name()), + true, + "expected a positive decimal, got 0: invalid decimal string", + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(out.String(), tc.expectErrMsg) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *CLITestSuite) TestTxUpdateGroupAdmin() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) + + cmd := groupcli.MsgUpdateGroupAdminCmd() + cmd.SetOutput(io.Discard) + + var outBuf bytes.Buffer + + ctxGen := func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + } + clientCtx := ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + groupIDs := make([]string, 2) + for i := 0; i < 2; i++ { + validMembers := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "1", + "metadata": "%s" + }]}`, accounts[0].Address.String(), validMetadata) + validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) + out, err := cli.ExecTestCLICmd(clientCtx, groupcli.MsgCreateGroupCmd(), + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMembersFile.Name(), + }, + s.commonFlags..., + ), + ) + s.Require().NoError(err, out.String()) + groupIDs[i] = fmt.Sprintf("%d", i+1) + } + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + respType proto.Message + expCmdOutput string + expectErr bool + expectErrMsg string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + groupIDs[0], + accounts[1].Address.String(), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), groupIDs[0], accounts[1].Address.String()), + false, + "", + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + groupIDs[1], + accounts[1].Address.String(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s --%s=%s", accounts[0].Address.String(), groupIDs[1], accounts[1].Address.String(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + false, + "", + }, + { + "group id invalid", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "", + accounts[1].Address.String(), + }, + s.commonFlags..., + ), + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "", accounts[1].Address.String()), + true, + "strconv.ParseUint: parsing \"\": invalid syntax", + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(out.String(), tc.expectErrMsg) + } else { + s.Require().NoError(err) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *CLITestSuite) TestTxUpdateGroupMetadata() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + cmd := groupcli.MsgUpdateGroupMetadataCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "1", + validMetadata, + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "1", validMetadata), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "1", + validMetadata, + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s --%s=%s", accounts[0].Address.String(), "1", validMetadata, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "group metadata too long", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + strconv.FormatUint(s.group.Id, 10), + strings.Repeat("a", 256), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), strconv.FormatUint(s.group.Id, 10), strings.Repeat("a", 256)), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxUpdateGroupMembers() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 3) + groupPolicyAddress := accounts[2] + + cmd := groupcli.MsgUpdateGroupMembersCmd() + cmd.SetOutput(io.Discard) + + groupID := "1" + + validUpdatedMembersFileName := testutil.WriteToNewTempFile(s.T(), fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "0", + "metadata": "%s" + }, { + "address": "%s", + "weight": "1", + "metadata": "%s" + }]}`, accounts[1], validMetadata, groupPolicyAddress, validMetadata)).Name() + + invalidMembersMetadata := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "1", + "metadata": "%s" + }]}`, accounts[1], tooLongMetadata) + invalidMembersMetadataFileName := testutil.WriteToNewTempFile(s.T(), invalidMembersMetadata).Name() + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + groupID, + validUpdatedMembersFileName, + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), groupID, validUpdatedMembersFileName), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + groupID, + validUpdatedMembersFileName, + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s --%s=%s", accounts[0].Address.String(), groupID, validUpdatedMembersFileName, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "group member metadata too long", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + groupID, + invalidMembersMetadataFileName, + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), groupID, invalidMembersMetadataFileName), + }, + { + "group doesn't exist", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + "12345", + validUpdatedMembersFileName, + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", accounts[0].Address.String(), "12345", validUpdatedMembersFileName), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxCreateGroupWithPolicy() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + cmd := groupcli.MsgCreateGroupWithPolicyCmd() + cmd.SetOutput(io.Discard) + + validMembers := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "1", + "metadata": "%s" + }]}`, accounts[0].Address.String(), validMetadata) + validMembersFile := testutil.WriteToNewTempFile(s.T(), validMembers) + + invalidMembersAddress := `{"members": [{ + "address": "", + "weight": "1" + }]}` + invalidMembersAddressFile := testutil.WriteToNewTempFile(s.T(), invalidMembersAddress) + + invalidMembersWeight := fmt.Sprintf(`{"members": [{ + "address": "%s", + "weight": "0" + }]}`, accounts[0].Address.String()) + invalidMembersWeightFile := testutil.WriteToNewTempFile(s.T(), invalidMembersWeight) + + thresholdDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type": "/cosmos.group.v1.ThresholdDecisionPolicy","threshold": "1","windows": {"voting_period":"1s"}}`) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectErr bool + expectErrMsg string + respType proto.Message + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMetadata, + validMembersFile.Name(), + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s %s --%s=%v", accounts[0].Address.String(), validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false), + }, + { + "group-policy-as-admin is true", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMetadata, + validMembersFile.Name(), + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, true), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s %s --%s=%v", accounts[0].Address.String(), validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, true), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMetadata, + validMembersFile.Name(), + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s %s --%s=%v --%s=%s", accounts[0].Address.String(), validMetadata, validMetadata, validMembersFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "invalid members address", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMetadata, + invalidMembersAddressFile.Name(), + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), + }, + s.commonFlags..., + ), + true, + "message validation failed: address: empty address string is not allowed", + nil, + fmt.Sprintf("%s %s %s %s %s --%s=%v", accounts[0].Address.String(), validMetadata, validMetadata, invalidMembersAddressFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false), + }, + { + "invalid members weight", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + accounts[0].Address.String(), + validMetadata, + validMetadata, + invalidMembersWeightFile.Name(), + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%v", groupcli.FlagGroupPolicyAsAdmin, false), + }, + s.commonFlags..., + ), + true, + "expected a positive decimal, got 0: invalid decimal string", + nil, + fmt.Sprintf("%s %s %s %s %s --%s=%v", accounts[0].Address.String(), validMetadata, validMetadata, invalidMembersWeightFile.Name(), thresholdDecisionPolicyFile.Name(), groupcli.FlagGroupPolicyAsAdmin, false), + }, + } + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(out.String(), tc.expectErrMsg) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *CLITestSuite) TestTxCreateGroupPolicy() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) + val := accounts[0] + + groupID := s.group.Id + + thresholdDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type": "/cosmos.group.v1.ThresholdDecisionPolicy","threshold": "1","windows": {"voting_period":"1s"}}`) + + percentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "windows":{"voting_period":"1s"}}`) + invalidNegativePercentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"-0.5", "windows":{"voting_period":"1s"}}`) + invalidPercentageDecisionPolicyFile := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"2", "windows":{"voting_period":"1s"}}`) + + cmd := groupcli.MsgCreateGroupPolicyCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expectErr bool + expectErrMsg string + respType proto.Message + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + val.Address.String(), + fmt.Sprintf("%v", groupID), + validMetadata, + thresholdDecisionPolicyFile.Name(), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s", val.Address.String(), fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name()), + }, + { + "correct data with percentage decision policy", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + val.Address.String(), + fmt.Sprintf("%v", groupID), + validMetadata, + percentageDecisionPolicyFile.Name(), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s", val.Address.String(), fmt.Sprintf("%v", groupID), validMetadata, percentageDecisionPolicyFile.Name()), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + val.Address.String(), + fmt.Sprintf("%v", groupID), + validMetadata, + thresholdDecisionPolicyFile.Name(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + false, + "", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s --%s=%s", val.Address.String(), fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "wrong admin", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + "wrongAdmin", + fmt.Sprintf("%v", groupID), + validMetadata, + thresholdDecisionPolicyFile.Name(), + }, + s.commonFlags..., + ), + true, + "key not found", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s", "wrongAdmin", fmt.Sprintf("%v", groupID), validMetadata, thresholdDecisionPolicyFile.Name()), + }, + { + "invalid percentage decision policy with negative value", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + val.Address.String(), + fmt.Sprintf("%v", groupID), + validMetadata, + invalidNegativePercentageDecisionPolicyFile.Name(), + }, + s.commonFlags..., + ), + true, + "expected a positive decimal", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s", val.Address.String(), fmt.Sprintf("%v", groupID), validMetadata, invalidNegativePercentageDecisionPolicyFile.Name()), + }, + { + "invalid percentage decision policy with value greater than 1", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + val.Address.String(), + fmt.Sprintf("%v", groupID), + validMetadata, + invalidPercentageDecisionPolicyFile.Name(), + }, + s.commonFlags..., + ), + true, + "percentage must be > 0 and <= 1", + &sdk.TxResponse{}, + fmt.Sprintf("%s %s %s %s", val.Address.String(), fmt.Sprintf("%v", groupID), validMetadata, invalidPercentageDecisionPolicyFile.Name()), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + + out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + s.Require().Contains(out.String(), tc.expectErrMsg) + } else { + s.Require().NoError(err, out.String()) + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), tc.respType), out.String()) + } + }) + } +} + +func (s *CLITestSuite) TestTxUpdateGroupPolicyAdmin() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 4) + newAdmin := accounts[0] + groupPolicyAdmin := accounts[1] + groupPolicyAddress := accounts[2] + + commonFlags := s.commonFlags + commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000)) + + cmd := groupcli.MsgUpdateGroupPolicyAdminCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + newAdmin.Address.String(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), newAdmin.Address.String()), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + newAdmin.Address.String(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), newAdmin.Address.String(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "wrong admin", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + "wrong admin", + groupPolicyAddress.Address.String(), + newAdmin.Address.String(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", "wrong admin", groupPolicyAddress.Address.String(), newAdmin.Address.String()), + }, + { + "wrong group policy", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + "wrong group policy", + newAdmin.Address.String(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), "wrong group policy", newAdmin.Address.String()), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxUpdateGroupPolicyDecisionPolicy() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 3) + newAdmin := accounts[0] + groupPolicyAdmin := accounts[1] + groupPolicyAddress := accounts[2] + + commonFlags := s.commonFlags + commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000)) + + thresholdDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows":{"voting_period":"40000s"}}`) + percentageDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "windows":{"voting_period":"40000s"}}`) + invalidNegativePercentageDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"-0.5", "windows":{"voting_period":"1s"}}`) + invalidPercentageDecisionPolicy := testutil.WriteToNewTempFile(s.T(), `{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"2", "windows":{"voting_period":"40000s"}}`) + + cmd := groupcli.MsgUpdateGroupPolicyDecisionPolicyCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + thresholdDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), thresholdDecisionPolicy.Name()), + }, + { + "correct data with percentage decision policy", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + percentageDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), percentageDecisionPolicy.Name()), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + thresholdDecisionPolicy.Name(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), thresholdDecisionPolicy.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "wrong admin", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + newAdmin.Address.String(), + groupPolicyAddress.Address.String(), + thresholdDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", newAdmin.Address.String(), groupPolicyAddress.Address.String(), thresholdDecisionPolicy.Name()), + }, + { + "wrong group policy", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + "wrong group policy", + thresholdDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), "wrong group policy", thresholdDecisionPolicy.Name()), + }, + { + "invalid percentage decision policy with negative value", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + invalidNegativePercentageDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), invalidNegativePercentageDecisionPolicy.Name()), + }, + { + "invalid percentage decision policy with value greater than 1", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.Address.String(), + groupPolicyAddress.Address.String(), + invalidPercentageDecisionPolicy.Name(), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.Address.String(), groupPolicyAddress.Address.String(), invalidPercentageDecisionPolicy.Name()), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } + +} + +func (s *CLITestSuite) TestTxUpdateGroupPolicyMetadata() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) + groupPolicyAdmin := accounts[0].Address + groupPolicyAddress := accounts[1].Address + + commonFlags := s.commonFlags + commonFlags = append(commonFlags, fmt.Sprintf("--%s=%d", flags.FlagGas, 300000)) + + cmd := groupcli.MsgUpdateGroupPolicyMetadataCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.String(), + groupPolicyAddress.String(), + validMetadata, + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.String(), groupPolicyAddress.String(), validMetadata), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.String(), + groupPolicyAddress.String(), + validMetadata, + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s --%s=%s", groupPolicyAdmin.String(), groupPolicyAddress.String(), validMetadata, flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "long metadata", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.String(), + groupPolicyAddress.String(), + strings.Repeat("a", 500), + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.String(), groupPolicyAddress.String(), strings.Repeat("a", 500)), + }, + { + "wrong admin", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + "wrong admin", + groupPolicyAddress.String(), + validMetadata, + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", "wrong admin", groupPolicyAddress.String(), validMetadata), + }, + { + "wrong group policy", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + groupPolicyAdmin.String(), + "wrong group policy", + validMetadata, + }, + commonFlags..., + ), + fmt.Sprintf("%s %s %s", groupPolicyAdmin.String(), "wrong group policy", validMetadata), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxSubmitProposal() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 2) + groupPolicyAddress := accounts[1].Address + + p := groupcli.Proposal{ + GroupPolicyAddress: groupPolicyAddress.String(), + Messages: []json.RawMessage{}, + Metadata: validMetadata, + Proposers: []string{accounts[0].Address.String()}, + } + bz, err := json.Marshal(&p) + s.Require().NoError(err) + proposalFile := testutil.WriteToNewTempFile(s.T(), string(bz)) + + cmd := groupcli.MsgSubmitProposalCmd() + cmd.SetOutput(io.Discard) + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + proposalFile.Name(), + }, + s.commonFlags..., + ), + proposalFile.Name(), + }, + { + "with try exec", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + proposalFile.Name(), + fmt.Sprintf("--%s=try", groupcli.FlagExec), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s --%s=try", proposalFile.Name(), groupcli.FlagExec), + }, + { + "with try exec, not enough yes votes for proposal to pass", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + proposalFile.Name(), + fmt.Sprintf("--%s=try", groupcli.FlagExec), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s --%s=try", proposalFile.Name(), groupcli.FlagExec), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + proposalFile.Name(), + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s --%s=%s", proposalFile.Name(), flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxVote() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 4) + + cmd := groupcli.MsgVoteCmd() + cmd.SetOutput(io.Discard) + + ids := make([]string, 4) + for i := 0; i < len(ids); i++ { + ids[i] = fmt.Sprint(i + 1) + } + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[0], + accounts[0].Address.String(), + "VOTE_OPTION_YES", + "", + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s", ids[0], accounts[0].Address.String(), "VOTE_OPTION_YES"), + }, + { + "with try exec", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[1], + accounts[0].Address.String(), + "VOTE_OPTION_YES", + "", + fmt.Sprintf("--%s=try", groupcli.FlagExec), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s %s --%s=try", ids[1], accounts[0].Address.String(), "VOTE_OPTION_YES", "", groupcli.FlagExec), + }, + { + "with amino-json", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[3], + accounts[0].Address.String(), + "VOTE_OPTION_YES", + "", + fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s %s --%s=%s", ids[3], accounts[0].Address.String(), "VOTE_OPTION_YES", "", flags.FlagSignMode, flags.SignModeLegacyAminoJSON), + }, + { + "metadata too long", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[2], + accounts[0].Address.String(), + "VOTE_OPTION_YES", + tooLongMetadata, + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s %s %s", ids[2], accounts[0].Address.String(), "VOTE_OPTION_YES", tooLongMetadata), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} + +func (s *CLITestSuite) TestTxWithdrawProposal() { + accounts := testutil.CreateKeyringAccounts(s.T(), s.kr, 1) + + cmd := groupcli.MsgWithdrawProposalCmd() + cmd.SetOutput(io.Discard) + + ids := make([]string, 2) + ids[0] = "1" + ids[1] = "2" + + testCases := []struct { + name string + ctxGen func() client.Context + args []string + expCmdOutput string + }{ + { + "correct data", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[0], + accounts[0].Address.String(), + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s", ids[0], accounts[0].Address.String()), + }, + { + "wrong admin", + func() client.Context { + bz, _ := s.encCfg.Codec.Marshal(&sdk.TxResponse{}) + c := newMockTendermintRPC(abci.ResponseQuery{ + Value: bz, + }) + return s.baseCtx.WithClient(c) + }, + append( + []string{ + ids[1], + "wrongAdmin", + }, + s.commonFlags..., + ), + fmt.Sprintf("%s %s", ids[1], "wrongAdmin"), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + + var outBuf bytes.Buffer + + clientCtx := tc.ctxGen().WithOutput(&outBuf) + ctx := svrcmd.CreateExecuteContext(context.Background()) + + cmd.SetContext(ctx) + cmd.SetArgs(tc.args) + + s.Require().NoError(client.SetCmdClientContextHandler(clientCtx, cmd)) + + if len(tc.args) != 0 { + s.Require().Contains(fmt.Sprint(cmd), tc.expCmdOutput) + } + }) + } +} From 65fff07a34c9ac1320cc98dfca83fdc91cd03cc1 Mon Sep 17 00:00:00 2001 From: Sai Kumar <17549398+gsk967@users.noreply.github.com> Date: Mon, 5 Sep 2022 20:31:01 +0530 Subject: [PATCH 20/24] feat(cli/api): add validator distribution info grpc gateway get endpoint (#13144) --- CHANGELOG.md | 1 + .../distribution/v1beta1/query.pulsar.go | 2136 +++++++++++++---- .../distribution/v1beta1/query_grpc.pb.go | 38 + proto/cosmos/distribution/v1beta1/query.proto | 26 + x/distribution/client/cli/query.go | 45 + .../client/testutil/grpc_query_suite.go | 38 + x/distribution/client/testutil/suite.go | 42 + x/distribution/keeper/grpc_query.go | 43 + x/distribution/types/query.pb.go | 692 +++++- x/distribution/types/query.pb.gw.go | 101 + 10 files changed, 2647 insertions(+), 515 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3105c7fcc88c..0fced6ba736f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [#13101](https://github.com/cosmos/cosmos-sdk/pull/13101) Remove weights from `simapp/params` and `testutil/sims`. They are now in their respective modules. * (simapp) [#13107](https://github.com/cosmos/cosmos-sdk/pull/13107)Β Call `SetIAVLCacheSize` with the configured value in simapp. * [#12398](https://github.com/cosmos/cosmos-sdk/issues/12398) Refactor all `x` modules to unit-test via mocks and decouple `simapp`. +* [#13144](https://github.com/cosmos/cosmos-sdk/pull/13144) Add validator distribution info grpc gateway get endpoint. ### State Machine Breaking diff --git a/api/cosmos/distribution/v1beta1/query.pulsar.go b/api/cosmos/distribution/v1beta1/query.pulsar.go index a354c084f7c7..2601738a7366 100644 --- a/api/cosmos/distribution/v1beta1/query.pulsar.go +++ b/api/cosmos/distribution/v1beta1/query.pulsar.go @@ -2,8 +2,8 @@ package distributionv1beta1 import ( - v1beta1 "cosmossdk.io/api/cosmos/base/query/v1beta1" - v1beta11 "cosmossdk.io/api/cosmos/base/v1beta1" + v1beta11 "cosmossdk.io/api/cosmos/base/query/v1beta1" + v1beta1 "cosmossdk.io/api/cosmos/base/v1beta1" fmt "fmt" _ "github.com/cosmos/cosmos-proto" runtime "github.com/cosmos/cosmos-proto/runtime" @@ -808,6 +808,1122 @@ func (x *fastReflection_QueryParamsResponse) ProtoMethods() *protoiface.Methods } } +var ( + md_QueryValidatorDistributionInfoRequest protoreflect.MessageDescriptor + fd_QueryValidatorDistributionInfoRequest_validator_address protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_distribution_v1beta1_query_proto_init() + md_QueryValidatorDistributionInfoRequest = File_cosmos_distribution_v1beta1_query_proto.Messages().ByName("QueryValidatorDistributionInfoRequest") + fd_QueryValidatorDistributionInfoRequest_validator_address = md_QueryValidatorDistributionInfoRequest.Fields().ByName("validator_address") +} + +var _ protoreflect.Message = (*fastReflection_QueryValidatorDistributionInfoRequest)(nil) + +type fastReflection_QueryValidatorDistributionInfoRequest QueryValidatorDistributionInfoRequest + +func (x *QueryValidatorDistributionInfoRequest) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryValidatorDistributionInfoRequest)(x) +} + +func (x *QueryValidatorDistributionInfoRequest) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryValidatorDistributionInfoRequest_messageType fastReflection_QueryValidatorDistributionInfoRequest_messageType +var _ protoreflect.MessageType = fastReflection_QueryValidatorDistributionInfoRequest_messageType{} + +type fastReflection_QueryValidatorDistributionInfoRequest_messageType struct{} + +func (x fastReflection_QueryValidatorDistributionInfoRequest_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryValidatorDistributionInfoRequest)(nil) +} +func (x fastReflection_QueryValidatorDistributionInfoRequest_messageType) New() protoreflect.Message { + return new(fastReflection_QueryValidatorDistributionInfoRequest) +} +func (x fastReflection_QueryValidatorDistributionInfoRequest_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryValidatorDistributionInfoRequest +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Descriptor() protoreflect.MessageDescriptor { + return md_QueryValidatorDistributionInfoRequest +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Type() protoreflect.MessageType { + return _fastReflection_QueryValidatorDistributionInfoRequest_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) New() protoreflect.Message { + return new(fastReflection_QueryValidatorDistributionInfoRequest) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Interface() protoreflect.ProtoMessage { + return (*QueryValidatorDistributionInfoRequest)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.ValidatorAddress != "" { + value := protoreflect.ValueOfString(x.ValidatorAddress) + if !f(fd_QueryValidatorDistributionInfoRequest_validator_address, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + return x.ValidatorAddress != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + x.ValidatorAddress = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + value := x.ValidatorAddress + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + x.ValidatorAddress = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + panic(fmt.Errorf("field validator_address of message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest.validator_address": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryValidatorDistributionInfoRequest) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryValidatorDistributionInfoRequest) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.ValidatorAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryValidatorDistributionInfoRequest) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.ValidatorAddress) > 0 { + i -= len(x.ValidatorAddress) + copy(dAtA[i:], x.ValidatorAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.ValidatorAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryValidatorDistributionInfoRequest) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryValidatorDistributionInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryValidatorDistributionInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.ValidatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +var _ protoreflect.List = (*_QueryValidatorDistributionInfoResponse_2_list)(nil) + +type _QueryValidatorDistributionInfoResponse_2_list struct { + list *[]*v1beta1.DecCoin +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) + (*x.list)[i] = concreteValue +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) + *x.list = append(*x.list, concreteValue) +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) AppendMutable() protoreflect.Value { + v := new(v1beta1.DecCoin) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) NewElement() protoreflect.Value { + v := new(v1beta1.DecCoin) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_2_list) IsValid() bool { + return x.list != nil +} + +var _ protoreflect.List = (*_QueryValidatorDistributionInfoResponse_3_list)(nil) + +type _QueryValidatorDistributionInfoResponse_3_list struct { + list *[]*v1beta1.DecCoin +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) Len() int { + if x.list == nil { + return 0 + } + return len(*x.list) +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) Get(i int) protoreflect.Value { + return protoreflect.ValueOfMessage((*x.list)[i].ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) Set(i int, value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) + (*x.list)[i] = concreteValue +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) Append(value protoreflect.Value) { + valueUnwrapped := value.Message() + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) + *x.list = append(*x.list, concreteValue) +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) AppendMutable() protoreflect.Value { + v := new(v1beta1.DecCoin) + *x.list = append(*x.list, v) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) Truncate(n int) { + for i := n; i < len(*x.list); i++ { + (*x.list)[i] = nil + } + *x.list = (*x.list)[:n] +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) NewElement() protoreflect.Value { + v := new(v1beta1.DecCoin) + return protoreflect.ValueOfMessage(v.ProtoReflect()) +} + +func (x *_QueryValidatorDistributionInfoResponse_3_list) IsValid() bool { + return x.list != nil +} + +var ( + md_QueryValidatorDistributionInfoResponse protoreflect.MessageDescriptor + fd_QueryValidatorDistributionInfoResponse_operator_address protoreflect.FieldDescriptor + fd_QueryValidatorDistributionInfoResponse_self_bond_rewards protoreflect.FieldDescriptor + fd_QueryValidatorDistributionInfoResponse_commission protoreflect.FieldDescriptor +) + +func init() { + file_cosmos_distribution_v1beta1_query_proto_init() + md_QueryValidatorDistributionInfoResponse = File_cosmos_distribution_v1beta1_query_proto.Messages().ByName("QueryValidatorDistributionInfoResponse") + fd_QueryValidatorDistributionInfoResponse_operator_address = md_QueryValidatorDistributionInfoResponse.Fields().ByName("operator_address") + fd_QueryValidatorDistributionInfoResponse_self_bond_rewards = md_QueryValidatorDistributionInfoResponse.Fields().ByName("self_bond_rewards") + fd_QueryValidatorDistributionInfoResponse_commission = md_QueryValidatorDistributionInfoResponse.Fields().ByName("commission") +} + +var _ protoreflect.Message = (*fastReflection_QueryValidatorDistributionInfoResponse)(nil) + +type fastReflection_QueryValidatorDistributionInfoResponse QueryValidatorDistributionInfoResponse + +func (x *QueryValidatorDistributionInfoResponse) ProtoReflect() protoreflect.Message { + return (*fastReflection_QueryValidatorDistributionInfoResponse)(x) +} + +func (x *QueryValidatorDistributionInfoResponse) slowProtoReflect() protoreflect.Message { + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_QueryValidatorDistributionInfoResponse_messageType fastReflection_QueryValidatorDistributionInfoResponse_messageType +var _ protoreflect.MessageType = fastReflection_QueryValidatorDistributionInfoResponse_messageType{} + +type fastReflection_QueryValidatorDistributionInfoResponse_messageType struct{} + +func (x fastReflection_QueryValidatorDistributionInfoResponse_messageType) Zero() protoreflect.Message { + return (*fastReflection_QueryValidatorDistributionInfoResponse)(nil) +} +func (x fastReflection_QueryValidatorDistributionInfoResponse_messageType) New() protoreflect.Message { + return new(fastReflection_QueryValidatorDistributionInfoResponse) +} +func (x fastReflection_QueryValidatorDistributionInfoResponse_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_QueryValidatorDistributionInfoResponse +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Descriptor() protoreflect.MessageDescriptor { + return md_QueryValidatorDistributionInfoResponse +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Type() protoreflect.MessageType { + return _fastReflection_QueryValidatorDistributionInfoResponse_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) New() protoreflect.Message { + return new(fastReflection_QueryValidatorDistributionInfoResponse) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Interface() protoreflect.ProtoMessage { + return (*QueryValidatorDistributionInfoResponse)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.OperatorAddress != "" { + value := protoreflect.ValueOfString(x.OperatorAddress) + if !f(fd_QueryValidatorDistributionInfoResponse_operator_address, value) { + return + } + } + if len(x.SelfBondRewards) != 0 { + value := protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_2_list{list: &x.SelfBondRewards}) + if !f(fd_QueryValidatorDistributionInfoResponse_self_bond_rewards, value) { + return + } + } + if len(x.Commission) != 0 { + value := protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_3_list{list: &x.Commission}) + if !f(fd_QueryValidatorDistributionInfoResponse_commission, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + return x.OperatorAddress != "" + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + return len(x.SelfBondRewards) != 0 + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + return len(x.Commission) != 0 + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + x.OperatorAddress = "" + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + x.SelfBondRewards = nil + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + x.Commission = nil + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + value := x.OperatorAddress + return protoreflect.ValueOfString(value) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + if len(x.SelfBondRewards) == 0 { + return protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_2_list{}) + } + listValue := &_QueryValidatorDistributionInfoResponse_2_list{list: &x.SelfBondRewards} + return protoreflect.ValueOfList(listValue) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + if len(x.Commission) == 0 { + return protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_3_list{}) + } + listValue := &_QueryValidatorDistributionInfoResponse_3_list{list: &x.Commission} + return protoreflect.ValueOfList(listValue) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + x.OperatorAddress = value.Interface().(string) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + lv := value.List() + clv := lv.(*_QueryValidatorDistributionInfoResponse_2_list) + x.SelfBondRewards = *clv.list + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + lv := value.List() + clv := lv.(*_QueryValidatorDistributionInfoResponse_3_list) + x.Commission = *clv.list + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + if x.SelfBondRewards == nil { + x.SelfBondRewards = []*v1beta1.DecCoin{} + } + value := &_QueryValidatorDistributionInfoResponse_2_list{list: &x.SelfBondRewards} + return protoreflect.ValueOfList(value) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + if x.Commission == nil { + x.Commission = []*v1beta1.DecCoin{} + } + value := &_QueryValidatorDistributionInfoResponse_3_list{list: &x.Commission} + return protoreflect.ValueOfList(value) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + panic(fmt.Errorf("field operator_address of message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.operator_address": + return protoreflect.ValueOfString("") + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards": + list := []*v1beta1.DecCoin{} + return protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_2_list{list: &list}) + case "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission": + list := []*v1beta1.DecCoin{} + return protoreflect.ValueOfList(&_QueryValidatorDistributionInfoResponse_3_list{list: &list}) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse")) + } + panic(fmt.Errorf("message cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_QueryValidatorDistributionInfoResponse) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*QueryValidatorDistributionInfoResponse) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.OperatorAddress) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if len(x.SelfBondRewards) > 0 { + for _, e := range x.SelfBondRewards { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if len(x.Commission) > 0 { + for _, e := range x.Commission { + l = options.Size(e) + n += 1 + l + runtime.Sov(uint64(l)) + } + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*QueryValidatorDistributionInfoResponse) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Commission) > 0 { + for iNdEx := len(x.Commission) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.Commission[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x1a + } + } + if len(x.SelfBondRewards) > 0 { + for iNdEx := len(x.SelfBondRewards) - 1; iNdEx >= 0; iNdEx-- { + encoded, err := options.Marshal(x.SelfBondRewards[iNdEx]) + if err != nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, err + } + i -= len(encoded) + copy(dAtA[i:], encoded) + i = runtime.EncodeVarint(dAtA, i, uint64(len(encoded))) + i-- + dAtA[i] = 0x12 + } + } + if len(x.OperatorAddress) > 0 { + i -= len(x.OperatorAddress) + copy(dAtA[i:], x.OperatorAddress) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.OperatorAddress))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*QueryValidatorDistributionInfoResponse) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryValidatorDistributionInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: QueryValidatorDistributionInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.OperatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field SelfBondRewards", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.SelfBondRewards = append(x.SelfBondRewards, &v1beta1.DecCoin{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.SelfBondRewards[len(x.SelfBondRewards)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Commission", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Commission = append(x.Commission, &v1beta1.DecCoin{}) + if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Commission[len(x.Commission)-1]); err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + var ( md_QueryValidatorOutstandingRewardsRequest protoreflect.MessageDescriptor fd_QueryValidatorOutstandingRewardsRequest_validator_address protoreflect.FieldDescriptor @@ -828,7 +1944,7 @@ func (x *QueryValidatorOutstandingRewardsRequest) ProtoReflect() protoreflect.Me } func (x *QueryValidatorOutstandingRewardsRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[2] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1248,7 +2364,7 @@ func (x *QueryValidatorOutstandingRewardsResponse) ProtoReflect() protoreflect.M } func (x *QueryValidatorOutstandingRewardsResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[3] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1683,7 +2799,7 @@ func (x *QueryValidatorCommissionRequest) ProtoReflect() protoreflect.Message { } func (x *QueryValidatorCommissionRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[4] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2103,7 +3219,7 @@ func (x *QueryValidatorCommissionResponse) ProtoReflect() protoreflect.Message { } func (x *QueryValidatorCommissionResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[5] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2544,7 +3660,7 @@ func (x *QueryValidatorSlashesRequest) ProtoReflect() protoreflect.Message { } func (x *QueryValidatorSlashesRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[6] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2726,7 +3842,7 @@ func (x *fastReflection_QueryValidatorSlashesRequest) Set(fd protoreflect.FieldD case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.ending_height": x.EndingHeight = value.Uint() case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.pagination": - x.Pagination = value.Message().Interface().(*v1beta1.PageRequest) + x.Pagination = value.Message().Interface().(*v1beta11.PageRequest) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorSlashesRequest")) @@ -2749,7 +3865,7 @@ func (x *fastReflection_QueryValidatorSlashesRequest) Mutable(fd protoreflect.Fi switch fd.FullName() { case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.pagination": if x.Pagination == nil { - x.Pagination = new(v1beta1.PageRequest) + x.Pagination = new(v1beta11.PageRequest) } return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.validator_address": @@ -2778,7 +3894,7 @@ func (x *fastReflection_QueryValidatorSlashesRequest) NewField(fd protoreflect.F case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.ending_height": return protoreflect.ValueOfUint64(uint64(0)) case "cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.pagination": - m := new(v1beta1.PageRequest) + m := new(v1beta11.PageRequest) return protoreflect.ValueOfMessage(m.ProtoReflect()) default: if fd.IsExtension() { @@ -3072,7 +4188,7 @@ func (x *fastReflection_QueryValidatorSlashesRequest) ProtoMethods() *protoiface return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } if x.Pagination == nil { - x.Pagination = &v1beta1.PageRequest{} + x.Pagination = &v1beta11.PageRequest{} } if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err @@ -3186,7 +4302,7 @@ func (x *QueryValidatorSlashesResponse) ProtoReflect() protoreflect.Message { } func (x *QueryValidatorSlashesResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[7] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3343,7 +4459,7 @@ func (x *fastReflection_QueryValidatorSlashesResponse) Set(fd protoreflect.Field clv := lv.(*_QueryValidatorSlashesResponse_1_list) x.Slashes = *clv.list case "cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.pagination": - x.Pagination = value.Message().Interface().(*v1beta1.PageResponse) + x.Pagination = value.Message().Interface().(*v1beta11.PageResponse) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse")) @@ -3372,7 +4488,7 @@ func (x *fastReflection_QueryValidatorSlashesResponse) Mutable(fd protoreflect.F return protoreflect.ValueOfList(value) case "cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.pagination": if x.Pagination == nil { - x.Pagination = new(v1beta1.PageResponse) + x.Pagination = new(v1beta11.PageResponse) } return protoreflect.ValueOfMessage(x.Pagination.ProtoReflect()) default: @@ -3392,7 +4508,7 @@ func (x *fastReflection_QueryValidatorSlashesResponse) NewField(fd protoreflect. list := []*ValidatorSlashEvent{} return protoreflect.ValueOfList(&_QueryValidatorSlashesResponse_1_list{list: &list}) case "cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.pagination": - m := new(v1beta1.PageResponse) + m := new(v1beta11.PageResponse) return protoreflect.ValueOfMessage(m.ProtoReflect()) default: if fd.IsExtension() { @@ -3645,7 +4761,7 @@ func (x *fastReflection_QueryValidatorSlashesResponse) ProtoMethods() *protoifac return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } if x.Pagination == nil { - x.Pagination = &v1beta1.PageResponse{} + x.Pagination = &v1beta11.PageResponse{} } if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pagination); err != nil { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err @@ -3708,7 +4824,7 @@ func (x *QueryDelegationRewardsRequest) ProtoReflect() protoreflect.Message { } func (x *QueryDelegationRewardsRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[8] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4173,7 +5289,7 @@ func (x *fastReflection_QueryDelegationRewardsRequest) ProtoMethods() *protoifac var _ protoreflect.List = (*_QueryDelegationRewardsResponse_1_list)(nil) type _QueryDelegationRewardsResponse_1_list struct { - list *[]*v1beta11.DecCoin + list *[]*v1beta1.DecCoin } func (x *_QueryDelegationRewardsResponse_1_list) Len() int { @@ -4189,18 +5305,18 @@ func (x *_QueryDelegationRewardsResponse_1_list) Get(i int) protoreflect.Value { func (x *_QueryDelegationRewardsResponse_1_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) (*x.list)[i] = concreteValue } func (x *_QueryDelegationRewardsResponse_1_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) *x.list = append(*x.list, concreteValue) } func (x *_QueryDelegationRewardsResponse_1_list) AppendMutable() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -4213,7 +5329,7 @@ func (x *_QueryDelegationRewardsResponse_1_list) Truncate(n int) { } func (x *_QueryDelegationRewardsResponse_1_list) NewElement() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -4241,7 +5357,7 @@ func (x *QueryDelegationRewardsResponse) ProtoReflect() protoreflect.Message { } func (x *QueryDelegationRewardsResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[9] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4406,7 +5522,7 @@ func (x *fastReflection_QueryDelegationRewardsResponse) Mutable(fd protoreflect. switch fd.FullName() { case "cosmos.distribution.v1beta1.QueryDelegationRewardsResponse.rewards": if x.Rewards == nil { - x.Rewards = []*v1beta11.DecCoin{} + x.Rewards = []*v1beta1.DecCoin{} } value := &_QueryDelegationRewardsResponse_1_list{list: &x.Rewards} return protoreflect.ValueOfList(value) @@ -4424,7 +5540,7 @@ func (x *fastReflection_QueryDelegationRewardsResponse) Mutable(fd protoreflect. func (x *fastReflection_QueryDelegationRewardsResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { case "cosmos.distribution.v1beta1.QueryDelegationRewardsResponse.rewards": - list := []*v1beta11.DecCoin{} + list := []*v1beta1.DecCoin{} return protoreflect.ValueOfList(&_QueryDelegationRewardsResponse_1_list{list: &list}) default: if fd.IsExtension() { @@ -4624,7 +5740,7 @@ func (x *fastReflection_QueryDelegationRewardsResponse) ProtoMethods() *protoifa if postIndex > l { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } - x.Rewards = append(x.Rewards, &v1beta11.DecCoin{}) + x.Rewards = append(x.Rewards, &v1beta1.DecCoin{}) if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Rewards[len(x.Rewards)-1]); err != nil { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } @@ -4684,7 +5800,7 @@ func (x *QueryDelegationTotalRewardsRequest) ProtoReflect() protoreflect.Message } func (x *QueryDelegationTotalRewardsRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[10] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5138,7 +6254,7 @@ func (x *_QueryDelegationTotalRewardsResponse_1_list) IsValid() bool { var _ protoreflect.List = (*_QueryDelegationTotalRewardsResponse_2_list)(nil) type _QueryDelegationTotalRewardsResponse_2_list struct { - list *[]*v1beta11.DecCoin + list *[]*v1beta1.DecCoin } func (x *_QueryDelegationTotalRewardsResponse_2_list) Len() int { @@ -5154,18 +6270,18 @@ func (x *_QueryDelegationTotalRewardsResponse_2_list) Get(i int) protoreflect.Va func (x *_QueryDelegationTotalRewardsResponse_2_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) (*x.list)[i] = concreteValue } func (x *_QueryDelegationTotalRewardsResponse_2_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) *x.list = append(*x.list, concreteValue) } func (x *_QueryDelegationTotalRewardsResponse_2_list) AppendMutable() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -5178,7 +6294,7 @@ func (x *_QueryDelegationTotalRewardsResponse_2_list) Truncate(n int) { } func (x *_QueryDelegationTotalRewardsResponse_2_list) NewElement() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -5208,7 +6324,7 @@ func (x *QueryDelegationTotalRewardsResponse) ProtoReflect() protoreflect.Messag } func (x *QueryDelegationTotalRewardsResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[11] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5399,7 +6515,7 @@ func (x *fastReflection_QueryDelegationTotalRewardsResponse) Mutable(fd protoref return protoreflect.ValueOfList(value) case "cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.total": if x.Total == nil { - x.Total = []*v1beta11.DecCoin{} + x.Total = []*v1beta1.DecCoin{} } value := &_QueryDelegationTotalRewardsResponse_2_list{list: &x.Total} return protoreflect.ValueOfList(value) @@ -5420,7 +6536,7 @@ func (x *fastReflection_QueryDelegationTotalRewardsResponse) NewField(fd protore list := []*DelegationDelegatorReward{} return protoreflect.ValueOfList(&_QueryDelegationTotalRewardsResponse_1_list{list: &list}) case "cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.total": - list := []*v1beta11.DecCoin{} + list := []*v1beta1.DecCoin{} return protoreflect.ValueOfList(&_QueryDelegationTotalRewardsResponse_2_list{list: &list}) default: if fd.IsExtension() { @@ -5676,7 +6792,7 @@ func (x *fastReflection_QueryDelegationTotalRewardsResponse) ProtoMethods() *pro if postIndex > l { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } - x.Total = append(x.Total, &v1beta11.DecCoin{}) + x.Total = append(x.Total, &v1beta1.DecCoin{}) if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Total[len(x.Total)-1]); err != nil { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } @@ -5736,7 +6852,7 @@ func (x *QueryDelegatorValidatorsRequest) ProtoReflect() protoreflect.Message { } func (x *QueryDelegatorValidatorsRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[12] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6202,7 +7318,7 @@ func (x *QueryDelegatorValidatorsResponse) ProtoReflect() protoreflect.Message { } func (x *QueryDelegatorValidatorsResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[13] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6636,7 +7752,7 @@ func (x *QueryDelegatorWithdrawAddressRequest) ProtoReflect() protoreflect.Messa } func (x *QueryDelegatorWithdrawAddressRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[14] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7056,7 +8172,7 @@ func (x *QueryDelegatorWithdrawAddressResponse) ProtoReflect() protoreflect.Mess } func (x *QueryDelegatorWithdrawAddressResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[15] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7474,7 +8590,7 @@ func (x *QueryCommunityPoolRequest) ProtoReflect() protoreflect.Message { } func (x *QueryCommunityPoolRequest) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[16] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7815,7 +8931,7 @@ func (x *fastReflection_QueryCommunityPoolRequest) ProtoMethods() *protoiface.Me var _ protoreflect.List = (*_QueryCommunityPoolResponse_1_list)(nil) type _QueryCommunityPoolResponse_1_list struct { - list *[]*v1beta11.DecCoin + list *[]*v1beta1.DecCoin } func (x *_QueryCommunityPoolResponse_1_list) Len() int { @@ -7831,18 +8947,18 @@ func (x *_QueryCommunityPoolResponse_1_list) Get(i int) protoreflect.Value { func (x *_QueryCommunityPoolResponse_1_list) Set(i int, value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) (*x.list)[i] = concreteValue } func (x *_QueryCommunityPoolResponse_1_list) Append(value protoreflect.Value) { valueUnwrapped := value.Message() - concreteValue := valueUnwrapped.Interface().(*v1beta11.DecCoin) + concreteValue := valueUnwrapped.Interface().(*v1beta1.DecCoin) *x.list = append(*x.list, concreteValue) } func (x *_QueryCommunityPoolResponse_1_list) AppendMutable() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) *x.list = append(*x.list, v) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -7855,7 +8971,7 @@ func (x *_QueryCommunityPoolResponse_1_list) Truncate(n int) { } func (x *_QueryCommunityPoolResponse_1_list) NewElement() protoreflect.Value { - v := new(v1beta11.DecCoin) + v := new(v1beta1.DecCoin) return protoreflect.ValueOfMessage(v.ProtoReflect()) } @@ -7883,7 +8999,7 @@ func (x *QueryCommunityPoolResponse) ProtoReflect() protoreflect.Message { } func (x *QueryCommunityPoolResponse) slowProtoReflect() protoreflect.Message { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[17] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8048,7 +9164,7 @@ func (x *fastReflection_QueryCommunityPoolResponse) Mutable(fd protoreflect.Fiel switch fd.FullName() { case "cosmos.distribution.v1beta1.QueryCommunityPoolResponse.pool": if x.Pool == nil { - x.Pool = []*v1beta11.DecCoin{} + x.Pool = []*v1beta1.DecCoin{} } value := &_QueryCommunityPoolResponse_1_list{list: &x.Pool} return protoreflect.ValueOfList(value) @@ -8066,7 +9182,7 @@ func (x *fastReflection_QueryCommunityPoolResponse) Mutable(fd protoreflect.Fiel func (x *fastReflection_QueryCommunityPoolResponse) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { switch fd.FullName() { case "cosmos.distribution.v1beta1.QueryCommunityPoolResponse.pool": - list := []*v1beta11.DecCoin{} + list := []*v1beta1.DecCoin{} return protoreflect.ValueOfList(&_QueryCommunityPoolResponse_1_list{list: &list}) default: if fd.IsExtension() { @@ -8266,7 +9382,7 @@ func (x *fastReflection_QueryCommunityPoolResponse) ProtoMethods() *protoiface.M if postIndex > l { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF } - x.Pool = append(x.Pool, &v1beta11.DecCoin{}) + x.Pool = append(x.Pool, &v1beta1.DecCoin{}) if err := options.Unmarshal(dAtA[iNdEx:postIndex], x.Pool[len(x.Pool)-1]); err != nil { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err } @@ -8383,6 +9499,98 @@ func (x *QueryParamsResponse) GetParams() *Params { return nil } +// QueryValidatorDistributionInfoRequest is the request type for the Query/ValidatorDistributionInfo RPC method. +type QueryValidatorDistributionInfoRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // validator_address defines the validator address to query for. + ValidatorAddress string `protobuf:"bytes,1,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` +} + +func (x *QueryValidatorDistributionInfoRequest) Reset() { + *x = QueryValidatorDistributionInfoRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryValidatorDistributionInfoRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryValidatorDistributionInfoRequest) ProtoMessage() {} + +// Deprecated: Use QueryValidatorDistributionInfoRequest.ProtoReflect.Descriptor instead. +func (*QueryValidatorDistributionInfoRequest) Descriptor() ([]byte, []int) { + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{2} +} + +func (x *QueryValidatorDistributionInfoRequest) GetValidatorAddress() string { + if x != nil { + return x.ValidatorAddress + } + return "" +} + +// QueryValidatorDistributionInfoResponse is the response type for the Query/ValidatorDistributionInfo RPC method. +type QueryValidatorDistributionInfoResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // operator_address defines the validator operator address. + OperatorAddress string `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` + // self_bond_rewards defines the self delegations rewards. + SelfBondRewards []*v1beta1.DecCoin `protobuf:"bytes,2,rep,name=self_bond_rewards,json=selfBondRewards,proto3" json:"self_bond_rewards,omitempty"` + // commission defines the commision the validator received. + Commission []*v1beta1.DecCoin `protobuf:"bytes,3,rep,name=commission,proto3" json:"commission,omitempty"` +} + +func (x *QueryValidatorDistributionInfoResponse) Reset() { + *x = QueryValidatorDistributionInfoResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *QueryValidatorDistributionInfoResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*QueryValidatorDistributionInfoResponse) ProtoMessage() {} + +// Deprecated: Use QueryValidatorDistributionInfoResponse.ProtoReflect.Descriptor instead. +func (*QueryValidatorDistributionInfoResponse) Descriptor() ([]byte, []int) { + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{3} +} + +func (x *QueryValidatorDistributionInfoResponse) GetOperatorAddress() string { + if x != nil { + return x.OperatorAddress + } + return "" +} + +func (x *QueryValidatorDistributionInfoResponse) GetSelfBondRewards() []*v1beta1.DecCoin { + if x != nil { + return x.SelfBondRewards + } + return nil +} + +func (x *QueryValidatorDistributionInfoResponse) GetCommission() []*v1beta1.DecCoin { + if x != nil { + return x.Commission + } + return nil +} + // QueryValidatorOutstandingRewardsRequest is the request type for the // Query/ValidatorOutstandingRewards RPC method. type QueryValidatorOutstandingRewardsRequest struct { @@ -8397,7 +9605,7 @@ type QueryValidatorOutstandingRewardsRequest struct { func (x *QueryValidatorOutstandingRewardsRequest) Reset() { *x = QueryValidatorOutstandingRewardsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[2] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8411,7 +9619,7 @@ func (*QueryValidatorOutstandingRewardsRequest) ProtoMessage() {} // Deprecated: Use QueryValidatorOutstandingRewardsRequest.ProtoReflect.Descriptor instead. func (*QueryValidatorOutstandingRewardsRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{2} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{4} } func (x *QueryValidatorOutstandingRewardsRequest) GetValidatorAddress() string { @@ -8434,7 +9642,7 @@ type QueryValidatorOutstandingRewardsResponse struct { func (x *QueryValidatorOutstandingRewardsResponse) Reset() { *x = QueryValidatorOutstandingRewardsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[3] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8448,7 +9656,7 @@ func (*QueryValidatorOutstandingRewardsResponse) ProtoMessage() {} // Deprecated: Use QueryValidatorOutstandingRewardsResponse.ProtoReflect.Descriptor instead. func (*QueryValidatorOutstandingRewardsResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{3} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{5} } func (x *QueryValidatorOutstandingRewardsResponse) GetRewards() *ValidatorOutstandingRewards { @@ -8472,7 +9680,7 @@ type QueryValidatorCommissionRequest struct { func (x *QueryValidatorCommissionRequest) Reset() { *x = QueryValidatorCommissionRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[4] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8486,7 +9694,7 @@ func (*QueryValidatorCommissionRequest) ProtoMessage() {} // Deprecated: Use QueryValidatorCommissionRequest.ProtoReflect.Descriptor instead. func (*QueryValidatorCommissionRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{4} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{6} } func (x *QueryValidatorCommissionRequest) GetValidatorAddress() string { @@ -8510,7 +9718,7 @@ type QueryValidatorCommissionResponse struct { func (x *QueryValidatorCommissionResponse) Reset() { *x = QueryValidatorCommissionResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[5] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8524,7 +9732,7 @@ func (*QueryValidatorCommissionResponse) ProtoMessage() {} // Deprecated: Use QueryValidatorCommissionResponse.ProtoReflect.Descriptor instead. func (*QueryValidatorCommissionResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{5} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{7} } func (x *QueryValidatorCommissionResponse) GetCommission() *ValidatorAccumulatedCommission { @@ -8548,13 +9756,13 @@ type QueryValidatorSlashesRequest struct { // starting_height defines the optional ending height to query the slashes. EndingHeight uint64 `protobuf:"varint,3,opt,name=ending_height,json=endingHeight,proto3" json:"ending_height,omitempty"` // pagination defines an optional pagination for the request. - Pagination *v1beta1.PageRequest `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *v1beta11.PageRequest `protobuf:"bytes,4,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (x *QueryValidatorSlashesRequest) Reset() { *x = QueryValidatorSlashesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[6] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8568,7 +9776,7 @@ func (*QueryValidatorSlashesRequest) ProtoMessage() {} // Deprecated: Use QueryValidatorSlashesRequest.ProtoReflect.Descriptor instead. func (*QueryValidatorSlashesRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{6} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{8} } func (x *QueryValidatorSlashesRequest) GetValidatorAddress() string { @@ -8592,7 +9800,7 @@ func (x *QueryValidatorSlashesRequest) GetEndingHeight() uint64 { return 0 } -func (x *QueryValidatorSlashesRequest) GetPagination() *v1beta1.PageRequest { +func (x *QueryValidatorSlashesRequest) GetPagination() *v1beta11.PageRequest { if x != nil { return x.Pagination } @@ -8609,13 +9817,13 @@ type QueryValidatorSlashesResponse struct { // slashes defines the slashes the validator received. Slashes []*ValidatorSlashEvent `protobuf:"bytes,1,rep,name=slashes,proto3" json:"slashes,omitempty"` // pagination defines the pagination in the response. - Pagination *v1beta1.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` + Pagination *v1beta11.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } func (x *QueryValidatorSlashesResponse) Reset() { *x = QueryValidatorSlashesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[7] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8629,7 +9837,7 @@ func (*QueryValidatorSlashesResponse) ProtoMessage() {} // Deprecated: Use QueryValidatorSlashesResponse.ProtoReflect.Descriptor instead. func (*QueryValidatorSlashesResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{7} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{9} } func (x *QueryValidatorSlashesResponse) GetSlashes() []*ValidatorSlashEvent { @@ -8639,7 +9847,7 @@ func (x *QueryValidatorSlashesResponse) GetSlashes() []*ValidatorSlashEvent { return nil } -func (x *QueryValidatorSlashesResponse) GetPagination() *v1beta1.PageResponse { +func (x *QueryValidatorSlashesResponse) GetPagination() *v1beta11.PageResponse { if x != nil { return x.Pagination } @@ -8662,7 +9870,7 @@ type QueryDelegationRewardsRequest struct { func (x *QueryDelegationRewardsRequest) Reset() { *x = QueryDelegationRewardsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[8] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8676,7 +9884,7 @@ func (*QueryDelegationRewardsRequest) ProtoMessage() {} // Deprecated: Use QueryDelegationRewardsRequest.ProtoReflect.Descriptor instead. func (*QueryDelegationRewardsRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{8} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{10} } func (x *QueryDelegationRewardsRequest) GetDelegatorAddress() string { @@ -8701,13 +9909,13 @@ type QueryDelegationRewardsResponse struct { unknownFields protoimpl.UnknownFields // rewards defines the rewards accrued by a delegation. - Rewards []*v1beta11.DecCoin `protobuf:"bytes,1,rep,name=rewards,proto3" json:"rewards,omitempty"` + Rewards []*v1beta1.DecCoin `protobuf:"bytes,1,rep,name=rewards,proto3" json:"rewards,omitempty"` } func (x *QueryDelegationRewardsResponse) Reset() { *x = QueryDelegationRewardsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[9] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8721,10 +9929,10 @@ func (*QueryDelegationRewardsResponse) ProtoMessage() {} // Deprecated: Use QueryDelegationRewardsResponse.ProtoReflect.Descriptor instead. func (*QueryDelegationRewardsResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{9} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{11} } -func (x *QueryDelegationRewardsResponse) GetRewards() []*v1beta11.DecCoin { +func (x *QueryDelegationRewardsResponse) GetRewards() []*v1beta1.DecCoin { if x != nil { return x.Rewards } @@ -8745,7 +9953,7 @@ type QueryDelegationTotalRewardsRequest struct { func (x *QueryDelegationTotalRewardsRequest) Reset() { *x = QueryDelegationTotalRewardsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[10] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8759,7 +9967,7 @@ func (*QueryDelegationTotalRewardsRequest) ProtoMessage() {} // Deprecated: Use QueryDelegationTotalRewardsRequest.ProtoReflect.Descriptor instead. func (*QueryDelegationTotalRewardsRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{10} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{12} } func (x *QueryDelegationTotalRewardsRequest) GetDelegatorAddress() string { @@ -8779,13 +9987,13 @@ type QueryDelegationTotalRewardsResponse struct { // rewards defines all the rewards accrued by a delegator. Rewards []*DelegationDelegatorReward `protobuf:"bytes,1,rep,name=rewards,proto3" json:"rewards,omitempty"` // total defines the sum of all the rewards. - Total []*v1beta11.DecCoin `protobuf:"bytes,2,rep,name=total,proto3" json:"total,omitempty"` + Total []*v1beta1.DecCoin `protobuf:"bytes,2,rep,name=total,proto3" json:"total,omitempty"` } func (x *QueryDelegationTotalRewardsResponse) Reset() { *x = QueryDelegationTotalRewardsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[11] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8799,7 +10007,7 @@ func (*QueryDelegationTotalRewardsResponse) ProtoMessage() {} // Deprecated: Use QueryDelegationTotalRewardsResponse.ProtoReflect.Descriptor instead. func (*QueryDelegationTotalRewardsResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{11} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{13} } func (x *QueryDelegationTotalRewardsResponse) GetRewards() []*DelegationDelegatorReward { @@ -8809,7 +10017,7 @@ func (x *QueryDelegationTotalRewardsResponse) GetRewards() []*DelegationDelegato return nil } -func (x *QueryDelegationTotalRewardsResponse) GetTotal() []*v1beta11.DecCoin { +func (x *QueryDelegationTotalRewardsResponse) GetTotal() []*v1beta1.DecCoin { if x != nil { return x.Total } @@ -8830,7 +10038,7 @@ type QueryDelegatorValidatorsRequest struct { func (x *QueryDelegatorValidatorsRequest) Reset() { *x = QueryDelegatorValidatorsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[12] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8844,7 +10052,7 @@ func (*QueryDelegatorValidatorsRequest) ProtoMessage() {} // Deprecated: Use QueryDelegatorValidatorsRequest.ProtoReflect.Descriptor instead. func (*QueryDelegatorValidatorsRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{12} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{14} } func (x *QueryDelegatorValidatorsRequest) GetDelegatorAddress() string { @@ -8868,7 +10076,7 @@ type QueryDelegatorValidatorsResponse struct { func (x *QueryDelegatorValidatorsResponse) Reset() { *x = QueryDelegatorValidatorsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[13] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8882,7 +10090,7 @@ func (*QueryDelegatorValidatorsResponse) ProtoMessage() {} // Deprecated: Use QueryDelegatorValidatorsResponse.ProtoReflect.Descriptor instead. func (*QueryDelegatorValidatorsResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{13} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{15} } func (x *QueryDelegatorValidatorsResponse) GetValidators() []string { @@ -8906,7 +10114,7 @@ type QueryDelegatorWithdrawAddressRequest struct { func (x *QueryDelegatorWithdrawAddressRequest) Reset() { *x = QueryDelegatorWithdrawAddressRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[14] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8920,7 +10128,7 @@ func (*QueryDelegatorWithdrawAddressRequest) ProtoMessage() {} // Deprecated: Use QueryDelegatorWithdrawAddressRequest.ProtoReflect.Descriptor instead. func (*QueryDelegatorWithdrawAddressRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{14} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{16} } func (x *QueryDelegatorWithdrawAddressRequest) GetDelegatorAddress() string { @@ -8944,7 +10152,7 @@ type QueryDelegatorWithdrawAddressResponse struct { func (x *QueryDelegatorWithdrawAddressResponse) Reset() { *x = QueryDelegatorWithdrawAddressResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[15] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8958,7 +10166,7 @@ func (*QueryDelegatorWithdrawAddressResponse) ProtoMessage() {} // Deprecated: Use QueryDelegatorWithdrawAddressResponse.ProtoReflect.Descriptor instead. func (*QueryDelegatorWithdrawAddressResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{15} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{17} } func (x *QueryDelegatorWithdrawAddressResponse) GetWithdrawAddress() string { @@ -8979,7 +10187,7 @@ type QueryCommunityPoolRequest struct { func (x *QueryCommunityPoolRequest) Reset() { *x = QueryCommunityPoolRequest{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[16] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8993,7 +10201,7 @@ func (*QueryCommunityPoolRequest) ProtoMessage() {} // Deprecated: Use QueryCommunityPoolRequest.ProtoReflect.Descriptor instead. func (*QueryCommunityPoolRequest) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{16} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{18} } // QueryCommunityPoolResponse is the response type for the Query/CommunityPool @@ -9004,13 +10212,13 @@ type QueryCommunityPoolResponse struct { unknownFields protoimpl.UnknownFields // pool defines community pool's coins. - Pool []*v1beta11.DecCoin `protobuf:"bytes,1,rep,name=pool,proto3" json:"pool,omitempty"` + Pool []*v1beta1.DecCoin `protobuf:"bytes,1,rep,name=pool,proto3" json:"pool,omitempty"` } func (x *QueryCommunityPoolResponse) Reset() { *x = QueryCommunityPoolResponse{} if protoimpl.UnsafeEnabled { - mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[17] + mi := &file_cosmos_distribution_v1beta1_query_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9024,10 +10232,10 @@ func (*QueryCommunityPoolResponse) ProtoMessage() {} // Deprecated: Use QueryCommunityPoolResponse.ProtoReflect.Descriptor instead. func (*QueryCommunityPoolResponse) Descriptor() ([]byte, []int) { - return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{17} + return file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP(), []int{19} } -func (x *QueryCommunityPoolResponse) GetPool() []*v1beta11.DecCoin { +func (x *QueryCommunityPoolResponse) GetPool() []*v1beta1.DecCoin { if x != nil { return x.Pool } @@ -9061,288 +10269,332 @@ var file_cosmos_distribution_v1beta1_query_proto_rawDesc = []byte{ 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x06, 0x70, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x22, 0x70, 0x0a, 0x27, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x28, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x58, 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x42, 0x04, 0xc8, 0xde, 0x1f, - 0x00, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x68, 0x0a, 0x1f, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, - 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3b, 0x2e, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, 0x65, 0x64, - 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, - 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x02, 0x0a, - 0x1c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, - 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, - 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, - 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x23, 0x0a, - 0x0d, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x69, 0x67, - 0x68, 0x74, 0x12, 0x46, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x0a, - 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, - 0x98, 0xa0, 0x1f, 0x01, 0x22, 0xba, 0x01, 0x0a, 0x1d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x07, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, - 0x6c, 0x61, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, - 0x07, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, - 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x1d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, - 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, - 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x45, 0x0a, 0x11, 0x76, 0x61, + 0x73, 0x22, 0x6e, 0x0a, 0x25, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x6f, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x8d, 0x01, 0x0a, 0x1e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6b, - 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x33, 0xc8, - 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, - 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, - 0x6e, 0x73, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x75, 0x0a, 0x22, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, - 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, - 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, - 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, - 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, - 0x1f, 0x00, 0x22, 0xe6, 0x01, 0x0a, 0x23, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, - 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x07, 0x72, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x77, - 0x61, 0x72, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, - 0x64, 0x73, 0x12, 0x67, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, - 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, - 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x72, 0x0a, 0x1f, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, - 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, - 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x73, 0x22, 0xdf, 0x02, 0x0a, 0x26, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x6f, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x10, + 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x12, 0x7d, 0x0a, 0x11, 0x73, 0x65, 0x6c, 0x66, 0x5f, 0x62, 0x6f, 0x6e, 0x64, 0x5f, 0x72, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x33, 0xc8, 0xde, 0x1f, 0x00, + 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, + 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, + 0x0f, 0x73, 0x65, 0x6c, 0x66, 0x42, 0x6f, 0x6e, 0x64, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, + 0x12, 0x71, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, + 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, + 0x69, 0x6e, 0x42, 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, + 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x70, 0x0a, 0x27, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, + 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, - 0x4c, 0x0a, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, - 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, - 0x6f, 0x72, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x77, 0x0a, - 0x24, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, - 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, + 0x69, 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x84, 0x01, 0x0a, 0x28, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x58, 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, + 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x42, 0x04, 0xc8, + 0xde, 0x1f, 0x00, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x68, 0x0a, 0x1f, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, + 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x45, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x0a, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x3b, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x75, 0x6d, 0x75, 0x6c, 0x61, 0x74, + 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x04, 0xc8, 0xde, + 0x1f, 0x00, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x85, + 0x02, 0x0a, 0x1c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x45, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, + 0x6e, 0x67, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, + 0x23, 0x0a, 0x0d, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x48, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x12, 0x46, 0x0a, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x76, 0x31, 0x62, + 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x08, 0x88, 0xa0, + 0x1f, 0x00, 0x98, 0xa0, 0x1f, 0x01, 0x22, 0xba, 0x01, 0x0a, 0x1d, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x07, 0x73, 0x6c, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x04, 0xc8, 0xde, 0x1f, + 0x00, 0x52, 0x07, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x47, 0x0a, 0x0a, 0x70, 0x61, + 0x67, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0a, 0x70, 0x61, 0x67, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0xb7, 0x01, 0x0a, 0x1d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, - 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x76, 0x0a, 0x25, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x43, 0x0a, 0x10, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x61, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x1b, - 0x0a, 0x19, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, - 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x83, 0x01, 0x0a, 0x1a, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x50, 0x6f, - 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x04, 0x70, 0x6f, - 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, - 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, - 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, - 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x04, 0x70, 0x6f, 0x6f, - 0x6c, 0x32, 0xd8, 0x0f, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x98, 0x01, 0x0a, 0x06, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, 0x6d, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x25, 0x12, 0x23, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x83, 0x02, 0x0a, 0x1b, 0x56, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, - 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0x44, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, + 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x45, 0x0a, 0x11, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x52, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x8d, 0x01, + 0x0a, 0x1e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x6b, 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, + 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, + 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x75, 0x0a, + 0x22, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, + 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, + 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0xe6, 0x01, 0x0a, 0x23, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x07, + 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x52, + 0x65, 0x77, 0x61, 0x72, 0x64, 0x42, 0x04, 0xc8, 0xde, 0x1f, 0x00, 0x52, 0x07, 0x72, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x73, 0x12, 0x67, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, + 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, + 0x6e, 0x42, 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, + 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x72, 0x0a, + 0x1f, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, + 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, + 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, + 0x00, 0x22, 0x4c, 0x0a, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x6f, 0x72, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, + 0x77, 0x0a, 0x24, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x45, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x10, 0x64, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, + 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, 0x22, 0x76, 0x0a, 0x25, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, + 0x61, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x43, 0x0a, 0x10, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, + 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x53, + 0x74, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x0f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x08, 0x88, 0xa0, 0x1f, 0x00, 0xe8, 0xa0, 0x1f, 0x00, + 0x22, 0x1b, 0x0a, 0x19, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, + 0x74, 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x83, 0x01, + 0x0a, 0x1a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, + 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x65, 0x0a, 0x04, + 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x42, 0x33, 0xc8, 0xde, 0x1f, 0x00, 0xaa, 0xdf, + 0x1f, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2d, 0x73, 0x64, 0x6b, 0x2f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x2e, 0x44, 0x65, 0x63, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x52, 0x04, 0x70, + 0x6f, 0x6f, 0x6c, 0x32, 0xc4, 0x11, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x98, 0x01, + 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0xe9, 0x01, 0x0a, 0x19, 0x56, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x42, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x45, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x12, 0x4f, 0x2f, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, - 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x6f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0xe2, 0x01, 0x0a, - 0x13, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, + 0x74, 0x6f, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x43, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x3d, 0x12, 0x3b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x7d, 0x12, 0x83, 0x02, 0x0a, 0x1b, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x73, 0x12, 0x44, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, - 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x4e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x48, 0x12, 0x46, 0x2f, 0x63, 0x6f, 0x73, 0x6d, + 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x45, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x4f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x57, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x51, 0x12, 0x4f, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, - 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0xd6, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, - 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x3a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x6c, - 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, - 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, - 0x73, 0x7d, 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x11, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, - 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x6f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0xe2, 0x01, 0x0a, 0x13, 0x56, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x12, 0x3c, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, + 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, + 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x3d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, - 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, - 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x59, 0x12, 0x57, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, - 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, - 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, 0x65, - 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x72, - 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0xe8, 0x01, 0x0a, 0x16, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0x3f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, - 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, - 0x12, 0x43, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, - 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x72, 0x65, - 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0xe2, 0x01, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, - 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x3c, 0x2e, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x6f, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x63, 0x6f, - 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, - 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x48, 0x12, 0x46, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, - 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0xf7, 0x01, 0x0a, 0x18, 0x44, - 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x41, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, - 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, - 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x63, 0x6f, 0x73, - 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, - 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, - 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, - 0x7b, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x7d, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x12, 0xb5, 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, - 0x74, 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, - 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, + 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6d, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x4e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x48, 0x12, 0x46, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, + 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0xd6, 0x01, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x6c, 0x61, + 0x73, 0x68, 0x65, 0x73, 0x12, 0x39, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x53, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x53, 0x6c, 0x61, 0x73, + 0x68, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, + 0x2f, 0x73, 0x6c, 0x61, 0x73, 0x68, 0x65, 0x73, 0x12, 0xed, 0x01, 0x0a, 0x11, 0x44, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x12, 0x3a, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, - 0x2b, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x42, 0xfd, 0x01, 0x0a, - 0x1f, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, - 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x42, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x40, - 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, + 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x63, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x59, 0x12, + 0x57, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, 0x65, + 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, + 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x72, 0x65, 0x77, + 0x61, 0x72, 0x64, 0x73, 0x2f, 0x7b, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x5f, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x12, 0xe8, 0x01, 0x0a, 0x16, 0x44, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x12, 0x3f, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x45, 0x12, 0x43, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, - 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x64, 0x69, 0x73, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0xa2, 0x02, 0x03, 0x43, 0x44, 0x58, 0xaa, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, - 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x44, 0x69, - 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0xe2, 0x02, 0x27, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x44, 0x69, 0x73, 0x74, + 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, + 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x72, 0x65, 0x77, 0x61, + 0x72, 0x64, 0x73, 0x12, 0xe2, 0x01, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, + 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x3c, 0x2e, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, + 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x4e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x48, + 0x12, 0x46, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, 0x65, 0x6c, 0x65, 0x67, + 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x7d, 0x2f, 0x76, 0x61, + 0x6c, 0x69, 0x64, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x12, 0xf7, 0x01, 0x0a, 0x18, 0x44, 0x65, 0x6c, + 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x41, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, + 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, + 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x42, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, + 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x65, + 0x67, 0x61, 0x74, 0x6f, 0x72, 0x57, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x54, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x4e, 0x12, 0x4c, 0x2f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x7b, 0x64, + 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x7d, 0x2f, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0xb5, 0x01, 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, + 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x36, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, + 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x43, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x74, 0x79, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x33, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x12, 0x2b, 0x2f, + 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x75, 0x6e, 0x69, 0x74, 0x79, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x42, 0xfd, 0x01, 0x0a, 0x1f, 0x63, + 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0a, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x40, 0x63, 0x6f, + 0x73, 0x6d, 0x6f, 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x64, 0x69, 0x73, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, + 0x03, 0x43, 0x44, 0x58, 0xaa, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x44, 0x69, + 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0xca, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1d, 0x43, - 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0xe2, 0x02, 0x27, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x5c, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1d, 0x43, 0x6f, 0x73, + 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x44, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -9357,69 +10609,75 @@ func file_cosmos_distribution_v1beta1_query_proto_rawDescGZIP() []byte { return file_cosmos_distribution_v1beta1_query_proto_rawDescData } -var file_cosmos_distribution_v1beta1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_cosmos_distribution_v1beta1_query_proto_msgTypes = make([]protoimpl.MessageInfo, 20) var file_cosmos_distribution_v1beta1_query_proto_goTypes = []interface{}{ (*QueryParamsRequest)(nil), // 0: cosmos.distribution.v1beta1.QueryParamsRequest (*QueryParamsResponse)(nil), // 1: cosmos.distribution.v1beta1.QueryParamsResponse - (*QueryValidatorOutstandingRewardsRequest)(nil), // 2: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsRequest - (*QueryValidatorOutstandingRewardsResponse)(nil), // 3: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse - (*QueryValidatorCommissionRequest)(nil), // 4: cosmos.distribution.v1beta1.QueryValidatorCommissionRequest - (*QueryValidatorCommissionResponse)(nil), // 5: cosmos.distribution.v1beta1.QueryValidatorCommissionResponse - (*QueryValidatorSlashesRequest)(nil), // 6: cosmos.distribution.v1beta1.QueryValidatorSlashesRequest - (*QueryValidatorSlashesResponse)(nil), // 7: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse - (*QueryDelegationRewardsRequest)(nil), // 8: cosmos.distribution.v1beta1.QueryDelegationRewardsRequest - (*QueryDelegationRewardsResponse)(nil), // 9: cosmos.distribution.v1beta1.QueryDelegationRewardsResponse - (*QueryDelegationTotalRewardsRequest)(nil), // 10: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsRequest - (*QueryDelegationTotalRewardsResponse)(nil), // 11: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse - (*QueryDelegatorValidatorsRequest)(nil), // 12: cosmos.distribution.v1beta1.QueryDelegatorValidatorsRequest - (*QueryDelegatorValidatorsResponse)(nil), // 13: cosmos.distribution.v1beta1.QueryDelegatorValidatorsResponse - (*QueryDelegatorWithdrawAddressRequest)(nil), // 14: cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressRequest - (*QueryDelegatorWithdrawAddressResponse)(nil), // 15: cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressResponse - (*QueryCommunityPoolRequest)(nil), // 16: cosmos.distribution.v1beta1.QueryCommunityPoolRequest - (*QueryCommunityPoolResponse)(nil), // 17: cosmos.distribution.v1beta1.QueryCommunityPoolResponse - (*Params)(nil), // 18: cosmos.distribution.v1beta1.Params - (*ValidatorOutstandingRewards)(nil), // 19: cosmos.distribution.v1beta1.ValidatorOutstandingRewards - (*ValidatorAccumulatedCommission)(nil), // 20: cosmos.distribution.v1beta1.ValidatorAccumulatedCommission - (*v1beta1.PageRequest)(nil), // 21: cosmos.base.query.v1beta1.PageRequest - (*ValidatorSlashEvent)(nil), // 22: cosmos.distribution.v1beta1.ValidatorSlashEvent - (*v1beta1.PageResponse)(nil), // 23: cosmos.base.query.v1beta1.PageResponse - (*v1beta11.DecCoin)(nil), // 24: cosmos.base.v1beta1.DecCoin - (*DelegationDelegatorReward)(nil), // 25: cosmos.distribution.v1beta1.DelegationDelegatorReward + (*QueryValidatorDistributionInfoRequest)(nil), // 2: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest + (*QueryValidatorDistributionInfoResponse)(nil), // 3: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse + (*QueryValidatorOutstandingRewardsRequest)(nil), // 4: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsRequest + (*QueryValidatorOutstandingRewardsResponse)(nil), // 5: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse + (*QueryValidatorCommissionRequest)(nil), // 6: cosmos.distribution.v1beta1.QueryValidatorCommissionRequest + (*QueryValidatorCommissionResponse)(nil), // 7: cosmos.distribution.v1beta1.QueryValidatorCommissionResponse + (*QueryValidatorSlashesRequest)(nil), // 8: cosmos.distribution.v1beta1.QueryValidatorSlashesRequest + (*QueryValidatorSlashesResponse)(nil), // 9: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse + (*QueryDelegationRewardsRequest)(nil), // 10: cosmos.distribution.v1beta1.QueryDelegationRewardsRequest + (*QueryDelegationRewardsResponse)(nil), // 11: cosmos.distribution.v1beta1.QueryDelegationRewardsResponse + (*QueryDelegationTotalRewardsRequest)(nil), // 12: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsRequest + (*QueryDelegationTotalRewardsResponse)(nil), // 13: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse + (*QueryDelegatorValidatorsRequest)(nil), // 14: cosmos.distribution.v1beta1.QueryDelegatorValidatorsRequest + (*QueryDelegatorValidatorsResponse)(nil), // 15: cosmos.distribution.v1beta1.QueryDelegatorValidatorsResponse + (*QueryDelegatorWithdrawAddressRequest)(nil), // 16: cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressRequest + (*QueryDelegatorWithdrawAddressResponse)(nil), // 17: cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressResponse + (*QueryCommunityPoolRequest)(nil), // 18: cosmos.distribution.v1beta1.QueryCommunityPoolRequest + (*QueryCommunityPoolResponse)(nil), // 19: cosmos.distribution.v1beta1.QueryCommunityPoolResponse + (*Params)(nil), // 20: cosmos.distribution.v1beta1.Params + (*v1beta1.DecCoin)(nil), // 21: cosmos.base.v1beta1.DecCoin + (*ValidatorOutstandingRewards)(nil), // 22: cosmos.distribution.v1beta1.ValidatorOutstandingRewards + (*ValidatorAccumulatedCommission)(nil), // 23: cosmos.distribution.v1beta1.ValidatorAccumulatedCommission + (*v1beta11.PageRequest)(nil), // 24: cosmos.base.query.v1beta1.PageRequest + (*ValidatorSlashEvent)(nil), // 25: cosmos.distribution.v1beta1.ValidatorSlashEvent + (*v1beta11.PageResponse)(nil), // 26: cosmos.base.query.v1beta1.PageResponse + (*DelegationDelegatorReward)(nil), // 27: cosmos.distribution.v1beta1.DelegationDelegatorReward } var file_cosmos_distribution_v1beta1_query_proto_depIdxs = []int32{ - 18, // 0: cosmos.distribution.v1beta1.QueryParamsResponse.params:type_name -> cosmos.distribution.v1beta1.Params - 19, // 1: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse.rewards:type_name -> cosmos.distribution.v1beta1.ValidatorOutstandingRewards - 20, // 2: cosmos.distribution.v1beta1.QueryValidatorCommissionResponse.commission:type_name -> cosmos.distribution.v1beta1.ValidatorAccumulatedCommission - 21, // 3: cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest - 22, // 4: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.slashes:type_name -> cosmos.distribution.v1beta1.ValidatorSlashEvent - 23, // 5: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse - 24, // 6: cosmos.distribution.v1beta1.QueryDelegationRewardsResponse.rewards:type_name -> cosmos.base.v1beta1.DecCoin - 25, // 7: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.rewards:type_name -> cosmos.distribution.v1beta1.DelegationDelegatorReward - 24, // 8: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.total:type_name -> cosmos.base.v1beta1.DecCoin - 24, // 9: cosmos.distribution.v1beta1.QueryCommunityPoolResponse.pool:type_name -> cosmos.base.v1beta1.DecCoin - 0, // 10: cosmos.distribution.v1beta1.Query.Params:input_type -> cosmos.distribution.v1beta1.QueryParamsRequest - 2, // 11: cosmos.distribution.v1beta1.Query.ValidatorOutstandingRewards:input_type -> cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsRequest - 4, // 12: cosmos.distribution.v1beta1.Query.ValidatorCommission:input_type -> cosmos.distribution.v1beta1.QueryValidatorCommissionRequest - 6, // 13: cosmos.distribution.v1beta1.Query.ValidatorSlashes:input_type -> cosmos.distribution.v1beta1.QueryValidatorSlashesRequest - 8, // 14: cosmos.distribution.v1beta1.Query.DelegationRewards:input_type -> cosmos.distribution.v1beta1.QueryDelegationRewardsRequest - 10, // 15: cosmos.distribution.v1beta1.Query.DelegationTotalRewards:input_type -> cosmos.distribution.v1beta1.QueryDelegationTotalRewardsRequest - 12, // 16: cosmos.distribution.v1beta1.Query.DelegatorValidators:input_type -> cosmos.distribution.v1beta1.QueryDelegatorValidatorsRequest - 14, // 17: cosmos.distribution.v1beta1.Query.DelegatorWithdrawAddress:input_type -> cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressRequest - 16, // 18: cosmos.distribution.v1beta1.Query.CommunityPool:input_type -> cosmos.distribution.v1beta1.QueryCommunityPoolRequest - 1, // 19: cosmos.distribution.v1beta1.Query.Params:output_type -> cosmos.distribution.v1beta1.QueryParamsResponse - 3, // 20: cosmos.distribution.v1beta1.Query.ValidatorOutstandingRewards:output_type -> cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse - 5, // 21: cosmos.distribution.v1beta1.Query.ValidatorCommission:output_type -> cosmos.distribution.v1beta1.QueryValidatorCommissionResponse - 7, // 22: cosmos.distribution.v1beta1.Query.ValidatorSlashes:output_type -> cosmos.distribution.v1beta1.QueryValidatorSlashesResponse - 9, // 23: cosmos.distribution.v1beta1.Query.DelegationRewards:output_type -> cosmos.distribution.v1beta1.QueryDelegationRewardsResponse - 11, // 24: cosmos.distribution.v1beta1.Query.DelegationTotalRewards:output_type -> cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse - 13, // 25: cosmos.distribution.v1beta1.Query.DelegatorValidators:output_type -> cosmos.distribution.v1beta1.QueryDelegatorValidatorsResponse - 15, // 26: cosmos.distribution.v1beta1.Query.DelegatorWithdrawAddress:output_type -> cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressResponse - 17, // 27: cosmos.distribution.v1beta1.Query.CommunityPool:output_type -> cosmos.distribution.v1beta1.QueryCommunityPoolResponse - 19, // [19:28] is the sub-list for method output_type - 10, // [10:19] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 20, // 0: cosmos.distribution.v1beta1.QueryParamsResponse.params:type_name -> cosmos.distribution.v1beta1.Params + 21, // 1: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.self_bond_rewards:type_name -> cosmos.base.v1beta1.DecCoin + 21, // 2: cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse.commission:type_name -> cosmos.base.v1beta1.DecCoin + 22, // 3: cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse.rewards:type_name -> cosmos.distribution.v1beta1.ValidatorOutstandingRewards + 23, // 4: cosmos.distribution.v1beta1.QueryValidatorCommissionResponse.commission:type_name -> cosmos.distribution.v1beta1.ValidatorAccumulatedCommission + 24, // 5: cosmos.distribution.v1beta1.QueryValidatorSlashesRequest.pagination:type_name -> cosmos.base.query.v1beta1.PageRequest + 25, // 6: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.slashes:type_name -> cosmos.distribution.v1beta1.ValidatorSlashEvent + 26, // 7: cosmos.distribution.v1beta1.QueryValidatorSlashesResponse.pagination:type_name -> cosmos.base.query.v1beta1.PageResponse + 21, // 8: cosmos.distribution.v1beta1.QueryDelegationRewardsResponse.rewards:type_name -> cosmos.base.v1beta1.DecCoin + 27, // 9: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.rewards:type_name -> cosmos.distribution.v1beta1.DelegationDelegatorReward + 21, // 10: cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse.total:type_name -> cosmos.base.v1beta1.DecCoin + 21, // 11: cosmos.distribution.v1beta1.QueryCommunityPoolResponse.pool:type_name -> cosmos.base.v1beta1.DecCoin + 0, // 12: cosmos.distribution.v1beta1.Query.Params:input_type -> cosmos.distribution.v1beta1.QueryParamsRequest + 2, // 13: cosmos.distribution.v1beta1.Query.ValidatorDistributionInfo:input_type -> cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest + 4, // 14: cosmos.distribution.v1beta1.Query.ValidatorOutstandingRewards:input_type -> cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsRequest + 6, // 15: cosmos.distribution.v1beta1.Query.ValidatorCommission:input_type -> cosmos.distribution.v1beta1.QueryValidatorCommissionRequest + 8, // 16: cosmos.distribution.v1beta1.Query.ValidatorSlashes:input_type -> cosmos.distribution.v1beta1.QueryValidatorSlashesRequest + 10, // 17: cosmos.distribution.v1beta1.Query.DelegationRewards:input_type -> cosmos.distribution.v1beta1.QueryDelegationRewardsRequest + 12, // 18: cosmos.distribution.v1beta1.Query.DelegationTotalRewards:input_type -> cosmos.distribution.v1beta1.QueryDelegationTotalRewardsRequest + 14, // 19: cosmos.distribution.v1beta1.Query.DelegatorValidators:input_type -> cosmos.distribution.v1beta1.QueryDelegatorValidatorsRequest + 16, // 20: cosmos.distribution.v1beta1.Query.DelegatorWithdrawAddress:input_type -> cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressRequest + 18, // 21: cosmos.distribution.v1beta1.Query.CommunityPool:input_type -> cosmos.distribution.v1beta1.QueryCommunityPoolRequest + 1, // 22: cosmos.distribution.v1beta1.Query.Params:output_type -> cosmos.distribution.v1beta1.QueryParamsResponse + 3, // 23: cosmos.distribution.v1beta1.Query.ValidatorDistributionInfo:output_type -> cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse + 5, // 24: cosmos.distribution.v1beta1.Query.ValidatorOutstandingRewards:output_type -> cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse + 7, // 25: cosmos.distribution.v1beta1.Query.ValidatorCommission:output_type -> cosmos.distribution.v1beta1.QueryValidatorCommissionResponse + 9, // 26: cosmos.distribution.v1beta1.Query.ValidatorSlashes:output_type -> cosmos.distribution.v1beta1.QueryValidatorSlashesResponse + 11, // 27: cosmos.distribution.v1beta1.Query.DelegationRewards:output_type -> cosmos.distribution.v1beta1.QueryDelegationRewardsResponse + 13, // 28: cosmos.distribution.v1beta1.Query.DelegationTotalRewards:output_type -> cosmos.distribution.v1beta1.QueryDelegationTotalRewardsResponse + 15, // 29: cosmos.distribution.v1beta1.Query.DelegatorValidators:output_type -> cosmos.distribution.v1beta1.QueryDelegatorValidatorsResponse + 17, // 30: cosmos.distribution.v1beta1.Query.DelegatorWithdrawAddress:output_type -> cosmos.distribution.v1beta1.QueryDelegatorWithdrawAddressResponse + 19, // 31: cosmos.distribution.v1beta1.Query.CommunityPool:output_type -> cosmos.distribution.v1beta1.QueryCommunityPoolResponse + 22, // [22:32] is the sub-list for method output_type + 12, // [12:22] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_cosmos_distribution_v1beta1_query_proto_init() } @@ -9454,7 +10712,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorOutstandingRewardsRequest); i { + switch v := v.(*QueryValidatorDistributionInfoRequest); i { case 0: return &v.state case 1: @@ -9466,7 +10724,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorOutstandingRewardsResponse); i { + switch v := v.(*QueryValidatorDistributionInfoResponse); i { case 0: return &v.state case 1: @@ -9478,7 +10736,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorCommissionRequest); i { + switch v := v.(*QueryValidatorOutstandingRewardsRequest); i { case 0: return &v.state case 1: @@ -9490,7 +10748,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorCommissionResponse); i { + switch v := v.(*QueryValidatorOutstandingRewardsResponse); i { case 0: return &v.state case 1: @@ -9502,7 +10760,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorSlashesRequest); i { + switch v := v.(*QueryValidatorCommissionRequest); i { case 0: return &v.state case 1: @@ -9514,7 +10772,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryValidatorSlashesResponse); i { + switch v := v.(*QueryValidatorCommissionResponse); i { case 0: return &v.state case 1: @@ -9526,7 +10784,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegationRewardsRequest); i { + switch v := v.(*QueryValidatorSlashesRequest); i { case 0: return &v.state case 1: @@ -9538,7 +10796,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegationRewardsResponse); i { + switch v := v.(*QueryValidatorSlashesResponse); i { case 0: return &v.state case 1: @@ -9550,7 +10808,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegationTotalRewardsRequest); i { + switch v := v.(*QueryDelegationRewardsRequest); i { case 0: return &v.state case 1: @@ -9562,7 +10820,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegationTotalRewardsResponse); i { + switch v := v.(*QueryDelegationRewardsResponse); i { case 0: return &v.state case 1: @@ -9574,7 +10832,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegatorValidatorsRequest); i { + switch v := v.(*QueryDelegationTotalRewardsRequest); i { case 0: return &v.state case 1: @@ -9586,7 +10844,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegatorValidatorsResponse); i { + switch v := v.(*QueryDelegationTotalRewardsResponse); i { case 0: return &v.state case 1: @@ -9598,7 +10856,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegatorWithdrawAddressRequest); i { + switch v := v.(*QueryDelegatorValidatorsRequest); i { case 0: return &v.state case 1: @@ -9610,7 +10868,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryDelegatorWithdrawAddressResponse); i { + switch v := v.(*QueryDelegatorValidatorsResponse); i { case 0: return &v.state case 1: @@ -9622,7 +10880,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*QueryCommunityPoolRequest); i { + switch v := v.(*QueryDelegatorWithdrawAddressRequest); i { case 0: return &v.state case 1: @@ -9634,6 +10892,30 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { } } file_cosmos_distribution_v1beta1_query_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryDelegatorWithdrawAddressResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_distribution_v1beta1_query_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*QueryCommunityPoolRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_cosmos_distribution_v1beta1_query_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*QueryCommunityPoolResponse); i { case 0: return &v.state @@ -9652,7 +10934,7 @@ func file_cosmos_distribution_v1beta1_query_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_cosmos_distribution_v1beta1_query_proto_rawDesc, NumEnums: 0, - NumMessages: 18, + NumMessages: 20, NumExtensions: 0, NumServices: 1, }, diff --git a/api/cosmos/distribution/v1beta1/query_grpc.pb.go b/api/cosmos/distribution/v1beta1/query_grpc.pb.go index 1e15d39c68c3..f360bf192133 100644 --- a/api/cosmos/distribution/v1beta1/query_grpc.pb.go +++ b/api/cosmos/distribution/v1beta1/query_grpc.pb.go @@ -24,6 +24,8 @@ const _ = grpc.SupportPackageIsVersion7 type QueryClient interface { // Params queries params of the distribution module. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator + ValidatorDistributionInfo(ctx context.Context, in *QueryValidatorDistributionInfoRequest, opts ...grpc.CallOption) (*QueryValidatorDistributionInfoResponse, error) // ValidatorOutstandingRewards queries rewards of a validator address. ValidatorOutstandingRewards(ctx context.Context, in *QueryValidatorOutstandingRewardsRequest, opts ...grpc.CallOption) (*QueryValidatorOutstandingRewardsResponse, error) // ValidatorCommission queries accumulated commission for a validator. @@ -60,6 +62,15 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } +func (c *queryClient) ValidatorDistributionInfo(ctx context.Context, in *QueryValidatorDistributionInfoRequest, opts ...grpc.CallOption) (*QueryValidatorDistributionInfoResponse, error) { + out := new(QueryValidatorDistributionInfoResponse) + err := c.cc.Invoke(ctx, "/cosmos.distribution.v1beta1.Query/ValidatorDistributionInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) ValidatorOutstandingRewards(ctx context.Context, in *QueryValidatorOutstandingRewardsRequest, opts ...grpc.CallOption) (*QueryValidatorOutstandingRewardsResponse, error) { out := new(QueryValidatorOutstandingRewardsResponse) err := c.cc.Invoke(ctx, "/cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards", in, out, opts...) @@ -138,6 +149,8 @@ func (c *queryClient) CommunityPool(ctx context.Context, in *QueryCommunityPoolR type QueryServer interface { // Params queries params of the distribution module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator + ValidatorDistributionInfo(context.Context, *QueryValidatorDistributionInfoRequest) (*QueryValidatorDistributionInfoResponse, error) // ValidatorOutstandingRewards queries rewards of a validator address. ValidatorOutstandingRewards(context.Context, *QueryValidatorOutstandingRewardsRequest) (*QueryValidatorOutstandingRewardsResponse, error) // ValidatorCommission queries accumulated commission for a validator. @@ -165,6 +178,9 @@ type UnimplementedQueryServer struct { func (UnimplementedQueryServer) Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } +func (UnimplementedQueryServer) ValidatorDistributionInfo(context.Context, *QueryValidatorDistributionInfoRequest) (*QueryValidatorDistributionInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidatorDistributionInfo not implemented") +} func (UnimplementedQueryServer) ValidatorOutstandingRewards(context.Context, *QueryValidatorOutstandingRewardsRequest) (*QueryValidatorOutstandingRewardsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ValidatorOutstandingRewards not implemented") } @@ -220,6 +236,24 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Query_ValidatorDistributionInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryValidatorDistributionInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ValidatorDistributionInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.distribution.v1beta1.Query/ValidatorDistributionInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ValidatorDistributionInfo(ctx, req.(*QueryValidatorDistributionInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_ValidatorOutstandingRewards_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryValidatorOutstandingRewardsRequest) if err := dec(in); err != nil { @@ -375,6 +409,10 @@ var Query_ServiceDesc = grpc.ServiceDesc{ MethodName: "Params", Handler: _Query_Params_Handler, }, + { + MethodName: "ValidatorDistributionInfo", + Handler: _Query_ValidatorDistributionInfo_Handler, + }, { MethodName: "ValidatorOutstandingRewards", Handler: _Query_ValidatorOutstandingRewards_Handler, diff --git a/proto/cosmos/distribution/v1beta1/query.proto b/proto/cosmos/distribution/v1beta1/query.proto index a09413fc9904..bb10d59b1a87 100644 --- a/proto/cosmos/distribution/v1beta1/query.proto +++ b/proto/cosmos/distribution/v1beta1/query.proto @@ -17,6 +17,12 @@ service Query { option (google.api.http).get = "/cosmos/distribution/v1beta1/params"; } + // ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator + rpc ValidatorDistributionInfo(QueryValidatorDistributionInfoRequest) + returns (QueryValidatorDistributionInfoResponse) { + option (google.api.http).get = "/cosmos/distribution/v1beta1/validators/{validator_address}"; + } + // ValidatorOutstandingRewards queries rewards of a validator address. rpc ValidatorOutstandingRewards(QueryValidatorOutstandingRewardsRequest) returns (QueryValidatorOutstandingRewardsResponse) { @@ -74,6 +80,26 @@ message QueryParamsResponse { Params params = 1 [(gogoproto.nullable) = false]; } +// QueryValidatorDistributionInfoRequest is the request type for the Query/ValidatorDistributionInfo RPC method. +message QueryValidatorDistributionInfoRequest { + // validator_address defines the validator address to query for. + string validator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// QueryValidatorDistributionInfoResponse is the response type for the Query/ValidatorDistributionInfo RPC method. +message QueryValidatorDistributionInfoResponse { + // operator_address defines the validator operator address. + string operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // self_bond_rewards defines the self delegations rewards. + repeated cosmos.base.v1beta1.DecCoin self_bond_rewards = 2 + [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins"]; + // commission defines the commision the validator received. + repeated cosmos.base.v1beta1.DecCoin commission = 3 [ + (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins", + (gogoproto.nullable) = false + ]; +} + // QueryValidatorOutstandingRewardsRequest is the request type for the // Query/ValidatorOutstandingRewards RPC method. message QueryValidatorOutstandingRewardsRequest { diff --git a/x/distribution/client/cli/query.go b/x/distribution/client/cli/query.go index aa087f5f8b27..2ffdd5f1158d 100644 --- a/x/distribution/client/cli/query.go +++ b/x/distribution/client/cli/query.go @@ -26,6 +26,7 @@ func GetQueryCmd() *cobra.Command { distQueryCmd.AddCommand( GetCmdQueryParams(), + GetCmdQueryValidatorDistributionInfo(), GetCmdQueryValidatorOutstandingRewards(), GetCmdQueryValidatorCommission(), GetCmdQueryValidatorSlashes(), @@ -62,6 +63,50 @@ func GetCmdQueryParams() *cobra.Command { return cmd } +// GetCmdQueryValidatorDistributionInfo implements the query validator distribution info command. +func GetCmdQueryValidatorDistributionInfo() *cobra.Command { + bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix() + + cmd := &cobra.Command{ + Use: "validator-distribution-info [validator]", + Args: cobra.ExactArgs(1), + Short: "Query validator distribution info", + Long: strings.TrimSpace( + fmt.Sprintf(`Query validator distribution info. +Example: +$ %s query distribution validator-distribution-info %s1lwjmdnks33xwnmfayc64ycprww49n33mtm92ne +`, + version.AppName, bech32PrefixValAddr, + ), + ), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + validatorAddr, err := sdk.ValAddressFromBech32(args[0]) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.ValidatorDistributionInfo(cmd.Context(), &types.QueryValidatorDistributionInfoRequest{ + ValidatorAddress: validatorAddr.String(), + }) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + // GetCmdQueryValidatorOutstandingRewards implements the query validator // outstanding rewards command. func GetCmdQueryValidatorOutstandingRewards() *cobra.Command { diff --git a/x/distribution/client/testutil/grpc_query_suite.go b/x/distribution/client/testutil/grpc_query_suite.go index d4ea3d51bb5c..5404d540e85a 100644 --- a/x/distribution/client/testutil/grpc_query_suite.go +++ b/x/distribution/client/testutil/grpc_query_suite.go @@ -75,6 +75,44 @@ func (s *GRPCQueryTestSuite) TestQueryParamsGRPC() { } } +func (s *GRPCQueryTestSuite) TestQueryValidatorDistributionInfoGRPC() { + val := s.network.Validators[0] + baseURL := val.APIAddress + + testCases := []struct { + name string + url string + expErr bool + respType proto.Message + }{ + { + "gRPC request with wrong validator address", + fmt.Sprintf("%s/cosmos/distribution/v1beta1/validators/%s", baseURL, "wrongAddress"), + true, + &types.QueryValidatorDistributionInfoResponse{}, + }, + { + "gRPC request with valid validator address ", + fmt.Sprintf("%s/cosmos/distribution/v1beta1/validators/%s", baseURL, val.ValAddress.String()), + false, + &types.QueryValidatorDistributionInfoResponse{}, + }, + } + + for _, tc := range testCases { + tc := tc + resp, err := rest.GetRequest(tc.url) + s.Run(tc.name, func() { + if tc.expErr { + s.Require().Error(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + } else { + s.Require().NoError(err) + s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(resp, tc.respType)) + } + }) + } +} + func (s *GRPCQueryTestSuite) TestQueryOutstandingRewardsGRPC() { val := s.network.Validators[0] baseURL := val.APIAddress diff --git a/x/distribution/client/testutil/suite.go b/x/distribution/client/testutil/suite.go index 2bd89cc5fb16..6967d4f34545 100644 --- a/x/distribution/client/testutil/suite.go +++ b/x/distribution/client/testutil/suite.go @@ -108,6 +108,48 @@ withdraw_addr_enabled: true`, } } +func (s *IntegrationTestSuite) TestGetCmdQueryValidatorDistributionInfo() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expErr bool + }{ + { + "invalid val address", + []string{"invalid address", fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + true, + }, + { + "json output", + []string{val.ValAddress.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + false, + }, + { + "text output", + []string{val.ValAddress.String(), fmt.Sprintf("--%s=text", tmcli.OutputFlag)}, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryValidatorDistributionInfo() + clientCtx := val.ClientCtx + + _, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + } + }) + } +} + func (s *IntegrationTestSuite) TestGetCmdQueryValidatorOutstandingRewards() { val := s.network.Validators[0] diff --git a/x/distribution/keeper/grpc_query.go b/x/distribution/keeper/grpc_query.go index c511b5240251..b63ac4328938 100644 --- a/x/distribution/keeper/grpc_query.go +++ b/x/distribution/keeper/grpc_query.go @@ -32,6 +32,49 @@ func (k Querier) Params(c context.Context, req *types.QueryParamsRequest) (*type return &types.QueryParamsResponse{Params: params}, nil } +// ValidatorDistributionInfo query validator's commission and self-delegation rewards +func (k Querier) ValidatorDistributionInfo(c context.Context, req *types.QueryValidatorDistributionInfoRequest) (*types.QueryValidatorDistributionInfoResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + + if req.ValidatorAddress == "" { + return nil, status.Error(codes.InvalidArgument, "empty validator address") + } + + ctx := sdk.UnwrapSDKContext(c) + + valAdr, err := sdk.ValAddressFromBech32(req.ValidatorAddress) + if err != nil { + return nil, err + } + + // self-delegation rewards + val := k.stakingKeeper.Validator(ctx, valAdr) + if val == nil { + return nil, sdkerrors.Wrap(types.ErrNoValidatorExists, req.ValidatorAddress) + } + + delAdr := sdk.AccAddress(valAdr) + + del := k.stakingKeeper.Delegation(ctx, delAdr, valAdr) + if del == nil { + return nil, types.ErrNoDelegationExists + } + + endingPeriod := k.IncrementValidatorPeriod(ctx, val) + rewards := k.CalculateDelegationRewards(ctx, val, del, endingPeriod) + + // validator's commission + validatorCommission := k.GetValidatorAccumulatedCommission(ctx, valAdr) + + return &types.QueryValidatorDistributionInfoResponse{ + Commission: validatorCommission.Commission, + OperatorAddress: delAdr.String(), + SelfBondRewards: rewards, + }, nil +} + // ValidatorOutstandingRewards queries rewards of a validator address func (k Querier) ValidatorOutstandingRewards(c context.Context, req *types.QueryValidatorOutstandingRewardsRequest) (*types.QueryValidatorOutstandingRewardsResponse, error) { if req == nil { diff --git a/x/distribution/types/query.pb.go b/x/distribution/types/query.pb.go index b6a794bfbf45..5e94d2665c84 100644 --- a/x/distribution/types/query.pb.go +++ b/x/distribution/types/query.pb.go @@ -116,6 +116,118 @@ func (m *QueryParamsResponse) GetParams() Params { return Params{} } +// QueryValidatorDistributionInfoRequest is the request type for the Query/ValidatorDistributionInfo RPC method. +type QueryValidatorDistributionInfoRequest struct { + // validator_address defines the validator address to query for. + ValidatorAddress string `protobuf:"bytes,1,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` +} + +func (m *QueryValidatorDistributionInfoRequest) Reset() { *m = QueryValidatorDistributionInfoRequest{} } +func (m *QueryValidatorDistributionInfoRequest) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorDistributionInfoRequest) ProtoMessage() {} +func (*QueryValidatorDistributionInfoRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_5efd02cbc06efdc9, []int{2} +} +func (m *QueryValidatorDistributionInfoRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorDistributionInfoRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorDistributionInfoRequest.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 *QueryValidatorDistributionInfoRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorDistributionInfoRequest.Merge(m, src) +} +func (m *QueryValidatorDistributionInfoRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorDistributionInfoRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorDistributionInfoRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorDistributionInfoRequest proto.InternalMessageInfo + +func (m *QueryValidatorDistributionInfoRequest) GetValidatorAddress() string { + if m != nil { + return m.ValidatorAddress + } + return "" +} + +// QueryValidatorDistributionInfoResponse is the response type for the Query/ValidatorDistributionInfo RPC method. +type QueryValidatorDistributionInfoResponse struct { + // operator_address defines the validator operator address. + OperatorAddress string `protobuf:"bytes,1,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` + // self_bond_rewards defines the self delegations rewards. + SelfBondRewards github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,2,rep,name=self_bond_rewards,json=selfBondRewards,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"self_bond_rewards"` + // commission defines the commision the validator received. + Commission github_com_cosmos_cosmos_sdk_types.DecCoins `protobuf:"bytes,3,rep,name=commission,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.DecCoins" json:"commission"` +} + +func (m *QueryValidatorDistributionInfoResponse) Reset() { + *m = QueryValidatorDistributionInfoResponse{} +} +func (m *QueryValidatorDistributionInfoResponse) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorDistributionInfoResponse) ProtoMessage() {} +func (*QueryValidatorDistributionInfoResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5efd02cbc06efdc9, []int{3} +} +func (m *QueryValidatorDistributionInfoResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorDistributionInfoResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorDistributionInfoResponse.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 *QueryValidatorDistributionInfoResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorDistributionInfoResponse.Merge(m, src) +} +func (m *QueryValidatorDistributionInfoResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorDistributionInfoResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorDistributionInfoResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorDistributionInfoResponse proto.InternalMessageInfo + +func (m *QueryValidatorDistributionInfoResponse) GetOperatorAddress() string { + if m != nil { + return m.OperatorAddress + } + return "" +} + +func (m *QueryValidatorDistributionInfoResponse) GetSelfBondRewards() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.SelfBondRewards + } + return nil +} + +func (m *QueryValidatorDistributionInfoResponse) GetCommission() github_com_cosmos_cosmos_sdk_types.DecCoins { + if m != nil { + return m.Commission + } + return nil +} + // QueryValidatorOutstandingRewardsRequest is the request type for the // Query/ValidatorOutstandingRewards RPC method. type QueryValidatorOutstandingRewardsRequest struct { @@ -129,7 +241,7 @@ func (m *QueryValidatorOutstandingRewardsRequest) Reset() { func (m *QueryValidatorOutstandingRewardsRequest) String() string { return proto.CompactTextString(m) } func (*QueryValidatorOutstandingRewardsRequest) ProtoMessage() {} func (*QueryValidatorOutstandingRewardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{2} + return fileDescriptor_5efd02cbc06efdc9, []int{4} } func (m *QueryValidatorOutstandingRewardsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -177,7 +289,7 @@ func (m *QueryValidatorOutstandingRewardsResponse) Reset() { func (m *QueryValidatorOutstandingRewardsResponse) String() string { return proto.CompactTextString(m) } func (*QueryValidatorOutstandingRewardsResponse) ProtoMessage() {} func (*QueryValidatorOutstandingRewardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{3} + return fileDescriptor_5efd02cbc06efdc9, []int{5} } func (m *QueryValidatorOutstandingRewardsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -224,7 +336,7 @@ func (m *QueryValidatorCommissionRequest) Reset() { *m = QueryValidatorC func (m *QueryValidatorCommissionRequest) String() string { return proto.CompactTextString(m) } func (*QueryValidatorCommissionRequest) ProtoMessage() {} func (*QueryValidatorCommissionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{4} + return fileDescriptor_5efd02cbc06efdc9, []int{6} } func (m *QueryValidatorCommissionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -271,7 +383,7 @@ func (m *QueryValidatorCommissionResponse) Reset() { *m = QueryValidator func (m *QueryValidatorCommissionResponse) String() string { return proto.CompactTextString(m) } func (*QueryValidatorCommissionResponse) ProtoMessage() {} func (*QueryValidatorCommissionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{5} + return fileDescriptor_5efd02cbc06efdc9, []int{7} } func (m *QueryValidatorCommissionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -324,7 +436,7 @@ func (m *QueryValidatorSlashesRequest) Reset() { *m = QueryValidatorSlas func (m *QueryValidatorSlashesRequest) String() string { return proto.CompactTextString(m) } func (*QueryValidatorSlashesRequest) ProtoMessage() {} func (*QueryValidatorSlashesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{6} + return fileDescriptor_5efd02cbc06efdc9, []int{8} } func (m *QueryValidatorSlashesRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -366,7 +478,7 @@ func (m *QueryValidatorSlashesResponse) Reset() { *m = QueryValidatorSla func (m *QueryValidatorSlashesResponse) String() string { return proto.CompactTextString(m) } func (*QueryValidatorSlashesResponse) ProtoMessage() {} func (*QueryValidatorSlashesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{7} + return fileDescriptor_5efd02cbc06efdc9, []int{9} } func (m *QueryValidatorSlashesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -422,7 +534,7 @@ func (m *QueryDelegationRewardsRequest) Reset() { *m = QueryDelegationRe func (m *QueryDelegationRewardsRequest) String() string { return proto.CompactTextString(m) } func (*QueryDelegationRewardsRequest) ProtoMessage() {} func (*QueryDelegationRewardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{8} + return fileDescriptor_5efd02cbc06efdc9, []int{10} } func (m *QueryDelegationRewardsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -462,7 +574,7 @@ func (m *QueryDelegationRewardsResponse) Reset() { *m = QueryDelegationR func (m *QueryDelegationRewardsResponse) String() string { return proto.CompactTextString(m) } func (*QueryDelegationRewardsResponse) ProtoMessage() {} func (*QueryDelegationRewardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{9} + return fileDescriptor_5efd02cbc06efdc9, []int{11} } func (m *QueryDelegationRewardsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -509,7 +621,7 @@ func (m *QueryDelegationTotalRewardsRequest) Reset() { *m = QueryDelegat func (m *QueryDelegationTotalRewardsRequest) String() string { return proto.CompactTextString(m) } func (*QueryDelegationTotalRewardsRequest) ProtoMessage() {} func (*QueryDelegationTotalRewardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{10} + return fileDescriptor_5efd02cbc06efdc9, []int{12} } func (m *QueryDelegationTotalRewardsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -551,7 +663,7 @@ func (m *QueryDelegationTotalRewardsResponse) Reset() { *m = QueryDelega func (m *QueryDelegationTotalRewardsResponse) String() string { return proto.CompactTextString(m) } func (*QueryDelegationTotalRewardsResponse) ProtoMessage() {} func (*QueryDelegationTotalRewardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{11} + return fileDescriptor_5efd02cbc06efdc9, []int{13} } func (m *QueryDelegationTotalRewardsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -605,7 +717,7 @@ func (m *QueryDelegatorValidatorsRequest) Reset() { *m = QueryDelegatorV func (m *QueryDelegatorValidatorsRequest) String() string { return proto.CompactTextString(m) } func (*QueryDelegatorValidatorsRequest) ProtoMessage() {} func (*QueryDelegatorValidatorsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{12} + return fileDescriptor_5efd02cbc06efdc9, []int{14} } func (m *QueryDelegatorValidatorsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -645,7 +757,7 @@ func (m *QueryDelegatorValidatorsResponse) Reset() { *m = QueryDelegator func (m *QueryDelegatorValidatorsResponse) String() string { return proto.CompactTextString(m) } func (*QueryDelegatorValidatorsResponse) ProtoMessage() {} func (*QueryDelegatorValidatorsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{13} + return fileDescriptor_5efd02cbc06efdc9, []int{15} } func (m *QueryDelegatorValidatorsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -685,7 +797,7 @@ func (m *QueryDelegatorWithdrawAddressRequest) Reset() { *m = QueryDeleg func (m *QueryDelegatorWithdrawAddressRequest) String() string { return proto.CompactTextString(m) } func (*QueryDelegatorWithdrawAddressRequest) ProtoMessage() {} func (*QueryDelegatorWithdrawAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{14} + return fileDescriptor_5efd02cbc06efdc9, []int{16} } func (m *QueryDelegatorWithdrawAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -725,7 +837,7 @@ func (m *QueryDelegatorWithdrawAddressResponse) Reset() { *m = QueryDele func (m *QueryDelegatorWithdrawAddressResponse) String() string { return proto.CompactTextString(m) } func (*QueryDelegatorWithdrawAddressResponse) ProtoMessage() {} func (*QueryDelegatorWithdrawAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{15} + return fileDescriptor_5efd02cbc06efdc9, []int{17} } func (m *QueryDelegatorWithdrawAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -763,7 +875,7 @@ func (m *QueryCommunityPoolRequest) Reset() { *m = QueryCommunityPoolReq func (m *QueryCommunityPoolRequest) String() string { return proto.CompactTextString(m) } func (*QueryCommunityPoolRequest) ProtoMessage() {} func (*QueryCommunityPoolRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{16} + return fileDescriptor_5efd02cbc06efdc9, []int{18} } func (m *QueryCommunityPoolRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -803,7 +915,7 @@ func (m *QueryCommunityPoolResponse) Reset() { *m = QueryCommunityPoolRe func (m *QueryCommunityPoolResponse) String() string { return proto.CompactTextString(m) } func (*QueryCommunityPoolResponse) ProtoMessage() {} func (*QueryCommunityPoolResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5efd02cbc06efdc9, []int{17} + return fileDescriptor_5efd02cbc06efdc9, []int{19} } func (m *QueryCommunityPoolResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -842,6 +954,8 @@ func (m *QueryCommunityPoolResponse) GetPool() github_com_cosmos_cosmos_sdk_type func init() { proto.RegisterType((*QueryParamsRequest)(nil), "cosmos.distribution.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "cosmos.distribution.v1beta1.QueryParamsResponse") + proto.RegisterType((*QueryValidatorDistributionInfoRequest)(nil), "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoRequest") + proto.RegisterType((*QueryValidatorDistributionInfoResponse)(nil), "cosmos.distribution.v1beta1.QueryValidatorDistributionInfoResponse") proto.RegisterType((*QueryValidatorOutstandingRewardsRequest)(nil), "cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsRequest") proto.RegisterType((*QueryValidatorOutstandingRewardsResponse)(nil), "cosmos.distribution.v1beta1.QueryValidatorOutstandingRewardsResponse") proto.RegisterType((*QueryValidatorCommissionRequest)(nil), "cosmos.distribution.v1beta1.QueryValidatorCommissionRequest") @@ -865,78 +979,84 @@ func init() { } var fileDescriptor_5efd02cbc06efdc9 = []byte{ - // 1129 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x98, 0xcf, 0x6f, 0x1b, 0x45, - 0x14, 0xc7, 0x3d, 0x6e, 0x9a, 0xd2, 0x57, 0x4a, 0xd2, 0x69, 0x84, 0xdc, 0x4d, 0xb0, 0xa3, 0x0d, - 0x25, 0x11, 0x51, 0xbc, 0x4d, 0x22, 0x15, 0x68, 0x41, 0x90, 0x5f, 0xa5, 0x52, 0xab, 0x36, 0x75, - 0xab, 0xa6, 0x70, 0xb1, 0xd6, 0xde, 0xd1, 0x7a, 0x55, 0x7b, 0xc7, 0xdd, 0x19, 0xc7, 0x44, 0x55, - 0x2f, 0x94, 0x4a, 0x5c, 0x90, 0x90, 0xb8, 0xf4, 0x98, 0x33, 0x67, 0x10, 0x12, 0x7f, 0x41, 0x8f, - 0x15, 0x48, 0xa8, 0x27, 0x40, 0x09, 0x42, 0xbd, 0x70, 0xe6, 0x5a, 0x79, 0x66, 0xd6, 0xde, 0xb5, - 0xd7, 0x6b, 0x3b, 0xae, 0x4f, 0x75, 0x67, 0xe7, 0x7d, 0xdf, 0xfb, 0xbc, 0x99, 0x37, 0xef, 0x29, - 0x30, 0x5f, 0xa4, 0xac, 0x42, 0x99, 0x61, 0x39, 0x8c, 0x7b, 0x4e, 0xa1, 0xc6, 0x1d, 0xea, 0x1a, - 0xbb, 0xcb, 0x05, 0xc2, 0xcd, 0x65, 0xe3, 0x41, 0x8d, 0x78, 0x7b, 0xd9, 0xaa, 0x47, 0x39, 0xc5, - 0xd3, 0x72, 0x63, 0x36, 0xb8, 0x31, 0xab, 0x36, 0x6a, 0xef, 0x2b, 0x95, 0x82, 0xc9, 0x88, 0xb4, - 0x6a, 0x6a, 0x54, 0x4d, 0xdb, 0x71, 0x4d, 0xb1, 0x5b, 0x08, 0x69, 0x53, 0x36, 0xb5, 0xa9, 0xf8, - 0x69, 0x34, 0x7e, 0xa9, 0xd5, 0x19, 0x9b, 0x52, 0xbb, 0x4c, 0x0c, 0xb3, 0xea, 0x18, 0xa6, 0xeb, - 0x52, 0x2e, 0x4c, 0x98, 0xfa, 0x9a, 0x0e, 0xea, 0xfb, 0xca, 0x45, 0xea, 0xf8, 0x9a, 0xd9, 0x38, - 0x8a, 0x50, 0xc4, 0x72, 0xff, 0x39, 0xb9, 0x3f, 0x2f, 0xc3, 0x50, 0x64, 0xe2, 0x3f, 0xfa, 0x14, - 0xe0, 0x5b, 0x0d, 0x80, 0x6d, 0xd3, 0x33, 0x2b, 0x2c, 0x47, 0x1e, 0xd4, 0x08, 0xe3, 0xfa, 0x3d, - 0x38, 0x1b, 0x5a, 0x65, 0x55, 0xea, 0x32, 0x82, 0xd7, 0x60, 0xbc, 0x2a, 0x56, 0x52, 0x68, 0x16, - 0x2d, 0x9c, 0x5a, 0x99, 0xcb, 0xc6, 0x64, 0x29, 0x2b, 0x8d, 0xd7, 0xc7, 0x9e, 0xfd, 0x99, 0x49, - 0xe4, 0x94, 0xa1, 0x5e, 0x85, 0x79, 0xa1, 0x7c, 0xd7, 0x2c, 0x3b, 0x96, 0xc9, 0xa9, 0x77, 0xb3, - 0xc6, 0x19, 0x37, 0x5d, 0xcb, 0x71, 0xed, 0x1c, 0xa9, 0x9b, 0x9e, 0xe5, 0x07, 0x81, 0xb7, 0xe0, - 0xcc, 0xae, 0xbf, 0x2b, 0x6f, 0x5a, 0x96, 0x47, 0x98, 0x74, 0x7c, 0x72, 0x3d, 0xf5, 0xdb, 0x4f, - 0x4b, 0x53, 0xca, 0xf7, 0x9a, 0xfc, 0x72, 0x9b, 0x7b, 0x0d, 0x89, 0xc9, 0xa6, 0x89, 0x5a, 0xd7, - 0xbf, 0x41, 0xb0, 0xd0, 0xdb, 0xa5, 0x22, 0xbc, 0x07, 0x27, 0x3c, 0xb9, 0xa4, 0x10, 0x3f, 0x8c, - 0x45, 0x8c, 0x91, 0x54, 0xdc, 0xbe, 0x9c, 0x5e, 0x82, 0x4c, 0x38, 0x8a, 0x0d, 0x5a, 0xa9, 0x38, - 0x8c, 0x39, 0xd4, 0x7d, 0xcd, 0xc0, 0x4f, 0x10, 0xcc, 0x76, 0x77, 0xa5, 0x40, 0x4d, 0x80, 0x62, - 0x73, 0x55, 0xb1, 0x5e, 0xee, 0x8f, 0x75, 0xad, 0x58, 0xac, 0x55, 0x6a, 0x65, 0x93, 0x13, 0xab, - 0x25, 0xac, 0x70, 0x03, 0xa2, 0xfa, 0x93, 0x24, 0xcc, 0x84, 0xe3, 0xb8, 0x5d, 0x36, 0x59, 0x89, - 0xbc, 0xe6, 0x03, 0xc6, 0xf3, 0x30, 0xc1, 0xb8, 0xe9, 0x71, 0xc7, 0xb5, 0xf3, 0x25, 0xe2, 0xd8, - 0x25, 0x9e, 0x4a, 0xce, 0xa2, 0x85, 0xb1, 0xdc, 0x5b, 0xfe, 0xf2, 0x55, 0xb1, 0x8a, 0xe7, 0xe0, - 0x34, 0x11, 0x47, 0xe4, 0x6f, 0x3b, 0x26, 0xb6, 0xbd, 0x29, 0x17, 0xd5, 0xa6, 0x2b, 0x00, 0xad, - 0x1a, 0x4e, 0x8d, 0x89, 0xc4, 0xbc, 0xe7, 0x27, 0xa6, 0x51, 0x90, 0x59, 0xf9, 0x4c, 0xb4, 0x6e, - 0xb9, 0x4d, 0x14, 0x50, 0x2e, 0x60, 0x79, 0xe9, 0x8d, 0x6f, 0xf7, 0x33, 0x89, 0xa7, 0xfb, 0x19, - 0xa4, 0xff, 0x8a, 0xe0, 0x9d, 0x2e, 0x79, 0x50, 0x87, 0xb1, 0x0d, 0x27, 0x98, 0x5c, 0x4a, 0xa1, - 0xd9, 0x63, 0x0b, 0xa7, 0x56, 0x2e, 0xf4, 0x77, 0x12, 0x42, 0x67, 0x6b, 0x97, 0xb8, 0xdc, 0xbf, - 0x6d, 0x4a, 0x06, 0x7f, 0x1e, 0xa2, 0x48, 0x0a, 0x8a, 0xf9, 0x9e, 0x14, 0x32, 0x9c, 0x20, 0x86, - 0xfe, 0x8b, 0x1f, 0xfc, 0x26, 0x29, 0x13, 0x5b, 0xac, 0x75, 0x96, 0xa9, 0x25, 0xbf, 0x0d, 0x72, - 0x8a, 0x4d, 0x13, 0xff, 0x14, 0x23, 0x2f, 0x43, 0x72, 0xd0, 0xcb, 0x20, 0xd3, 0xfe, 0x72, 0x3f, - 0x93, 0xd0, 0xbf, 0x43, 0x90, 0xee, 0x16, 0xb9, 0xca, 0xfb, 0xfd, 0x60, 0xb5, 0x37, 0xf2, 0x3e, - 0x13, 0x4a, 0x91, 0x9f, 0x9c, 0x4d, 0x52, 0xdc, 0xa0, 0x8e, 0xbb, 0xbe, 0xda, 0xc8, 0xf1, 0x8f, - 0x7f, 0x65, 0x16, 0x6d, 0x87, 0x97, 0x6a, 0x85, 0x6c, 0x91, 0x56, 0xd4, 0x63, 0xaa, 0xfe, 0x59, - 0x62, 0xd6, 0x7d, 0x83, 0xef, 0x55, 0x09, 0xf3, 0x6d, 0x58, 0xeb, 0x01, 0xa8, 0x81, 0xde, 0x16, - 0xce, 0x1d, 0xca, 0xcd, 0xf2, 0x48, 0xb2, 0x19, 0x48, 0xc3, 0xbf, 0x08, 0xe6, 0x62, 0xfd, 0xaa, - 0x5c, 0xdc, 0x6d, 0xcf, 0xc5, 0xc5, 0xd8, 0x3b, 0xd8, 0x52, 0xdb, 0xf4, 0x7d, 0x4b, 0xc5, 0xb6, - 0x77, 0x0f, 0xdb, 0x70, 0x9c, 0x37, 0xfc, 0xa5, 0x92, 0xa3, 0xca, 0xb0, 0xd4, 0xd7, 0x3d, 0xf5, - 0xc0, 0x36, 0xe3, 0x69, 0x96, 0xc9, 0xe8, 0x92, 0x7b, 0x5d, 0xbd, 0xb4, 0x91, 0x3e, 0x55, 0x62, - 0xd3, 0x00, 0xcd, 0x5b, 0x2a, 0x73, 0x7b, 0x32, 0x17, 0x58, 0x09, 0xa8, 0xd5, 0xe1, 0xdd, 0xb0, - 0xda, 0x8e, 0xc3, 0x4b, 0x96, 0x67, 0xd6, 0x95, 0xe3, 0x91, 0x61, 0xec, 0xc2, 0xf9, 0x1e, 0x8e, - 0x15, 0xcb, 0x06, 0x4c, 0xd6, 0xd5, 0xa7, 0xbe, 0x1d, 0x4f, 0xd4, 0xc3, 0x62, 0x01, 0xbf, 0xd3, - 0x70, 0x4e, 0xf8, 0x6d, 0xb4, 0x91, 0x9a, 0xeb, 0xf0, 0xbd, 0x6d, 0x4a, 0xcb, 0xfe, 0x0c, 0xf2, - 0x18, 0x81, 0x16, 0xf5, 0x55, 0x85, 0x42, 0x60, 0xac, 0x4a, 0x69, 0x79, 0x74, 0x85, 0x2b, 0xe4, - 0x57, 0x5e, 0x4c, 0xc0, 0x71, 0x11, 0x05, 0x7e, 0x8a, 0x60, 0x5c, 0x8e, 0x34, 0xd8, 0x88, 0x2d, - 0x8d, 0xce, 0x79, 0x4a, 0xbb, 0xd0, 0xbf, 0x81, 0xc4, 0xd3, 0x17, 0xbf, 0xfe, 0xfd, 0x9f, 0x1f, - 0x92, 0xe7, 0xf1, 0x9c, 0x11, 0x37, 0xeb, 0xc9, 0xa1, 0x0a, 0x3f, 0x4e, 0xc2, 0x74, 0xcc, 0x28, - 0x82, 0x37, 0x7b, 0xbb, 0xef, 0x3d, 0x8f, 0x69, 0x5b, 0x43, 0xaa, 0x28, 0xb2, 0x1d, 0x41, 0x76, - 0x0b, 0xdf, 0x8c, 0x25, 0x6b, 0x15, 0x88, 0xf1, 0xb0, 0xa3, 0x2f, 0x3c, 0x32, 0x68, 0x4b, 0x3f, - 0xef, 0xbf, 0x34, 0x07, 0x08, 0xce, 0x46, 0x8c, 0x3c, 0xf8, 0xe3, 0x01, 0xe2, 0xee, 0x18, 0xca, - 0xb4, 0x4f, 0x8e, 0x68, 0xad, 0x68, 0x6f, 0x08, 0xda, 0xab, 0xf8, 0xca, 0x30, 0xb4, 0xad, 0xa1, - 0x0a, 0xff, 0x81, 0x60, 0xb2, 0x7d, 0x8e, 0xc0, 0x1f, 0x0d, 0x10, 0x63, 0x78, 0x06, 0xd3, 0x2e, - 0x1d, 0xc5, 0x54, 0xb1, 0x5d, 0x13, 0x6c, 0x5b, 0x78, 0x63, 0x18, 0x36, 0x7f, 0x62, 0xf9, 0x0f, - 0xc1, 0x99, 0x8e, 0x4e, 0x8d, 0xfb, 0x08, 0xaf, 0xdb, 0x60, 0xa2, 0x5d, 0x3e, 0x92, 0xad, 0x62, - 0xcb, 0x0b, 0xb6, 0x2f, 0xf0, 0x4e, 0x2c, 0x5b, 0xf3, 0x4d, 0x65, 0xc6, 0xc3, 0x8e, 0x27, 0xf9, - 0x91, 0xa1, 0x6e, 0x66, 0x14, 0x37, 0x7e, 0x89, 0xe0, 0xed, 0xe8, 0x96, 0x8c, 0x3f, 0x1d, 0x24, - 0xf0, 0x88, 0x21, 0x42, 0xfb, 0xec, 0xe8, 0x02, 0x03, 0x1d, 0x6d, 0x7f, 0xf8, 0xa2, 0x30, 0x23, - 0x3a, 0x64, 0x3f, 0x85, 0xd9, 0xbd, 0x99, 0xf7, 0x53, 0x98, 0x31, 0x6d, 0xb9, 0xcf, 0xc2, 0xec, - 0x41, 0xd8, 0xba, 0xdb, 0xf8, 0x7f, 0x04, 0xa9, 0x6e, 0xfd, 0x13, 0xaf, 0x0d, 0x10, 0x6b, 0x74, - 0xd3, 0xd7, 0xd6, 0x87, 0x91, 0x50, 0xcc, 0x77, 0x04, 0xf3, 0x0d, 0x7c, 0x7d, 0x18, 0xe6, 0xf6, - 0x01, 0x00, 0xff, 0x8c, 0xe0, 0x74, 0xa8, 0x47, 0xe3, 0x8b, 0xbd, 0x63, 0x8d, 0x6a, 0xf9, 0xda, - 0x07, 0x03, 0xdb, 0x29, 0xb0, 0x55, 0x01, 0xb6, 0x84, 0x17, 0x63, 0xc1, 0x8a, 0xbe, 0x6d, 0xbe, - 0xd1, 0xda, 0xd7, 0xaf, 0x3d, 0x3b, 0x48, 0xa3, 0xe7, 0x07, 0x69, 0xf4, 0xf7, 0x41, 0x1a, 0x7d, - 0x7f, 0x98, 0x4e, 0x3c, 0x3f, 0x4c, 0x27, 0x5e, 0x1c, 0xa6, 0x13, 0x5f, 0x2e, 0xc7, 0xce, 0x09, - 0x5f, 0x85, 0xd5, 0xc5, 0xd8, 0x50, 0x18, 0x17, 0x7f, 0x4e, 0x59, 0x7d, 0x15, 0x00, 0x00, 0xff, - 0xff, 0xc6, 0xc9, 0xca, 0xd1, 0x61, 0x12, 0x00, 0x00, + // 1228 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x4d, 0x6c, 0x1b, 0x45, + 0x14, 0xf6, 0x38, 0x69, 0x4a, 0x5f, 0x29, 0x49, 0xa6, 0x11, 0x72, 0x36, 0xc1, 0x8e, 0x36, 0xb4, + 0x89, 0x88, 0xe2, 0x6d, 0x12, 0xa9, 0x40, 0x43, 0x05, 0xb1, 0x93, 0x52, 0xd4, 0xaa, 0x4d, 0xdd, + 0xaa, 0x29, 0x5c, 0xac, 0xb5, 0x77, 0xba, 0x5e, 0xd5, 0xde, 0x71, 0x76, 0xd6, 0x09, 0x51, 0x95, + 0x0b, 0xa5, 0x12, 0x17, 0x24, 0x24, 0x2e, 0x3d, 0xe6, 0xcc, 0x19, 0x84, 0xc4, 0x99, 0x43, 0x8f, + 0x15, 0x48, 0x88, 0x13, 0x45, 0x09, 0x42, 0xe5, 0xc0, 0x99, 0x2b, 0xf2, 0xcc, 0xac, 0xbd, 0xeb, + 0x9f, 0xb5, 0x1d, 0xc7, 0xa7, 0x6c, 0xde, 0xce, 0xfb, 0xde, 0xfb, 0xde, 0xcf, 0xec, 0x97, 0xc0, + 0x5c, 0x9e, 0xb2, 0x12, 0x65, 0x9a, 0x61, 0x31, 0xd7, 0xb1, 0x72, 0x15, 0xd7, 0xa2, 0xb6, 0xb6, + 0xb3, 0x94, 0x23, 0xae, 0xbe, 0xa4, 0x6d, 0x57, 0x88, 0xb3, 0x97, 0x2c, 0x3b, 0xd4, 0xa5, 0x78, + 0x4a, 0x1c, 0x4c, 0xfa, 0x0f, 0x26, 0xe5, 0x41, 0xe5, 0x1d, 0x89, 0x92, 0xd3, 0x19, 0x11, 0x5e, + 0x35, 0x8c, 0xb2, 0x6e, 0x5a, 0xb6, 0xce, 0x4f, 0x73, 0x20, 0x65, 0xc2, 0xa4, 0x26, 0xe5, 0x8f, + 0x5a, 0xf5, 0x49, 0x5a, 0xa7, 0x4d, 0x4a, 0xcd, 0x22, 0xd1, 0xf4, 0xb2, 0xa5, 0xe9, 0xb6, 0x4d, + 0x5d, 0xee, 0xc2, 0xe4, 0xdb, 0xb8, 0x1f, 0xdf, 0x43, 0xce, 0x53, 0xcb, 0xc3, 0x4c, 0x86, 0xb1, + 0x08, 0x64, 0x2c, 0xce, 0x4f, 0x8a, 0xf3, 0x59, 0x91, 0x86, 0x64, 0xc6, 0x7f, 0x51, 0x27, 0x00, + 0xdf, 0xa9, 0x12, 0xd8, 0xd4, 0x1d, 0xbd, 0xc4, 0x32, 0x64, 0xbb, 0x42, 0x98, 0xab, 0x3e, 0x80, + 0xf3, 0x01, 0x2b, 0x2b, 0x53, 0x9b, 0x11, 0xbc, 0x06, 0x23, 0x65, 0x6e, 0x89, 0xa1, 0x19, 0x34, + 0x7f, 0x76, 0x79, 0x36, 0x19, 0x52, 0xa5, 0xa4, 0x70, 0x4e, 0x0d, 0x3f, 0xff, 0x23, 0x11, 0xc9, + 0x48, 0x47, 0xd5, 0x86, 0x0b, 0x1c, 0xf9, 0xbe, 0x5e, 0xb4, 0x0c, 0xdd, 0xa5, 0xce, 0xba, 0xcf, + 0xf5, 0x13, 0xfb, 0x21, 0x95, 0x29, 0xe0, 0x0d, 0x18, 0xdf, 0xf1, 0xce, 0x64, 0x75, 0xc3, 0x70, + 0x08, 0x13, 0x61, 0xcf, 0xa4, 0x62, 0xbf, 0x7c, 0xbf, 0x38, 0x21, 0x23, 0xaf, 0x89, 0x37, 0x77, + 0x5d, 0xc7, 0xb2, 0xcd, 0xcc, 0x58, 0xcd, 0x45, 0xda, 0xd5, 0x97, 0x51, 0xb8, 0xd8, 0x29, 0xa0, + 0x64, 0x97, 0x86, 0x31, 0x5a, 0x26, 0x4e, 0x4f, 0x01, 0x47, 0x3d, 0x0f, 0x69, 0xc6, 0xfb, 0x30, + 0xce, 0x48, 0xf1, 0x61, 0x36, 0x47, 0x6d, 0x23, 0xeb, 0x90, 0x5d, 0xdd, 0x31, 0x58, 0x2c, 0x3a, + 0x33, 0x34, 0x7f, 0x76, 0x79, 0xda, 0xab, 0x56, 0xb5, 0xad, 0xb5, 0x2a, 0xad, 0x93, 0x7c, 0x9a, + 0x5a, 0x76, 0x6a, 0xa5, 0x5a, 0xa6, 0xef, 0x5e, 0x26, 0x16, 0x4c, 0xcb, 0x2d, 0x54, 0x72, 0xc9, + 0x3c, 0x2d, 0xc9, 0x4e, 0xc9, 0x1f, 0x8b, 0xcc, 0x78, 0xa4, 0xb9, 0x7b, 0x65, 0xc2, 0x3c, 0x1f, + 0x96, 0x19, 0xad, 0xc6, 0x4a, 0x51, 0xdb, 0xc8, 0x88, 0x48, 0x78, 0x1b, 0x20, 0x4f, 0x4b, 0x25, + 0x8b, 0x31, 0x8b, 0xda, 0xb1, 0xa1, 0x41, 0xc5, 0xf5, 0x05, 0x51, 0xcb, 0x30, 0x17, 0x2c, 0xf0, + 0xed, 0x8a, 0xcb, 0x5c, 0xdd, 0x36, 0xaa, 0xf5, 0x11, 0x69, 0x9d, 0x70, 0x4f, 0xbf, 0x44, 0x30, + 0xdf, 0x39, 0xa4, 0xec, 0xea, 0x03, 0x38, 0xed, 0xb5, 0x41, 0x0c, 0xed, 0x7b, 0xa1, 0x43, 0x1b, + 0x02, 0x29, 0x27, 0xd9, 0x83, 0x53, 0x0b, 0x90, 0x08, 0x66, 0x91, 0xae, 0x15, 0xe5, 0x84, 0x09, + 0x3f, 0x45, 0x30, 0xd3, 0x3e, 0x94, 0x24, 0xaa, 0x07, 0x5a, 0x2f, 0xb8, 0xae, 0x76, 0xc7, 0x75, + 0x2d, 0x9f, 0xaf, 0x94, 0x2a, 0x45, 0xdd, 0x25, 0x46, 0x1d, 0x58, 0xd2, 0xf5, 0xb7, 0xfa, 0x69, + 0x14, 0xa6, 0x83, 0x79, 0xdc, 0x2d, 0xea, 0xac, 0x40, 0x4e, 0xb8, 0xc1, 0x78, 0x0e, 0x46, 0x99, + 0xab, 0x3b, 0xae, 0x65, 0x9b, 0xd9, 0x02, 0xb1, 0xcc, 0x82, 0x1b, 0x8b, 0xce, 0xa0, 0xf9, 0xe1, + 0xcc, 0x1b, 0x9e, 0xf9, 0x3a, 0xb7, 0xe2, 0x59, 0x38, 0x47, 0x78, 0x8b, 0xbc, 0x63, 0x43, 0xfc, + 0xd8, 0xeb, 0xc2, 0x28, 0x0f, 0x5d, 0x03, 0xa8, 0xdf, 0xca, 0xb1, 0x61, 0x5e, 0x98, 0x8b, 0x81, + 0x9d, 0x10, 0x17, 0x7f, 0xfd, 0xde, 0x32, 0x89, 0x24, 0x94, 0xf1, 0x79, 0x5e, 0x79, 0xed, 0xab, + 0x83, 0x44, 0xe4, 0xd9, 0x41, 0x02, 0xa9, 0x3f, 0x21, 0x78, 0xab, 0x4d, 0x1d, 0x64, 0x33, 0x36, + 0xe1, 0x34, 0x13, 0xa6, 0x18, 0xe2, 0x4b, 0x78, 0xa9, 0xbb, 0x4e, 0x70, 0x9c, 0x8d, 0x1d, 0x62, + 0xbb, 0xde, 0xb4, 0x49, 0x18, 0xfc, 0x71, 0x80, 0x45, 0x94, 0xb3, 0x98, 0xeb, 0xc8, 0x42, 0xa4, + 0xe3, 0xa7, 0xa1, 0xfe, 0xe8, 0x25, 0xbf, 0x4e, 0x8a, 0xc4, 0xe4, 0xb6, 0xe6, 0x35, 0x35, 0xc4, + 0xbb, 0x5e, 0xba, 0x58, 0x73, 0xf1, 0xba, 0xd8, 0x72, 0x18, 0xa2, 0xbd, 0x0e, 0x83, 0x28, 0xfb, + 0xab, 0x83, 0x44, 0x44, 0xfd, 0x1a, 0x41, 0xbc, 0x5d, 0xe6, 0xb2, 0xee, 0x8f, 0xfc, 0xdb, 0x3e, + 0xa0, 0xcb, 0xaf, 0x76, 0x01, 0x54, 0x40, 0x6d, 0x48, 0xe7, 0x1e, 0x75, 0xf5, 0xe2, 0x40, 0xaa, + 0xe9, 0x2b, 0xc3, 0xdf, 0x08, 0x66, 0x43, 0xe3, 0xca, 0x5a, 0xdc, 0x6f, 0xac, 0xc5, 0xe5, 0xd0, + 0x19, 0xac, 0xa3, 0xad, 0x7b, 0xb1, 0x05, 0x62, 0xc3, 0xbd, 0x87, 0x4d, 0x38, 0xe5, 0x56, 0xe3, + 0x0d, 0xee, 0xb3, 0x26, 0xf0, 0x55, 0x47, 0x5e, 0xb0, 0xb5, 0x7c, 0x6a, 0x6b, 0x32, 0xb8, 0xe2, + 0xde, 0x94, 0x37, 0x6d, 0xcb, 0x98, 0xb2, 0xb0, 0x71, 0x80, 0xda, 0x94, 0x8a, 0xda, 0x9e, 0xc9, + 0xf8, 0x2c, 0x3e, 0xb4, 0x5d, 0x78, 0x3b, 0x88, 0xb6, 0x65, 0xb9, 0x05, 0xc3, 0xd1, 0x77, 0x65, + 0xe0, 0x81, 0xd1, 0xd8, 0x91, 0x32, 0xab, 0x7d, 0xe0, 0xba, 0xe8, 0xd9, 0x95, 0xaf, 0xba, 0x17, + 0x3d, 0xbb, 0x41, 0x30, 0x5f, 0xdc, 0x29, 0x98, 0xe4, 0x71, 0xab, 0x9f, 0x91, 0x8a, 0x6d, 0xb9, + 0x7b, 0x9b, 0x94, 0x16, 0x3d, 0x55, 0xf9, 0x04, 0x81, 0xd2, 0xea, 0xad, 0x4c, 0x85, 0xc0, 0x70, + 0x99, 0xd2, 0xe2, 0xe0, 0x16, 0x97, 0xc3, 0x2f, 0xff, 0x3c, 0x0e, 0xa7, 0x78, 0x16, 0xf8, 0x19, + 0x82, 0x11, 0x21, 0x52, 0xb1, 0x16, 0xba, 0x1a, 0xcd, 0x0a, 0x59, 0xb9, 0xd4, 0xbd, 0x83, 0xa0, + 0xa7, 0x2e, 0x7c, 0xf1, 0xeb, 0x5f, 0xdf, 0x46, 0x2f, 0xe0, 0x59, 0x2d, 0x4c, 0xbd, 0x0b, 0x99, + 0x8c, 0xff, 0x41, 0x30, 0xd9, 0x56, 0xb1, 0xe2, 0x54, 0xe7, 0xe0, 0x9d, 0xf4, 0xb5, 0x92, 0xee, + 0x0b, 0x43, 0x72, 0x4a, 0x73, 0x4e, 0x57, 0xf1, 0x6a, 0x28, 0xa7, 0xfa, 0x6a, 0x68, 0x8f, 0x9b, + 0xbe, 0x08, 0xfb, 0xf8, 0x49, 0x14, 0xa6, 0x42, 0x64, 0x17, 0x5e, 0xef, 0x21, 0xd3, 0xb6, 0xda, + 0x53, 0xd9, 0xe8, 0x13, 0x45, 0x32, 0xde, 0xe2, 0x8c, 0xef, 0xe0, 0xdb, 0x7d, 0x30, 0xd6, 0x68, + 0x1d, 0xdf, 0xfb, 0x1b, 0x01, 0x1f, 0x22, 0x38, 0xdf, 0x42, 0xde, 0xe1, 0x0f, 0x7a, 0xc8, 0xbb, + 0x49, 0x80, 0x2a, 0x57, 0x8f, 0xe9, 0x2d, 0xd9, 0xde, 0xe2, 0x6c, 0xaf, 0xe3, 0x6b, 0xfd, 0xb0, + 0xad, 0x0b, 0x48, 0xfc, 0x1b, 0x82, 0xb1, 0x46, 0xcd, 0x84, 0xdf, 0xef, 0x21, 0xc7, 0xa0, 0xde, + 0x54, 0xae, 0x1c, 0xc7, 0x55, 0x72, 0xbb, 0xc1, 0xb9, 0x6d, 0xe0, 0x74, 0x3f, 0xdc, 0x3c, 0x75, + 0xf6, 0x2f, 0x82, 0xf1, 0x26, 0x55, 0x82, 0xbb, 0x48, 0xaf, 0x9d, 0x08, 0x53, 0x56, 0x8f, 0xe5, + 0x2b, 0xb9, 0x65, 0x39, 0xb7, 0x4f, 0xf1, 0x56, 0x28, 0xb7, 0xda, 0xf7, 0x83, 0x69, 0x8f, 0x9b, + 0x3e, 0x3f, 0xfb, 0x9a, 0x9c, 0xcc, 0x96, 0x3b, 0xfb, 0x0a, 0xc1, 0x9b, 0xad, 0xe5, 0x07, 0xfe, + 0xb0, 0x97, 0xc4, 0x5b, 0x08, 0x26, 0xe5, 0xa3, 0xe3, 0x03, 0xf4, 0xd4, 0xda, 0xee, 0xe8, 0xf3, + 0xc5, 0x6c, 0xa1, 0x06, 0xba, 0x59, 0xcc, 0xf6, 0xc2, 0xa5, 0x9b, 0xc5, 0x0c, 0x91, 0x20, 0x5d, + 0x2e, 0x66, 0x07, 0x86, 0xf5, 0xd9, 0xc6, 0xff, 0x21, 0x88, 0xb5, 0xd3, 0x0a, 0x78, 0xad, 0x87, + 0x5c, 0x5b, 0x0b, 0x1c, 0x25, 0xd5, 0x0f, 0x84, 0xe4, 0x7c, 0x8f, 0x73, 0xbe, 0x85, 0x6f, 0xf6, + 0xc3, 0xb9, 0x51, 0xec, 0xe0, 0x1f, 0x10, 0x9c, 0x0b, 0xe8, 0x11, 0x7c, 0xb9, 0x73, 0xae, 0xad, + 0xe4, 0x8d, 0xf2, 0x6e, 0xcf, 0x7e, 0x92, 0xd8, 0x0a, 0x27, 0xb6, 0x88, 0x17, 0x42, 0x89, 0xe5, + 0x3d, 0xdf, 0x6c, 0x55, 0xc6, 0xa4, 0x6e, 0x3c, 0x3f, 0x8c, 0xa3, 0x17, 0x87, 0x71, 0xf4, 0xe7, + 0x61, 0x1c, 0x7d, 0x73, 0x14, 0x8f, 0xbc, 0x38, 0x8a, 0x47, 0x7e, 0x3f, 0x8a, 0x47, 0x3e, 0x5b, + 0x0a, 0xd5, 0x44, 0x9f, 0x07, 0xd1, 0xb9, 0x44, 0xca, 0x8d, 0xf0, 0x7f, 0x06, 0xae, 0xfc, 0x1f, + 0x00, 0x00, 0xff, 0xff, 0x9e, 0xe9, 0xb3, 0x0a, 0x1f, 0x15, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -953,6 +1073,8 @@ const _ = grpc.SupportPackageIsVersion4 type QueryClient interface { // Params queries params of the distribution module. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator + ValidatorDistributionInfo(ctx context.Context, in *QueryValidatorDistributionInfoRequest, opts ...grpc.CallOption) (*QueryValidatorDistributionInfoResponse, error) // ValidatorOutstandingRewards queries rewards of a validator address. ValidatorOutstandingRewards(ctx context.Context, in *QueryValidatorOutstandingRewardsRequest, opts ...grpc.CallOption) (*QueryValidatorOutstandingRewardsResponse, error) // ValidatorCommission queries accumulated commission for a validator. @@ -989,6 +1111,15 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } +func (c *queryClient) ValidatorDistributionInfo(ctx context.Context, in *QueryValidatorDistributionInfoRequest, opts ...grpc.CallOption) (*QueryValidatorDistributionInfoResponse, error) { + out := new(QueryValidatorDistributionInfoResponse) + err := c.cc.Invoke(ctx, "/cosmos.distribution.v1beta1.Query/ValidatorDistributionInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *queryClient) ValidatorOutstandingRewards(ctx context.Context, in *QueryValidatorOutstandingRewardsRequest, opts ...grpc.CallOption) (*QueryValidatorOutstandingRewardsResponse, error) { out := new(QueryValidatorOutstandingRewardsResponse) err := c.cc.Invoke(ctx, "/cosmos.distribution.v1beta1.Query/ValidatorOutstandingRewards", in, out, opts...) @@ -1065,6 +1196,8 @@ func (c *queryClient) CommunityPool(ctx context.Context, in *QueryCommunityPoolR type QueryServer interface { // Params queries params of the distribution module. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // ValidatorDistributionInfo queries validator commision and self-delegation rewards for validator + ValidatorDistributionInfo(context.Context, *QueryValidatorDistributionInfoRequest) (*QueryValidatorDistributionInfoResponse, error) // ValidatorOutstandingRewards queries rewards of a validator address. ValidatorOutstandingRewards(context.Context, *QueryValidatorOutstandingRewardsRequest) (*QueryValidatorOutstandingRewardsResponse, error) // ValidatorCommission queries accumulated commission for a validator. @@ -1091,6 +1224,9 @@ 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) ValidatorDistributionInfo(ctx context.Context, req *QueryValidatorDistributionInfoRequest) (*QueryValidatorDistributionInfoResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ValidatorDistributionInfo not implemented") +} func (*UnimplementedQueryServer) ValidatorOutstandingRewards(ctx context.Context, req *QueryValidatorOutstandingRewardsRequest) (*QueryValidatorOutstandingRewardsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ValidatorOutstandingRewards not implemented") } @@ -1138,6 +1274,24 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Query_ValidatorDistributionInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryValidatorDistributionInfoRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).ValidatorDistributionInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.distribution.v1beta1.Query/ValidatorDistributionInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).ValidatorDistributionInfo(ctx, req.(*QueryValidatorDistributionInfoRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Query_ValidatorOutstandingRewards_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(QueryValidatorOutstandingRewardsRequest) if err := dec(in); err != nil { @@ -1290,6 +1444,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Params", Handler: _Query_Params_Handler, }, + { + MethodName: "ValidatorDistributionInfo", + Handler: _Query_ValidatorDistributionInfo_Handler, + }, { MethodName: "ValidatorOutstandingRewards", Handler: _Query_ValidatorOutstandingRewards_Handler, @@ -1383,6 +1541,94 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryValidatorDistributionInfoRequest) 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 *QueryValidatorDistributionInfoRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorDistributionInfoRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorDistributionInfoResponse) 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 *QueryValidatorDistributionInfoResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorDistributionInfoResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Commission) > 0 { + for iNdEx := len(m.Commission) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Commission[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } + if len(m.SelfBondRewards) > 0 { + for iNdEx := len(m.SelfBondRewards) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SelfBondRewards[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if len(m.OperatorAddress) > 0 { + i -= len(m.OperatorAddress) + copy(dAtA[i:], m.OperatorAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.OperatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *QueryValidatorOutstandingRewardsRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1978,6 +2224,44 @@ func (m *QueryParamsResponse) Size() (n int) { return n } +func (m *QueryValidatorDistributionInfoRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryValidatorDistributionInfoResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.OperatorAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if len(m.SelfBondRewards) > 0 { + for _, e := range m.SelfBondRewards { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + if len(m.Commission) > 0 { + for _, e := range m.Commission { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func (m *QueryValidatorOutstandingRewardsRequest) Size() (n int) { if m == nil { return 0 @@ -2351,6 +2635,238 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryValidatorDistributionInfoRequest) 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: QueryValidatorDistributionInfoRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorDistributionInfoRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", 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.ValidatorAddress = string(dAtA[iNdEx:postIndex]) + 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 *QueryValidatorDistributionInfoResponse) 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: QueryValidatorDistributionInfoResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorDistributionInfoResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", 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.OperatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SelfBondRewards", 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 + } + m.SelfBondRewards = append(m.SelfBondRewards, types.DecCoin{}) + if err := m.SelfBondRewards[len(m.SelfBondRewards)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Commission", 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 + } + m.Commission = append(m.Commission, types.DecCoin{}) + if err := m.Commission[len(m.Commission)-1].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 *QueryValidatorOutstandingRewardsRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/x/distribution/types/query.pb.gw.go b/x/distribution/types/query.pb.gw.go index 2b4ce81b8b81..9cf7f680118e 100644 --- a/x/distribution/types/query.pb.gw.go +++ b/x/distribution/types/query.pb.gw.go @@ -51,6 +51,60 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal } +func request_Query_ValidatorDistributionInfo_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorDistributionInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["validator_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "validator_address") + } + + protoReq.ValidatorAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "validator_address", err) + } + + msg, err := client.ValidatorDistributionInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_ValidatorDistributionInfo_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorDistributionInfoRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["validator_address"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "validator_address") + } + + protoReq.ValidatorAddress, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "validator_address", err) + } + + msg, err := server.ValidatorDistributionInfo(ctx, &protoReq) + return msg, metadata, err + +} + func request_Query_ValidatorOutstandingRewards_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq QueryValidatorOutstandingRewardsRequest var metadata runtime.ServerMetadata @@ -516,6 +570,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_ValidatorDistributionInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_ValidatorDistributionInfo_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ValidatorDistributionInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ValidatorOutstandingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -761,6 +838,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_ValidatorDistributionInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_ValidatorDistributionInfo_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_ValidatorDistributionInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_Query_ValidatorOutstandingRewards_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -927,6 +1024,8 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "distribution", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ValidatorDistributionInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"cosmos", "distribution", "v1beta1", "validators", "validator_address"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_ValidatorOutstandingRewards_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmos", "distribution", "v1beta1", "validators", "validator_address", "outstanding_rewards"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_ValidatorCommission_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"cosmos", "distribution", "v1beta1", "validators", "validator_address", "commission"}, "", runtime.AssumeColonVerbOpt(false))) @@ -947,6 +1046,8 @@ var ( var ( forward_Query_Params_0 = runtime.ForwardResponseMessage + forward_Query_ValidatorDistributionInfo_0 = runtime.ForwardResponseMessage + forward_Query_ValidatorOutstandingRewards_0 = runtime.ForwardResponseMessage forward_Query_ValidatorCommission_0 = runtime.ForwardResponseMessage From fe90139a2128aad31187c084342ccef943052795 Mon Sep 17 00:00:00 2001 From: Amaury <1293565+amaurym@users.noreply.github.com> Date: Mon, 5 Sep 2022 17:24:51 +0200 Subject: [PATCH 21/24] docs(textual): Require signing over raw bytes (#12910) ## Description Security concerns around what's signed, pulled out from https://github.com/cosmos/cosmos-sdk/pull/12785#discussion_r935040037. cc @peterbourgon --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- .../architecture/adr-050-sign-mode-textual.md | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/architecture/adr-050-sign-mode-textual.md b/docs/architecture/adr-050-sign-mode-textual.md index aaa7e2bfd828..05f4085916fc 100644 --- a/docs/architecture/adr-050-sign-mode-textual.md +++ b/docs/architecture/adr-050-sign-mode-textual.md @@ -5,6 +5,7 @@ - Dec 06, 2021: Initial Draft. - Feb 07, 2022: Draft read and concept-ACKed by the Ledger team. - May 16, 2022: Change status to Accepted. +- Aug 11, 2022: Require signing over tx raw bytes. ## Status @@ -115,6 +116,7 @@ Tip: *Public Key: *Sequence: *End of other signers +*Hash of raw bytes: // Hex encoding of bytes defined in #10, to prevent tx hash malleability. ``` ### 8. Encoding of the Transaction Body @@ -158,7 +160,26 @@ Grantee: cosmos1ghi...jkl End of transaction messages ``` -### 9. Signing Payload and Wire Format +### 10. Require signing over the `TxBody` and `AuthInfo` raw bytes + +Recall that the transaction bytes merklelized on chain are the Protobuf binary serialization of [TxRaw](https://github.com/cosmos/cosmos-sdk/blob/v0.46.0/proto/cosmos/tx/v1beta1/tx.proto#L33), which contains the `body_bytes` and `auth_info_bytes`. Moreover, the transaction hash is defined as the SHA256 hash of the `TxRaw` bytes. We require that the user signs over these bytes in SIGN_MODE_TEXTUAL, more specifically over the following string: + +``` +*Hash of raw bytes: +``` + +where: +- `++` denotes concatenation, +- `HEX` is the hexadecimal representation of the bytes, all in capital letters, no `0x` prefix, +- and `len()` is encoded as a Big-Endian uint64. + +This is to prevent transaction hash malleability. The point #1 about bijectivity assures that transaction `body` and `auth_info` values are not malleable, but the transaction hash still might be malleable with point #1 only, because the SIGN_MODE_TEXTUAL strings don't follow the byte ordering defined in `body_bytes` and `auth_info_bytes`. Without this hash, a malicious validator or exchange could intercept a transaction, modify its transaction hash _after_ the user signed it using SIGN_MODE_TEXTUAL (by tweaking the byte ordering inside `body_bytes` or `auth_info_bytes`), and then submit it to Tendermint. + +By including this hash in the SIGN_MODE_TEXTUAL signing payload, we keep the same level of guarantees as [SIGN_MODE_DIRECT](./adr-020-protobuf-transaction-encoding.md). + +These bytes are only shown in expert mode, hence the leading `*`. + +### 11. Signing Payload and Wire Format This string array is encoded as a single `\n`-delimited string before transmitted to the hardware device, and this long string is the signing payload signed by the hardware wallet. @@ -232,6 +253,7 @@ Amount: 10 atom // Conversion from uatom to atom using value renderer End of transaction messages Fee: 0.002 atom *Gas: 100'000 +*Hash of raw bytes: ``` #### Example 2: Multi-Msg Transaction with 3 signers @@ -320,6 +342,7 @@ Tip: 200 ibc/CDC4587874B85BEA4FCEC3CEA5A1195139799A1FEE711A07D972537E18FDA39D *Sign mode: Direct Aux *Sequence: 42 *End of other signers +*Hash of raw bytes: ``` #### Example 5: Complex Transaction with Nested Messages @@ -466,6 +489,7 @@ Fee: 0.002 atom *Sign mode: Direct *Sequence: 42 *End of other signers +*Hash of raw bytes: ``` ## Consequences From 99f5d671ef582975a45429b44549e23f4544c98e Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Mon, 5 Sep 2022 17:42:51 +0200 Subject: [PATCH 22/24] ci: use ghcr.io cosmos website-deployment image (#13156) --- .github/workflows/deploy-docs.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 4ae01c38a90a..fd45b4dd7fe9 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -20,7 +20,7 @@ jobs: contents: write # for JamesIves/github-pages-deploy-action to push changes in repo runs-on: ubuntu-latest container: - image: tendermintdev/docker-website-deployment + image: ghcr.io/cosmos/website-deployment steps: - name: Checkout πŸ›ŽοΈ uses: actions/checkout@v3 @@ -28,9 +28,8 @@ jobs: persist-credentials: false fetch-depth: 0 - - name: Install and Build πŸ”§ + - name: Build πŸ”§ run: | - apk add rsync csplit make build-docs LEDGER_ENABLED=false - name: Deploy πŸš€ From 0fbcb0b18381d19b7e556ed07e5467129678d68d Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 6 Sep 2022 03:33:31 +0200 Subject: [PATCH 23/24] ci: fix deploying action (#13157) --- .github/workflows/deploy-docs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index fd45b4dd7fe9..af5be04398ef 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -27,9 +27,11 @@ jobs: with: persist-credentials: false fetch-depth: 0 + path: "." - name: Build πŸ”§ run: | + git config --global --add safe.directory /__w/cosmos-sdk/cosmos-sdk make build-docs LEDGER_ENABLED=false - name: Deploy πŸš€ From d47970d6737207f704066cfe37d0ac055dca05a1 Mon Sep 17 00:00:00 2001 From: Ezequiel Raynaudo Date: Tue, 6 Sep 2022 10:35:01 -0300 Subject: [PATCH 24/24] fix: printf for Record protobuf (#13145) * Disable gogoproto_import for record pb * Update changelog Co-authored-by: Marko --- CHANGELOG.md | 1 + api/cosmos/crypto/keyring/v1/record.pulsar.go | 5 +- crypto/keyring/record.pb.go | 58 +++++++++---------- proto/cosmos/crypto/keyring/v1/record.proto | 1 + 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fced6ba736f..12f80bde5a4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -132,6 +132,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* [#13145](https://github.com/cosmos/cosmos-sdk/pull/13145) Fix panic when calling `String()` to a Record struct type. * [#13116](https://github.com/cosmos/cosmos-sdk/pull/13116) Fix a dead-lock in the `Group-TotalWeight` `x/group` invariant. * [#13046](https://github.com/cosmos/cosmos-sdk/pull/13046) Fix missing return statement in BaseApp.Query. * [#12548](https://github.com/cosmos/cosmos-sdk/pull/12548) Prevent signing from wrong key while using multisig. diff --git a/api/cosmos/crypto/keyring/v1/record.pulsar.go b/api/cosmos/crypto/keyring/v1/record.pulsar.go index 7a330c9c247d..345af2dffd19 100644 --- a/api/cosmos/crypto/keyring/v1/record.pulsar.go +++ b/api/cosmos/crypto/keyring/v1/record.pulsar.go @@ -2831,7 +2831,7 @@ var file_cosmos_crypto_keyring_v1_record_proto_rawDesc = []byte{ 0x6f, 0x73, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x68, 0x64, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x49, 0x50, 0x34, 0x34, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x1a, 0x07, 0x0a, 0x05, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x1a, 0x09, 0x0a, 0x07, 0x4f, 0x66, - 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0xe7, 0x01, + 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x42, 0xeb, 0x01, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x31, 0x42, 0x0b, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x63, @@ -2846,7 +2846,8 @@ var file_cosmos_crypto_keyring_v1_record_proto_rawDesc = []byte{ 0x65, 0x79, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1b, 0x43, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x3a, 0x3a, 0x4b, 0x65, 0x79, 0x72, 0x69, 0x6e, 0x67, 0x3a, - 0x3a, 0x56, 0x31, 0xc8, 0xe1, 0x1e, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x3a, 0x56, 0x31, 0xc8, 0xe1, 0x1e, 0x00, 0x98, 0xe3, 0x1e, 0x00, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/crypto/keyring/record.pb.go b/crypto/keyring/record.pb.go index 5e8df719a5c6..f8878692e096 100644 --- a/crypto/keyring/record.pb.go +++ b/crypto/keyring/record.pb.go @@ -8,7 +8,7 @@ import ( types "github.com/cosmos/cosmos-sdk/codec/types" hd "github.com/cosmos/cosmos-sdk/crypto/hd" _ "github.com/gogo/protobuf/gogoproto" - proto "github.com/gogo/protobuf/proto" + proto "github.com/golang/protobuf/proto" io "io" math "math" math_bits "math/bits" @@ -23,7 +23,7 @@ var _ = math.Inf // 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 +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package // Record is used for representing a key in the keyring. type Record struct { @@ -307,33 +307,33 @@ func init() { } var fileDescriptor_36d640103edea005 = []byte{ - // 408 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3d, 0x6b, 0xdb, 0x40, - 0x1c, 0xc6, 0xa5, 0x5a, 0x2f, 0xf5, 0x75, 0x3b, 0x3c, 0xa8, 0xa2, 0x08, 0x53, 0x68, 0x6b, 0x28, - 0xbe, 0xc3, 0xad, 0x87, 0x4e, 0x06, 0x9b, 0x0e, 0x36, 0x4e, 0x88, 0xd1, 0x98, 0x25, 0xe8, 0xe5, - 0x2c, 0x09, 0x4b, 0x3a, 0x71, 0x92, 0x0c, 0xfa, 0x16, 0xf9, 0x58, 0x1e, 0x3d, 0x66, 0x4c, 0xec, - 0x2d, 0x9f, 0x22, 0xdc, 0x9d, 0x3c, 0xc4, 0x90, 0x38, 0x93, 0x4e, 0xdc, 0xef, 0xf9, 0x3f, 0xcf, - 0x73, 0xfc, 0xc1, 0x8f, 0x80, 0x96, 0x19, 0x2d, 0x71, 0xc0, 0x9a, 0xa2, 0xa2, 0x78, 0x43, 0x1a, - 0x96, 0xe4, 0x11, 0xde, 0x8e, 0x30, 0x23, 0x01, 0x65, 0x21, 0x2a, 0x18, 0xad, 0x28, 0xb4, 0x24, - 0x86, 0x24, 0x86, 0x5a, 0x0c, 0x6d, 0x47, 0x76, 0x2f, 0xa2, 0x11, 0x15, 0x10, 0xe6, 0x27, 0xc9, - 0xdb, 0x5f, 0x23, 0x4a, 0xa3, 0x94, 0x60, 0xf1, 0xe7, 0xd7, 0x6b, 0xec, 0xe5, 0x4d, 0x7b, 0xf5, - 0xed, 0xb5, 0x63, 0x1c, 0x72, 0xb3, 0xb8, 0x35, 0xfa, 0xfe, 0xdc, 0x01, 0x86, 0x2b, 0x9c, 0x21, - 0x04, 0x5a, 0xee, 0x65, 0xc4, 0x52, 0xfb, 0xea, 0xa0, 0xeb, 0x8a, 0x33, 0x1c, 0x02, 0xb3, 0xa8, - 0xfd, 0xbb, 0x0d, 0x69, 0xac, 0x4f, 0x7d, 0x75, 0xf0, 0xe5, 0x4f, 0x0f, 0x49, 0x27, 0x74, 0x72, - 0x42, 0xd3, 0xbc, 0x71, 0x8d, 0xa2, 0xf6, 0x97, 0xa4, 0x81, 0x13, 0xa0, 0xa7, 0x34, 0xf0, 0x52, - 0xab, 0x23, 0xe0, 0x9f, 0xe8, 0xad, 0x1a, 0x48, 0x7a, 0xa2, 0x2b, 0x4e, 0xcf, 0x15, 0x57, 0xca, - 0xe0, 0x14, 0x18, 0x29, 0x09, 0x23, 0xc2, 0x2c, 0x4d, 0x0c, 0xf8, 0x75, 0x79, 0x80, 0xc0, 0xe7, - 0x8a, 0xdb, 0x0a, 0x79, 0x84, 0xac, 0x4e, 0xab, 0xc4, 0xd2, 0x3f, 0x18, 0xe1, 0x9a, 0xd3, 0x3c, - 0x82, 0x90, 0xc1, 0xff, 0xc0, 0xa4, 0xeb, 0x75, 0x9a, 0xe4, 0xc4, 0x32, 0xc4, 0x84, 0xc1, 0xc5, - 0x09, 0x37, 0x92, 0x9f, 0x2b, 0xee, 0x49, 0x6a, 0xff, 0x03, 0xba, 0xa8, 0x06, 0x31, 0xf8, 0x5c, - 0xb0, 0x64, 0x2b, 0x5e, 0x50, 0x7d, 0xe7, 0x05, 0x4d, 0x4e, 0x2d, 0x49, 0x63, 0x4f, 0x80, 0x21, - 0x3b, 0xc1, 0x31, 0xd0, 0x0a, 0xaf, 0x8a, 0x5b, 0x59, 0xff, 0x2c, 0x46, 0x1c, 0xf2, 0x04, 0xb3, - 0xc5, 0x6a, 0x3c, 0x5e, 0x79, 0xcc, 0xcb, 0x4a, 0x57, 0xd0, 0xb6, 0x09, 0x74, 0xd1, 0xc8, 0xee, - 0x02, 0xb3, 0x0d, 0x36, 0x33, 0x80, 0x96, 0x54, 0x24, 0x9b, 0x2d, 0x76, 0x4f, 0x8e, 0xb2, 0x3b, - 0x38, 0xea, 0xfe, 0xe0, 0xa8, 0x8f, 0x07, 0x47, 0xbd, 0x3f, 0x3a, 0xca, 0xfe, 0xe8, 0x28, 0x0f, - 0x47, 0x47, 0xb9, 0xfd, 0x1d, 0x25, 0x55, 0x5c, 0xfb, 0x28, 0xa0, 0x19, 0x3e, 0xed, 0x8c, 0xf8, - 0x0c, 0xcb, 0x70, 0x73, 0xb6, 0xb0, 0xbe, 0x21, 0xd2, 0xff, 0x7d, 0x09, 0x00, 0x00, 0xff, 0xff, - 0x64, 0x83, 0x0c, 0x89, 0xd0, 0x02, 0x00, 0x00, + // 411 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xbd, 0xae, 0xd3, 0x30, + 0x1c, 0xc5, 0x1d, 0x6e, 0x3e, 0xb8, 0x66, 0xb3, 0xee, 0x10, 0x22, 0x64, 0x55, 0x48, 0x40, 0x25, + 0x54, 0x5b, 0x85, 0x0e, 0x4c, 0x95, 0x5a, 0x31, 0x14, 0x95, 0x8a, 0x2a, 0x23, 0x0b, 0xca, 0x87, + 0x9b, 0x44, 0x4d, 0xe2, 0xc8, 0x49, 0x2a, 0xe5, 0x2d, 0x18, 0x79, 0xa4, 0x8e, 0x1d, 0x19, 0xa1, + 0xd9, 0x78, 0x0a, 0x64, 0x3b, 0x1d, 0xa8, 0x04, 0x65, 0x8a, 0x23, 0xff, 0xce, 0xff, 0x9c, 0x63, + 0xfd, 0xe1, 0x8b, 0x88, 0xd7, 0x05, 0xaf, 0x69, 0x24, 0xba, 0xaa, 0xe1, 0x74, 0xcf, 0x3a, 0x91, + 0x95, 0x09, 0x3d, 0x4c, 0xa9, 0x60, 0x11, 0x17, 0x31, 0xa9, 0x04, 0x6f, 0x38, 0x72, 0x35, 0x46, + 0x34, 0x46, 0x06, 0x8c, 0x1c, 0xa6, 0xde, 0x43, 0xc2, 0x13, 0xae, 0x20, 0x2a, 0x4f, 0x9a, 0xf7, + 0x9e, 0x26, 0x9c, 0x27, 0x39, 0xa3, 0xea, 0x2f, 0x6c, 0x77, 0x34, 0x28, 0xbb, 0xe1, 0xea, 0xd9, + 0x9f, 0x8e, 0x69, 0x2c, 0xcd, 0xd2, 0xc1, 0xe8, 0xf9, 0xaf, 0x3b, 0x68, 0xfb, 0xca, 0x19, 0x21, + 0x68, 0x96, 0x41, 0xc1, 0x5c, 0x63, 0x64, 0x8c, 0xef, 0x7d, 0x75, 0x46, 0x13, 0xe8, 0x54, 0x6d, + 0xf8, 0x65, 0xcf, 0x3a, 0xf7, 0xd1, 0xc8, 0x18, 0x3f, 0x79, 0xf3, 0x40, 0xb4, 0x13, 0xb9, 0x38, + 0x91, 0x45, 0xd9, 0xf9, 0x76, 0xd5, 0x86, 0x6b, 0xd6, 0xa1, 0x39, 0xb4, 0x72, 0x1e, 0x05, 0xb9, + 0x7b, 0xa7, 0xe0, 0x97, 0xe4, 0x6f, 0x35, 0x88, 0xf6, 0x24, 0x1f, 0x25, 0xbd, 0x02, 0xbe, 0x96, + 0xa1, 0x05, 0xb4, 0x73, 0x16, 0x27, 0x4c, 0xb8, 0xa6, 0x1a, 0xf0, 0xea, 0xf6, 0x00, 0x85, 0xaf, + 0x80, 0x3f, 0x08, 0x65, 0x84, 0xa2, 0xcd, 0x9b, 0xcc, 0xb5, 0xfe, 0x33, 0xc2, 0x46, 0xd2, 0x32, + 0x82, 0x92, 0xa1, 0xf7, 0xd0, 0xe1, 0xbb, 0x5d, 0x9e, 0x95, 0xcc, 0xb5, 0xd5, 0x84, 0xf1, 0xcd, + 0x09, 0x9f, 0x34, 0xbf, 0x02, 0xfe, 0x45, 0xea, 0xbd, 0x83, 0x96, 0xaa, 0x86, 0x28, 0x7c, 0x5c, + 0x89, 0xec, 0xa0, 0x5e, 0xd0, 0xf8, 0xc7, 0x0b, 0x3a, 0x92, 0x5a, 0xb3, 0xce, 0x9b, 0x43, 0x5b, + 0x77, 0x42, 0x33, 0x68, 0x56, 0x41, 0x93, 0x0e, 0xb2, 0xd1, 0x55, 0x8c, 0x34, 0x96, 0x09, 0x96, + 0x1f, 0xb6, 0xb3, 0xd9, 0x36, 0x10, 0x41, 0x51, 0xfb, 0x8a, 0xf6, 0x1c, 0x68, 0xa9, 0x46, 0xde, + 0x3d, 0x74, 0x86, 0x60, 0x4b, 0x1b, 0x9a, 0x59, 0xc3, 0x8a, 0xe5, 0xe6, 0xf8, 0x13, 0x83, 0xe3, + 0x19, 0x1b, 0xa7, 0x33, 0x36, 0x7e, 0x9c, 0xb1, 0xf1, 0xb5, 0xc7, 0xe0, 0x5b, 0x8f, 0xc1, 0xa9, + 0xc7, 0xe0, 0x7b, 0x8f, 0xc1, 0xe7, 0xd7, 0x49, 0xd6, 0xa4, 0x6d, 0x48, 0x22, 0x5e, 0xd0, 0xcb, + 0xde, 0xa8, 0xcf, 0xa4, 0x8e, 0xf7, 0x57, 0x4b, 0x1b, 0xda, 0xaa, 0xc1, 0xdb, 0xdf, 0x01, 0x00, + 0x00, 0xff, 0xff, 0x47, 0x24, 0x2f, 0xa9, 0xd4, 0x02, 0x00, 0x00, } func (m *Record) Marshal() (dAtA []byte, err error) { diff --git a/proto/cosmos/crypto/keyring/v1/record.proto b/proto/cosmos/crypto/keyring/v1/record.proto index 14c6da63eb5d..e79ea7f4666f 100644 --- a/proto/cosmos/crypto/keyring/v1/record.proto +++ b/proto/cosmos/crypto/keyring/v1/record.proto @@ -8,6 +8,7 @@ import "cosmos/crypto/hd/v1/hd.proto"; option go_package = "github.com/cosmos/cosmos-sdk/crypto/keyring"; option (gogoproto.goproto_getters_all) = false; +option (gogoproto.gogoproto_import) = false; // Record is used for representing a key in the keyring. message Record {