From 4e4a45be701e45c0792cb76111d45f2302b366d3 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:23:14 +0000 Subject: [PATCH 01/32] feat(dogfood): scaffold module --- proto/exocore/dogfood/v1/genesis.proto | 13 + proto/exocore/dogfood/v1/params.proto | 13 + proto/exocore/dogfood/v1/query.proto | 27 ++ proto/exocore/dogfood/v1/tx.proto | 8 + x/dogfood/client/cli/query.go | 33 ++ x/dogfood/client/cli/query_params.go | 36 ++ x/dogfood/client/cli/tx.go | 39 ++ x/dogfood/genesis.go | 20 + x/dogfood/keeper/keeper.go | 46 +++ x/dogfood/keeper/msg_server.go | 17 + x/dogfood/keeper/params.go | 16 + x/dogfood/keeper/query.go | 7 + x/dogfood/keeper/query_params.go | 19 + x/dogfood/module.go | 172 ++++++++ x/dogfood/types/codec.go | 19 + x/dogfood/types/errors.go | 12 + x/dogfood/types/expected_keepers.go | 18 + x/dogfood/types/genesis.go | 14 + x/dogfood/types/genesis.pb.go | 321 +++++++++++++++ x/dogfood/types/keys.go | 19 + x/dogfood/types/params.go | 39 ++ x/dogfood/types/params.pb.go | 264 ++++++++++++ x/dogfood/types/query.pb.go | 538 +++++++++++++++++++++++++ x/dogfood/types/query.pb.gw.go | 153 +++++++ x/dogfood/types/tx.pb.go | 81 ++++ x/dogfood/types/types.go | 1 + 26 files changed, 1945 insertions(+) create mode 100644 proto/exocore/dogfood/v1/genesis.proto create mode 100644 proto/exocore/dogfood/v1/params.proto create mode 100644 proto/exocore/dogfood/v1/query.proto create mode 100644 proto/exocore/dogfood/v1/tx.proto create mode 100644 x/dogfood/client/cli/query.go create mode 100644 x/dogfood/client/cli/query_params.go create mode 100644 x/dogfood/client/cli/tx.go create mode 100644 x/dogfood/genesis.go create mode 100644 x/dogfood/keeper/keeper.go create mode 100644 x/dogfood/keeper/msg_server.go create mode 100644 x/dogfood/keeper/params.go create mode 100644 x/dogfood/keeper/query.go create mode 100644 x/dogfood/keeper/query_params.go create mode 100644 x/dogfood/module.go create mode 100644 x/dogfood/types/codec.go create mode 100644 x/dogfood/types/errors.go create mode 100644 x/dogfood/types/expected_keepers.go create mode 100644 x/dogfood/types/genesis.go create mode 100644 x/dogfood/types/genesis.pb.go create mode 100644 x/dogfood/types/keys.go create mode 100644 x/dogfood/types/params.go create mode 100644 x/dogfood/types/params.pb.go create mode 100644 x/dogfood/types/query.pb.go create mode 100644 x/dogfood/types/query.pb.gw.go create mode 100644 x/dogfood/types/tx.pb.go create mode 100644 x/dogfood/types/types.go diff --git a/proto/exocore/dogfood/v1/genesis.proto b/proto/exocore/dogfood/v1/genesis.proto new file mode 100644 index 000000000..4cb6bca2f --- /dev/null +++ b/proto/exocore/dogfood/v1/genesis.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package exocore.dogfood.v1; + +import "gogoproto/gogo.proto"; +import "exocore/dogfood/v1/params.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; + +// GenesisState defines the dogfood module's genesis state. +message GenesisState { + Params params = 1 [(gogoproto.nullable) = false]; +} diff --git a/proto/exocore/dogfood/v1/params.proto b/proto/exocore/dogfood/v1/params.proto new file mode 100644 index 000000000..3305239a6 --- /dev/null +++ b/proto/exocore/dogfood/v1/params.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +package exocore.dogfood.v1; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; + +// Params defines the parameters for the module. +message Params { + option (gogoproto.goproto_stringer) = false; + +} diff --git a/proto/exocore/dogfood/v1/query.proto b/proto/exocore/dogfood/v1/query.proto new file mode 100644 index 000000000..9f1a73ae7 --- /dev/null +++ b/proto/exocore/dogfood/v1/query.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package exocore.dogfood.v1; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cosmos/base/query/v1beta1/pagination.proto"; +import "exocore/dogfood/v1/params.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; + +// Query defines the gRPC querier service. +service Query { + // Parameters queries the parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/exocore/dogfood/params"; + } +} + +// QueryParamsRequest is request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is response type for the Query/Params RPC method. +message QueryParamsResponse { + // params holds all the parameters of this module. + Params params = 1 [(gogoproto.nullable) = false]; +} \ No newline at end of file diff --git a/proto/exocore/dogfood/v1/tx.proto b/proto/exocore/dogfood/v1/tx.proto new file mode 100644 index 000000000..77c3fbde4 --- /dev/null +++ b/proto/exocore/dogfood/v1/tx.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +package exocore.dogfood.v1; + +option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; + +// Msg defines the Msg service. +service Msg {} \ No newline at end of file diff --git a/x/dogfood/client/cli/query.go b/x/dogfood/client/cli/query.go new file mode 100644 index 000000000..41b496df3 --- /dev/null +++ b/x/dogfood/client/cli/query.go @@ -0,0 +1,33 @@ +package cli + +import ( + "fmt" + // "strings" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + // "github.com/cosmos/cosmos-sdk/client/flags" + // sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +// GetQueryCmd returns the cli query commands for this module +func GetQueryCmd(queryRoute string) *cobra.Command { + // Group dogfood queries under a subcommand + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf( + "Querying commands for the %s module", + types.ModuleName, + ), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdQueryParams()) + + return cmd +} diff --git a/x/dogfood/client/cli/query_params.go b/x/dogfood/client/cli/query_params.go new file mode 100644 index 000000000..f5f252819 --- /dev/null +++ b/x/dogfood/client/cli/query_params.go @@ -0,0 +1,36 @@ +package cli + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/spf13/cobra" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +func CmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "shows the parameters of the module", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/dogfood/client/cli/tx.go b/x/dogfood/client/cli/tx.go new file mode 100644 index 000000000..ed092de4d --- /dev/null +++ b/x/dogfood/client/cli/tx.go @@ -0,0 +1,39 @@ +package cli + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + // "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +var ( + DefaultRelativePacketTimeoutTimestamp = uint64( + (time.Duration(10) * time.Minute).Nanoseconds(), + ) +) + +const ( + flagPacketTimeoutTimestamp = "packet-timeout-timestamp" + listSeparator = "," +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf( + "%s transactions subcommands", + types.ModuleName, + ), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + return cmd +} diff --git a/x/dogfood/genesis.go b/x/dogfood/genesis.go new file mode 100644 index 000000000..0c4077eb6 --- /dev/null +++ b/x/dogfood/genesis.go @@ -0,0 +1,20 @@ +package dogfood + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/keeper" + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { + k.SetParams(ctx, genState.Params) +} + +// ExportGenesis returns the module's exported genesis +func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetParams(ctx) + + return genesis +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go new file mode 100644 index 000000000..b1b480e39 --- /dev/null +++ b/x/dogfood/keeper/keeper.go @@ -0,0 +1,46 @@ +package keeper + +import ( + "fmt" + + "github.com/cometbft/cometbft/libs/log" + "github.com/cosmos/cosmos-sdk/codec" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +type ( + Keeper struct { + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + memKey storetypes.StoreKey + paramstore paramtypes.Subspace + } +) + +func NewKeeper( + cdc codec.BinaryCodec, + storeKey, + memKey storetypes.StoreKey, + ps paramtypes.Subspace, + +) *Keeper { + // set KeyTable if it has not already been set + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + return &Keeper{ + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + } +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} diff --git a/x/dogfood/keeper/msg_server.go b/x/dogfood/keeper/msg_server.go new file mode 100644 index 000000000..403b51343 --- /dev/null +++ b/x/dogfood/keeper/msg_server.go @@ -0,0 +1,17 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} diff --git a/x/dogfood/keeper/params.go b/x/dogfood/keeper/params.go new file mode 100644 index 000000000..95553df50 --- /dev/null +++ b/x/dogfood/keeper/params.go @@ -0,0 +1,16 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GetParams get all parameters as types.Params +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + return types.NewParams() +} + +// SetParams set the params +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramstore.SetParamSet(ctx, ¶ms) +} diff --git a/x/dogfood/keeper/query.go b/x/dogfood/keeper/query.go new file mode 100644 index 000000000..dfee6251a --- /dev/null +++ b/x/dogfood/keeper/query.go @@ -0,0 +1,7 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" +) + +var _ types.QueryServer = Keeper{} diff --git a/x/dogfood/keeper/query_params.go b/x/dogfood/keeper/query_params.go new file mode 100644 index 000000000..2f0e76b04 --- /dev/null +++ b/x/dogfood/keeper/query_params.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "context" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (k Keeper) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil +} diff --git a/x/dogfood/module.go b/x/dogfood/module.go new file mode 100644 index 000000000..90d11aad2 --- /dev/null +++ b/x/dogfood/module.go @@ -0,0 +1,172 @@ +package dogfood + +import ( + "context" + "encoding/json" + "fmt" + + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + abci "github.com/cometbft/cometbft/abci/types" + + "github.com/ExocoreNetwork/exocore/x/dogfood/client/cli" + "github.com/ExocoreNetwork/exocore/x/dogfood/keeper" + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" +) + +var ( + _ module.AppModule = AppModule{} + _ module.AppModuleBasic = AppModuleBasic{} +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface that defines the independent methods a +// Cosmos SDK module needs to implement. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the name of the module as a string +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the amino codec for the module, which is used to marshal +// and unmarshal structs to/from []byte in order to persist them in the module's KVStore +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers a module's interface types and their concrete implementations as +// proto.Message +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns a default GenesisState for the module, marshalled to json.RawMessage. +// The default GenesisState need to be defined by the module developer and is primarily used for +// testing +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +// ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form +func (AppModuleBasic) ValidateGenesis( + cdc codec.JSONCodec, + config client.TxEncodingConfig, + bz json.RawMessage, +) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the module +func (AppModuleBasic) RegisterGRPCGatewayRoutes( + clientCtx client.Context, + mux *runtime.ServeMux, +) { + types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) +} + +// GetTxCmd returns the root Tx command for the module. The subcommands of this root command are +// used by end-users to generate new transactions containing messages defined in the module +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the root query command for the module. The subcommands of this root +// command are used by end-users to generate new queries to the subset of the state defined by +// the module +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd(types.StoreKey) +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface that defines the inter-dependent methods that +// modules need to implement +type AppModule struct { + AppModuleBasic + + keeper keeper.Keeper + accountKeeper types.AccountKeeper + bankKeeper types.BankKeeper +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, + accountKeeper types.AccountKeeper, + bankKeeper types.BankKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + accountKeeper: accountKeeper, + bankKeeper: bankKeeper, + } +} + +// RegisterServices registers a gRPC query service to respond to the module-specific gRPC +// queries +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers the invariants of the module. If an invariant deviates from its +// predicted value, the InvariantRegistry triggers appropriate logic (most often the chain will +// be halted) +func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// InitGenesis performs the module's genesis initialization. It returns no validator updates. +func (am AppModule) InitGenesis( + ctx sdk.Context, + cdc codec.JSONCodec, + gs json.RawMessage, +) []abci.ValidatorUpdate { + var genState types.GenesisState + // Initialize global index to index in genesis state + cdc.MustUnmarshalJSON(gs, &genState) + + InitGenesis(ctx, am.keeper, genState) + + return []abci.ValidatorUpdate{} +} + +// ExportGenesis returns the module's exported genesis state as raw JSON bytes. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := ExportGenesis(ctx, am.keeper) + return cdc.MustMarshalJSON(genState) +} + +// ConsensusVersion is a sequence number for state-breaking change of the module. It should be +// incremented on each consensus-breaking change introduced by the module. To avoid wrong/empty +// versions, the initial version should be set to 1 +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// BeginBlock contains the logic that is automatically triggered at the beginning of each block +func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} + +// EndBlock contains the logic that is automatically triggered at the end of each block +func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return []abci.ValidatorUpdate{} +} diff --git a/x/dogfood/types/codec.go b/x/dogfood/types/codec.go new file mode 100644 index 000000000..b70e2a444 --- /dev/null +++ b/x/dogfood/types/codec.go @@ -0,0 +1,19 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/dogfood/types/errors.go b/x/dogfood/types/errors.go new file mode 100644 index 000000000..f279c2d27 --- /dev/null +++ b/x/dogfood/types/errors.go @@ -0,0 +1,12 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// x/dogfood module sentinel errors +var ( + ErrSample = sdkerrors.Register(ModuleName, 1100, "sample error") +) diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go new file mode 100644 index 000000000..6aa6e9778 --- /dev/null +++ b/x/dogfood/types/expected_keepers.go @@ -0,0 +1,18 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// AccountKeeper defines the expected account keeper used for simulations (noalias) +type AccountKeeper interface { + GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI + // Methods imported from account should be defined here +} + +// BankKeeper defines the expected interface needed to retrieve account balances. +type BankKeeper interface { + SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins + // Methods imported from bank should be defined here +} diff --git a/x/dogfood/types/genesis.go b/x/dogfood/types/genesis.go new file mode 100644 index 000000000..9d633ecd7 --- /dev/null +++ b/x/dogfood/types/genesis.go @@ -0,0 +1,14 @@ +package types + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + return gs.Params.Validate() +} diff --git a/x/dogfood/types/genesis.pb.go b/x/dogfood/types/genesis.pb.go new file mode 100644 index 000000000..a70ecb578 --- /dev/null +++ b/x/dogfood/types/genesis.pb.go @@ -0,0 +1,321 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/dogfood/v1/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// GenesisState defines the dogfood module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *GenesisState) Reset() { *m = GenesisState{} } +func (m *GenesisState) String() string { return proto.CompactTextString(m) } +func (*GenesisState) ProtoMessage() {} +func (*GenesisState) Descriptor() ([]byte, []int) { + return fileDescriptor_1a9d908a27866b1b, []int{0} +} +func (m *GenesisState) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GenesisState.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 *GenesisState) XXX_Merge(src proto.Message) { + xxx_messageInfo_GenesisState.Merge(m, src) +} +func (m *GenesisState) XXX_Size() int { + return m.Size() +} +func (m *GenesisState) XXX_DiscardUnknown() { + xxx_messageInfo_GenesisState.DiscardUnknown(m) +} + +var xxx_messageInfo_GenesisState proto.InternalMessageInfo + +func (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "exocore.dogfood.v1.GenesisState") +} + +func init() { proto.RegisterFile("exocore/dogfood/v1/genesis.proto", fileDescriptor_1a9d908a27866b1b) } + +var fileDescriptor_1a9d908a27866b1b = []byte{ + // 202 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xad, 0xc8, 0x4f, + 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x4f, + 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0xaa, + 0xd0, 0x83, 0xaa, 0xd0, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, + 0x58, 0x10, 0x95, 0x52, 0xf2, 0x58, 0xcc, 0x2a, 0x48, 0x2c, 0x4a, 0xcc, 0x85, 0x1a, 0xa5, 0xe4, + 0xc1, 0xc5, 0xe3, 0x0e, 0x31, 0x3b, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x82, 0x8b, 0x0d, 0x22, + 0x2f, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xa5, 0x87, 0x69, 0x97, 0x5e, 0x00, 0x58, 0x85, + 0x13, 0xcb, 0x89, 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xf5, 0x4e, 0xde, 0x27, 0x1e, 0xc9, 0x31, 0x5e, + 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, + 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x98, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, + 0xab, 0xef, 0x0a, 0x31, 0xcd, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x5b, 0x1f, 0xe6, 0xbc, 0x0a, + 0xb8, 0x03, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xae, 0x33, 0x06, 0x04, 0x00, 0x00, + 0xff, 0xff, 0xda, 0xc5, 0xe8, 0xc9, 0x0c, 0x01, 0x00, 0x00, +} + +func (m *GenesisState) 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 *GenesisState) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + return n +} + +func sovGenesis(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozGenesis(x uint64) (n int) { + return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *GenesisState) 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 ErrIntOverflowGenesis + } + 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: GenesisState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipGenesis(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowGenesis + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthGenesis + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenesis + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenesis + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go new file mode 100644 index 000000000..2a58dafee --- /dev/null +++ b/x/dogfood/types/keys.go @@ -0,0 +1,19 @@ +package types + +const ( + // ModuleName defines the module name + ModuleName = "dogfood" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the module's message routing key + RouterKey = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_dogfood" +) + +func KeyPrefix(p string) []byte { + return []byte(p) +} diff --git a/x/dogfood/types/params.go b/x/dogfood/types/params.go new file mode 100644 index 000000000..357196ad6 --- /dev/null +++ b/x/dogfood/types/params.go @@ -0,0 +1,39 @@ +package types + +import ( + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "gopkg.in/yaml.v2" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance +func NewParams() Params { + return Params{} +} + +// DefaultParams returns a default set of parameters +func DefaultParams() Params { + return NewParams() +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{} +} + +// Validate validates the set of params +func (p Params) Validate() error { + return nil +} + +// String implements the Stringer interface. +func (p Params) String() string { + out, _ := yaml.Marshal(p) + return string(out) +} diff --git a/x/dogfood/types/params.pb.go b/x/dogfood/types/params.pb.go new file mode 100644 index 000000000..60a1da67d --- /dev/null +++ b/x/dogfood/types/params.pb.go @@ -0,0 +1,264 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/dogfood/v1/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Params defines the parameters for the module. +type Params struct { +} + +func (m *Params) Reset() { *m = Params{} } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_e8747fb70c97d97f, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func init() { + proto.RegisterType((*Params)(nil), "exocore.dogfood.v1.Params") +} + +func init() { proto.RegisterFile("exocore/dogfood/v1/params.proto", fileDescriptor_e8747fb70c97d97f) } + +var fileDescriptor_e8747fb70c97d97f = []byte{ + // 160 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xad, 0xc8, 0x4f, + 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, + 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0x2a, 0xd0, + 0x83, 0x2a, 0xd0, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, 0x58, + 0x10, 0x95, 0x4a, 0x7c, 0x5c, 0x6c, 0x01, 0x60, 0x9d, 0x56, 0x2c, 0x33, 0x16, 0xc8, 0x33, 0x38, + 0x79, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, + 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x61, 0x7a, 0x66, 0x49, + 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x2b, 0xc4, 0x78, 0xbf, 0xd4, 0x92, 0xf2, 0xfc, + 0xa2, 0x6c, 0x7d, 0x98, 0x73, 0x2a, 0xe0, 0x0e, 0x2a, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, + 0xdb, 0x61, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x0e, 0x0c, 0x9a, 0xb0, 0x00, 0x00, 0x00, +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowParams + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowParams + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dogfood/types/query.pb.go b/x/dogfood/types/query.pb.go new file mode 100644 index 000000000..ec851da1b --- /dev/null +++ b/x/dogfood/types/query.pb.go @@ -0,0 +1,538 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/dogfood/v1/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/query" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryParamsRequest is request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_e23d51a3dceb1c68, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.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 *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params holds all the parameters of this module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e23d51a3dceb1c68, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "exocore.dogfood.v1.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "exocore.dogfood.v1.QueryParamsResponse") +} + +func init() { proto.RegisterFile("exocore/dogfood/v1/query.proto", fileDescriptor_e23d51a3dceb1c68) } + +var fileDescriptor_e23d51a3dceb1c68 = []byte{ + // 309 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0x3f, 0x4b, 0x03, 0x31, + 0x18, 0xc6, 0x2f, 0xa2, 0x1d, 0xe2, 0x16, 0x0b, 0xea, 0x21, 0xa9, 0x74, 0x50, 0x71, 0x48, 0xb8, + 0xba, 0x38, 0x17, 0x9c, 0x04, 0xff, 0x74, 0x74, 0xcb, 0xb5, 0x31, 0x1e, 0xda, 0x7b, 0xd3, 0x4b, + 0xee, 0x6c, 0x1d, 0xf5, 0x0b, 0x08, 0x7e, 0xa9, 0x8e, 0x05, 0x17, 0x27, 0x91, 0x3b, 0x3f, 0x88, + 0xf4, 0x12, 0x0a, 0xda, 0x82, 0x5b, 0x78, 0x9f, 0xdf, 0xf3, 0xe4, 0x79, 0x5f, 0x4c, 0xe5, 0x18, + 0xfa, 0x90, 0x49, 0x3e, 0x00, 0x75, 0x0b, 0x30, 0xe0, 0x45, 0xc4, 0x47, 0xb9, 0xcc, 0x26, 0x4c, + 0x67, 0x60, 0x81, 0x10, 0xaf, 0x33, 0xaf, 0xb3, 0x22, 0x0a, 0x9b, 0x0a, 0x14, 0xd4, 0x32, 0x9f, + 0xbf, 0x1c, 0x19, 0xee, 0x29, 0x00, 0xf5, 0x20, 0xb9, 0xd0, 0x09, 0x17, 0x69, 0x0a, 0x56, 0xd8, + 0x04, 0x52, 0xe3, 0xd5, 0xe3, 0x3e, 0x98, 0x21, 0x18, 0x1e, 0x0b, 0x23, 0xdd, 0x07, 0xbc, 0x88, + 0x62, 0x69, 0x45, 0xc4, 0xb5, 0x50, 0x49, 0x5a, 0xc3, 0x9e, 0x6d, 0xad, 0xe8, 0xa4, 0x45, 0x26, + 0x86, 0x3e, 0xac, 0xdd, 0xc4, 0xe4, 0x7a, 0x1e, 0x71, 0x55, 0x0f, 0x7b, 0x72, 0x94, 0x4b, 0x63, + 0xdb, 0x97, 0x78, 0xeb, 0xd7, 0xd4, 0x68, 0x48, 0x8d, 0x24, 0xa7, 0xb8, 0xe1, 0xcc, 0x3b, 0x68, + 0x1f, 0x1d, 0x6d, 0x76, 0x42, 0xb6, 0xbc, 0x12, 0x73, 0x9e, 0xee, 0xfa, 0xf4, 0xb3, 0x15, 0xf4, + 0x3c, 0xdf, 0x79, 0x41, 0x78, 0xa3, 0x4e, 0x24, 0x4f, 0xb8, 0xe1, 0x08, 0x72, 0xb0, 0xca, 0xbd, + 0x5c, 0x26, 0x3c, 0xfc, 0x97, 0x73, 0xf5, 0xda, 0xad, 0xe7, 0xf7, 0xef, 0xb7, 0xb5, 0x5d, 0xb2, + 0xcd, 0xff, 0x6e, 0xed, 0x5a, 0x74, 0xcf, 0xa7, 0x25, 0x45, 0xb3, 0x92, 0xa2, 0xaf, 0x92, 0xa2, + 0xd7, 0x8a, 0x06, 0xb3, 0x8a, 0x06, 0x1f, 0x15, 0x0d, 0x6e, 0x22, 0x95, 0xd8, 0xbb, 0x3c, 0x66, + 0x7d, 0x18, 0xf2, 0x33, 0x67, 0xbe, 0x90, 0xf6, 0x11, 0xb2, 0xfb, 0x45, 0xd6, 0x78, 0x91, 0x66, + 0x27, 0x5a, 0x9a, 0xb8, 0x51, 0x1f, 0xf0, 0xe4, 0x27, 0x00, 0x00, 0xff, 0xff, 0x19, 0xa2, 0xb5, + 0x7c, 0xf7, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Parameters queries the parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/exocore.dogfood.v1.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Parameters queries the parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/exocore.dogfood.v1.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "exocore.dogfood.v1.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "exocore/dogfood/v1/query.proto", +} + +func (m *QueryParamsRequest) 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 *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + 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 *QueryParamsResponse) 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.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 skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dogfood/types/query.pb.gw.go b/x/dogfood/types/query.pb.gw.go new file mode 100644 index 000000000..f078ad093 --- /dev/null +++ b/x/dogfood/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: exocore/dogfood/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_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_Params_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_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"exocore", "dogfood", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/dogfood/types/tx.pb.go b/x/dogfood/types/tx.pb.go new file mode 100644 index 000000000..0f65f29c2 --- /dev/null +++ b/x/dogfood/types/tx.pb.go @@ -0,0 +1,81 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/dogfood/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +func init() { proto.RegisterFile("exocore/dogfood/v1/tx.proto", fileDescriptor_015649094fe3d8cd) } + +var fileDescriptor_015649094fe3d8cd = []byte{ + // 137 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xad, 0xc8, 0x4f, + 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, + 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0x4a, 0xea, 0x41, 0x25, 0xf5, 0xca, + 0x0c, 0x8d, 0x58, 0xb9, 0x98, 0x7d, 0x8b, 0xd3, 0x9d, 0xbc, 0x4f, 0x3c, 0x92, 0x63, 0xbc, 0xf0, + 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, 0xb8, + 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x30, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, 0x3f, 0x57, + 0xdf, 0x15, 0xa2, 0xdf, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x5b, 0x1f, 0x66, 0x57, 0x05, 0xdc, + 0xb6, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0xb0, 0x75, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xe3, 0x2e, 0x08, 0x39, 0x8d, 0x00, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "exocore.dogfood.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{}, + Metadata: "exocore/dogfood/v1/tx.proto", +} diff --git a/x/dogfood/types/types.go b/x/dogfood/types/types.go new file mode 100644 index 000000000..ab1254f4c --- /dev/null +++ b/x/dogfood/types/types.go @@ -0,0 +1 @@ +package types From 503728c81b6a75b3c46aa5a46ccfac9cb161ef01 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:28:55 +0000 Subject: [PATCH 02/32] fix(dogfood): remove mem store --- x/dogfood/keeper/keeper.go | 6 +----- x/dogfood/types/keys.go | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index b1b480e39..5abed0dd1 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -16,17 +16,14 @@ type ( Keeper struct { cdc codec.BinaryCodec storeKey storetypes.StoreKey - memKey storetypes.StoreKey paramstore paramtypes.Subspace } ) func NewKeeper( cdc codec.BinaryCodec, - storeKey, - memKey storetypes.StoreKey, + storeKey storetypes.StoreKey, ps paramtypes.Subspace, - ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -36,7 +33,6 @@ func NewKeeper( return &Keeper{ cdc: cdc, storeKey: storeKey, - memKey: memKey, paramstore: ps, } } diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 2a58dafee..1a9e60990 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -9,9 +9,6 @@ const ( // RouterKey defines the module's message routing key RouterKey = ModuleName - - // MemStoreKey defines the in-memory store key - MemStoreKey = "mem_dogfood" ) func KeyPrefix(p string) []byte { From 36a2961c28ee094d3572d71ba7816655f6f2fbcc Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:04:42 +0000 Subject: [PATCH 03/32] fix(dogfood): remove not required keepers --- x/dogfood/module.go | 8 +------- x/dogfood/types/expected_keepers.go | 17 ----------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/x/dogfood/module.go b/x/dogfood/module.go index 90d11aad2..e8ea80431 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -106,22 +106,16 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { type AppModule struct { AppModuleBasic - keeper keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + keeper keeper.Keeper } func NewAppModule( cdc codec.Codec, keeper keeper.Keeper, - accountKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), keeper: keeper, - accountKeeper: accountKeeper, - bankKeeper: bankKeeper, } } diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index 6aa6e9778..ab1254f4c 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -1,18 +1 @@ package types - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/auth/types" -) - -// AccountKeeper defines the expected account keeper used for simulations (noalias) -type AccountKeeper interface { - GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI - // Methods imported from account should be defined here -} - -// BankKeeper defines the expected interface needed to retrieve account balances. -type BankKeeper interface { - SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins - // Methods imported from bank should be defined here -} From 47861d7a817b1aa03df27d8ac79d448bd6da1e38 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:08:08 +0000 Subject: [PATCH 04/32] refactor(dogfood): remove not required items --- x/dogfood/client/cli/query.go | 28 ++++++++++++++++++++++ x/dogfood/client/cli/query_params.go | 36 ---------------------------- x/dogfood/client/cli/tx.go | 12 ---------- x/dogfood/types/keys.go | 7 ------ 4 files changed, 28 insertions(+), 55 deletions(-) delete mode 100644 x/dogfood/client/cli/query_params.go diff --git a/x/dogfood/client/cli/query.go b/x/dogfood/client/cli/query.go index 41b496df3..a4dfc065d 100644 --- a/x/dogfood/client/cli/query.go +++ b/x/dogfood/client/cli/query.go @@ -7,6 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" // "github.com/cosmos/cosmos-sdk/client/flags" // sdk "github.com/cosmos/cosmos-sdk/types" @@ -31,3 +32,30 @@ func GetQueryCmd(queryRoute string) *cobra.Command { return cmd } + +func CmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "shows the parameters of the module", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + + res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/dogfood/client/cli/query_params.go b/x/dogfood/client/cli/query_params.go deleted file mode 100644 index f5f252819..000000000 --- a/x/dogfood/client/cli/query_params.go +++ /dev/null @@ -1,36 +0,0 @@ -package cli - -import ( - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/spf13/cobra" - - "github.com/ExocoreNetwork/exocore/x/dogfood/types" -) - -func CmdQueryParams() *cobra.Command { - cmd := &cobra.Command{ - Use: "params", - Short: "shows the parameters of the module", - Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientQueryContext(cmd) - if err != nil { - return err - } - - queryClient := types.NewQueryClient(clientCtx) - - res, err := queryClient.Params(cmd.Context(), &types.QueryParamsRequest{}) - if err != nil { - return err - } - - return clientCtx.PrintProto(res) - }, - } - - flags.AddQueryFlagsToCmd(cmd) - - return cmd -} diff --git a/x/dogfood/client/cli/tx.go b/x/dogfood/client/cli/tx.go index ed092de4d..06c36befa 100644 --- a/x/dogfood/client/cli/tx.go +++ b/x/dogfood/client/cli/tx.go @@ -2,7 +2,6 @@ package cli import ( "fmt" - "time" "github.com/spf13/cobra" @@ -11,17 +10,6 @@ import ( "github.com/ExocoreNetwork/exocore/x/dogfood/types" ) -var ( - DefaultRelativePacketTimeoutTimestamp = uint64( - (time.Duration(10) * time.Minute).Nanoseconds(), - ) -) - -const ( - flagPacketTimeoutTimestamp = "packet-timeout-timestamp" - listSeparator = "," -) - // GetTxCmd returns the transaction commands for this module func GetTxCmd() *cobra.Command { cmd := &cobra.Command{ diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 1a9e60990..1256e87e4 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -6,11 +6,4 @@ const ( // StoreKey defines the primary module store key StoreKey = ModuleName - - // RouterKey defines the module's message routing key - RouterKey = ModuleName ) - -func KeyPrefix(p string) []byte { - return []byte(p) -} From 15e8e8af96496b6621703bd49a2cdadd7c000dc8 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:10:45 +0000 Subject: [PATCH 05/32] refactor(dogfood): remove errors --- x/dogfood/types/errors.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/x/dogfood/types/errors.go b/x/dogfood/types/errors.go index f279c2d27..5c3965cb5 100644 --- a/x/dogfood/types/errors.go +++ b/x/dogfood/types/errors.go @@ -1,12 +1,3 @@ package types // DONTCOVER - -import ( - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" -) - -// x/dogfood module sentinel errors -var ( - ErrSample = sdkerrors.Register(ModuleName, 1100, "sample error") -) From 92be5654213c26e3530d84733127052ad8883816 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:14:59 +0000 Subject: [PATCH 06/32] refactor(dogfood): merge `query_params.go` --- x/dogfood/keeper/query.go | 18 ++++++++++++++++++ x/dogfood/keeper/query_params.go | 19 ------------------- 2 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 x/dogfood/keeper/query_params.go diff --git a/x/dogfood/keeper/query.go b/x/dogfood/keeper/query.go index dfee6251a..34ed99320 100644 --- a/x/dogfood/keeper/query.go +++ b/x/dogfood/keeper/query.go @@ -1,7 +1,25 @@ package keeper import ( + "context" + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + sdk "github.com/cosmos/cosmos-sdk/types" ) var _ types.QueryServer = Keeper{} + +func (k Keeper) Params( + goCtx context.Context, + req *types.QueryParamsRequest, +) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil +} diff --git a/x/dogfood/keeper/query_params.go b/x/dogfood/keeper/query_params.go deleted file mode 100644 index 2f0e76b04..000000000 --- a/x/dogfood/keeper/query_params.go +++ /dev/null @@ -1,19 +0,0 @@ -package keeper - -import ( - "context" - - "github.com/ExocoreNetwork/exocore/x/dogfood/types" - sdk "github.com/cosmos/cosmos-sdk/types" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" -) - -func (k Keeper) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { - if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") - } - ctx := sdk.UnwrapSDKContext(goCtx) - - return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil -} From 6d44166b0f5719377ac3e664f9499ddaf5884cd9 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 16:17:27 +0000 Subject: [PATCH 07/32] feat(dogfood): add parameters The dogfooding module, as previously described, is used as the staking module for the Exocore chain. It allows operators and delegators to deposit and delegate their assets on a client chain for staking. The staked assets are then used to secure the Exocore chain. The parameters used by this module are the following: - EpochsUntilUnbonded, which represents the number of epochs after which an unbonding is effective. - EpochIdentifier, which is the identifier of the epoch duration. It should be valid according to the epoch keeper of `app.go`, and is thus constrained to the options week/day/hour. - MaxValidators, which is the maximum number of validators that will be forwarded to ABCI. - HistoricalEntries, which is the number of historical entries to persist in state. These are used by IBC. --- proto/exocore/dogfood/v1/params.proto | 12 +- x/dogfood/genesis.go | 2 +- x/dogfood/keeper/params.go | 48 ++++++- x/dogfood/keeper/query.go | 2 +- x/dogfood/types/params.go | 109 +++++++++++++-- x/dogfood/types/params.pb.go | 194 ++++++++++++++++++++++++-- 6 files changed, 339 insertions(+), 28 deletions(-) diff --git a/proto/exocore/dogfood/v1/params.proto b/proto/exocore/dogfood/v1/params.proto index 3305239a6..4d3f94a8d 100644 --- a/proto/exocore/dogfood/v1/params.proto +++ b/proto/exocore/dogfood/v1/params.proto @@ -9,5 +9,15 @@ option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; // Params defines the parameters for the module. message Params { option (gogoproto.goproto_stringer) = false; - + // EpochsUntilUnbonded is the number of epochs after which an unbonding + // is released. Note that it starts from the beginning of the next epoch + // in which the unbonding request was received. At that point, the vote + // power is reduced by the amount of the unbonding operation. + uint32 epochs_until_unbonded = 1; + // EpochIdentifier is the identifier of the epoch (week, hour, day). + string epoch_identifier = 2; + // MaxValidators is the maximum number of validators. + uint32 max_validators = 3; + // HistoricalEntries is the number of historical entries to persist. + uint32 historical_entries = 4; } diff --git a/x/dogfood/genesis.go b/x/dogfood/genesis.go index 0c4077eb6..15eef3d3e 100644 --- a/x/dogfood/genesis.go +++ b/x/dogfood/genesis.go @@ -14,7 +14,7 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) // ExportGenesis returns the module's exported genesis func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { genesis := types.DefaultGenesis() - genesis.Params = k.GetParams(ctx) + genesis.Params = k.GetDogfoodParams(ctx) return genesis } diff --git a/x/dogfood/keeper/params.go b/x/dogfood/keeper/params.go index 95553df50..f2bb7af60 100644 --- a/x/dogfood/keeper/params.go +++ b/x/dogfood/keeper/params.go @@ -5,12 +5,52 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// GetParams get all parameters as types.Params -func (k Keeper) GetParams(ctx sdk.Context) types.Params { - return types.NewParams() +// GetEpochsUntilUnbonded returns the number of epochs after which an unbonding that is made +// during the current epoch will be released. It is a parameter of the dogfood module. +func (k Keeper) GetEpochsUntilUnbonded(ctx sdk.Context) uint32 { + var epochsUntilUnbonded uint32 + k.paramstore.Get(ctx, types.KeyEpochsUntilUnbonded, &epochsUntilUnbonded) + return epochsUntilUnbonded } -// SetParams set the params +// GetEpochIdentifier returns the epoch identifier used to measure an epoch. It is a parameter +// of the dogfood module. +func (k Keeper) GetEpochIdentifier(ctx sdk.Context) string { + var epochIdentifier string + k.paramstore.Get(ctx, types.KeyEpochIdentifier, &epochIdentifier) + return epochIdentifier +} + +// GetMaxValidators returns the maximum number of validators that can be asked to validate for +// the chain. It is a parameter of the dogfood module. +func (k Keeper) GetMaxValidators(ctx sdk.Context) uint32 { + var maxValidators uint32 + k.paramstore.Get(ctx, types.KeyMaxValidators, &maxValidators) + return maxValidators +} + +// GetHistorialEntries is the number of historical info entries to persist in the store. These +// entries are used by the IBC module. The return value is a parameter of the dogfood module. +func (k Keeper) GetHistoricalEntries(ctx sdk.Context) uint32 { + var historicalEntries uint32 + k.paramstore.Get(ctx, types.KeyHistoricalEntries, &historicalEntries) + return historicalEntries +} + +// SetParams sets the params for the dogfood module. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramstore.SetParamSet(ctx, ¶ms) } + +// GetDogfoodParams returns the parameters for the dogfood module. Note that this function is +// intentionally called GetDogfoodParams and not GetParams, since the GetParams function is used +// to implement the slashingtypes.StakingKeeper interface `GetParams(sdk.Context) +// stakingtypes.Params`. +func (k Keeper) GetDogfoodParams(ctx sdk.Context) (params types.Params) { + return types.NewParams( + k.GetEpochsUntilUnbonded(ctx), + k.GetEpochIdentifier(ctx), + k.GetMaxValidators(ctx), + k.GetHistoricalEntries(ctx), + ) +} diff --git a/x/dogfood/keeper/query.go b/x/dogfood/keeper/query.go index 34ed99320..60c010b19 100644 --- a/x/dogfood/keeper/query.go +++ b/x/dogfood/keeper/query.go @@ -21,5 +21,5 @@ func (k Keeper) Params( } ctx := sdk.UnwrapSDKContext(goCtx) - return &types.QueryParamsResponse{Params: k.GetParams(ctx)}, nil + return &types.QueryParamsResponse{Params: k.GetDogfoodParams(ctx)}, nil } diff --git a/x/dogfood/types/params.go b/x/dogfood/types/params.go index 357196ad6..97fb4f583 100644 --- a/x/dogfood/types/params.go +++ b/x/dogfood/types/params.go @@ -1,38 +1,127 @@ package types import ( + "fmt" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "gopkg.in/yaml.v2" + + epochTypes "github.com/evmos/evmos/v14/x/epochs/types" ) var _ paramtypes.ParamSet = (*Params)(nil) -// ParamKeyTable the param key table for launch module +const ( + // DefaultEpochsUntilUnbonded is the default number of epochs after which an unbonding entry + // is released. For example, if an unbonding is requested during epoch 8, it is made + // effective at the beginning of epoch 9. The unbonding amount is released at the beginning + // of epoch 16 (9 + DefaultEpochsUntilUnbonded). + DefaultEpochsUntilUnbonded = 7 + // DefaultEpochIdentifier is the epoch identifier which is used, by default, to identify the + // epoch. Note that the options include week, day or hour. + DefaultEpochIdentifier = epochTypes.HourEpochID + // DefaultMaxValidators is the default maximum number of bonded validators. + DefaultMaxValidators = stakingtypes.DefaultMaxValidators + // DefaultHistorical entries is the number of entries of historical staking data to persist. + // Apps that don't use IBC can ignore this value by not adding the staking module to the + // application module manager's SetOrderBeginBlockers. + DefaultHistoricalEntries = stakingtypes.DefaultHistoricalEntries +) + +// Reflection based keys for params subspace. +var ( + KeyEpochsUntilUnbonded = []byte("EpochsUntilUnbonded") + KeyEpochIdentifier = []byte("EpochIdentifier") + KeyMaxValidators = []byte("MaxValidators") + KeyHistoricalEntries = []byte("HistoricalEntries") +) + +// ParamKeyTable returns a key table with the necessary registered params. func ParamKeyTable() paramtypes.KeyTable { return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) } -// NewParams creates a new Params instance -func NewParams() Params { - return Params{} +// NewParams creates a new Params instance. +func NewParams( + epochsUntilUnbonded uint32, + epochIdentifier string, + maxValidators uint32, + historicalEntries uint32, +) Params { + return Params{ + EpochsUntilUnbonded: epochsUntilUnbonded, + EpochIdentifier: epochIdentifier, + MaxValidators: maxValidators, + HistoricalEntries: historicalEntries, + } } -// DefaultParams returns a default set of parameters +// DefaultParams returns a default set of parameters. func DefaultParams() Params { - return NewParams() + return NewParams( + DefaultEpochsUntilUnbonded, + DefaultEpochIdentifier, + DefaultMaxValidators, + DefaultHistoricalEntries, + ) } -// ParamSetPairs get the params.ParamSet +// ParamSetPairs implements params.ParamSet func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{} + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair( + KeyEpochsUntilUnbonded, + &p.EpochsUntilUnbonded, + ValidatePositiveUint32, + ), + paramtypes.NewParamSetPair( + KeyEpochIdentifier, + &p.EpochIdentifier, + epochTypes.ValidateEpochIdentifierInterface, + ), + paramtypes.NewParamSetPair( + KeyMaxValidators, + &p.MaxValidators, + ValidatePositiveUint32, + ), + paramtypes.NewParamSetPair( + KeyHistoricalEntries, + &p.HistoricalEntries, + ValidatePositiveUint32, + ), + } } -// Validate validates the set of params +// Validate validates the set of params. func (p Params) Validate() error { + if err := ValidatePositiveUint32(p.EpochsUntilUnbonded); err != nil { + return fmt.Errorf("epochs until unbonded: %w", err) + } + if err := epochTypes.ValidateEpochIdentifierInterface(p.EpochIdentifier); err != nil { + return fmt.Errorf("epoch identifier: %w", err) + } + if err := ValidatePositiveUint32(p.MaxValidators); err != nil { + return fmt.Errorf("max validators: %w", err) + } + if err := ValidatePositiveUint32(p.HistoricalEntries); err != nil { + return fmt.Errorf("historical entries: %w", err) + } + return nil +} + +// ValidatePositiveUint32 checks whether the supplied value is a positive uint32. +func ValidatePositiveUint32(i interface{}) error { + if val, ok := i.(uint32); !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } else if val == 0 { + return fmt.Errorf("invalid parameter value: %d", val) + } return nil } -// String implements the Stringer interface. +// String implements the Stringer interface. Ths interface is required as part of the +// proto.Message interface, which is used in the query server. func (p Params) String() string { out, _ := yaml.Marshal(p) return string(out) diff --git a/x/dogfood/types/params.pb.go b/x/dogfood/types/params.pb.go index 60a1da67d..1b35e818a 100644 --- a/x/dogfood/types/params.pb.go +++ b/x/dogfood/types/params.pb.go @@ -25,6 +25,17 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the module. type Params struct { + // EpochsUntilUnbonded is the number of epochs after which an unbonding + // is released. Note that it starts from the beginning of the next epoch + // in which the unbonding request was received. At that point, the vote + // power is reduced by the amount of the unbonding operation. + EpochsUntilUnbonded uint32 `protobuf:"varint,1,opt,name=epochs_until_unbonded,json=epochsUntilUnbonded,proto3" json:"epochs_until_unbonded,omitempty"` + // EpochIdentifier is the identifier of the epoch (week, hour, day). + EpochIdentifier string `protobuf:"bytes,2,opt,name=epoch_identifier,json=epochIdentifier,proto3" json:"epoch_identifier,omitempty"` + // MaxValidators is the maximum number of validators. + MaxValidators uint32 `protobuf:"varint,3,opt,name=max_validators,json=maxValidators,proto3" json:"max_validators,omitempty"` + // HistoricalEntries is the number of historical entries to persist. + HistoricalEntries uint32 `protobuf:"varint,4,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -59,6 +70,34 @@ func (m *Params) XXX_DiscardUnknown() { var xxx_messageInfo_Params proto.InternalMessageInfo +func (m *Params) GetEpochsUntilUnbonded() uint32 { + if m != nil { + return m.EpochsUntilUnbonded + } + return 0 +} + +func (m *Params) GetEpochIdentifier() string { + if m != nil { + return m.EpochIdentifier + } + return "" +} + +func (m *Params) GetMaxValidators() uint32 { + if m != nil { + return m.MaxValidators + } + return 0 +} + +func (m *Params) GetHistoricalEntries() uint32 { + if m != nil { + return m.HistoricalEntries + } + return 0 +} + func init() { proto.RegisterType((*Params)(nil), "exocore.dogfood.v1.Params") } @@ -66,17 +105,26 @@ func init() { func init() { proto.RegisterFile("exocore/dogfood/v1/params.proto", fileDescriptor_e8747fb70c97d97f) } var fileDescriptor_e8747fb70c97d97f = []byte{ - // 160 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4f, 0xad, 0xc8, 0x4f, - 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, - 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0x2a, 0xd0, - 0x83, 0x2a, 0xd0, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, 0x58, - 0x10, 0x95, 0x4a, 0x7c, 0x5c, 0x6c, 0x01, 0x60, 0x9d, 0x56, 0x2c, 0x33, 0x16, 0xc8, 0x33, 0x38, - 0x79, 0x9f, 0x78, 0x24, 0xc7, 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, - 0xcb, 0x31, 0x5c, 0x78, 0x2c, 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x61, 0x7a, 0x66, 0x49, - 0x46, 0x69, 0x92, 0x5e, 0x72, 0x7e, 0xae, 0xbe, 0x2b, 0xc4, 0x78, 0xbf, 0xd4, 0x92, 0xf2, 0xfc, - 0xa2, 0x6c, 0x7d, 0x98, 0x73, 0x2a, 0xe0, 0x0e, 0x2a, 0xa9, 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, - 0xdb, 0x61, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x8e, 0x0e, 0x0c, 0x9a, 0xb0, 0x00, 0x00, 0x00, + // 290 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0x3f, 0x4b, 0xc3, 0x40, + 0x18, 0x87, 0x73, 0x5a, 0x0a, 0x1e, 0xd4, 0x3f, 0xa7, 0x42, 0x70, 0xb8, 0x16, 0x41, 0xa8, 0x83, + 0x39, 0xaa, 0x9b, 0xa3, 0xd0, 0x41, 0x04, 0x91, 0x42, 0x1d, 0x5c, 0xc2, 0x35, 0x77, 0x4d, 0x0f, + 0x9b, 0xbc, 0xe1, 0xee, 0x1a, 0xe3, 0xb7, 0x70, 0x74, 0xf4, 0xbb, 0xb8, 0x38, 0x76, 0x74, 0x94, + 0xe4, 0x8b, 0x48, 0x2f, 0x31, 0x6e, 0xc7, 0xef, 0x79, 0xee, 0x1d, 0x1e, 0xdc, 0x97, 0x05, 0x44, + 0xa0, 0x25, 0x13, 0x10, 0xcf, 0x01, 0x04, 0xcb, 0x47, 0x2c, 0xe3, 0x9a, 0x27, 0x26, 0xc8, 0x34, + 0x58, 0x20, 0xa4, 0x11, 0x82, 0x46, 0x08, 0xf2, 0xd1, 0xc9, 0x51, 0x0c, 0x31, 0x38, 0xcc, 0x36, + 0xaf, 0xda, 0x3c, 0xfd, 0x44, 0xb8, 0xfb, 0xe0, 0xbe, 0x92, 0x4b, 0x7c, 0x2c, 0x33, 0x88, 0x16, + 0x26, 0x5c, 0xa5, 0x56, 0x2d, 0xc3, 0x55, 0x3a, 0x83, 0x54, 0x48, 0xe1, 0xa3, 0x01, 0x1a, 0xf6, + 0x26, 0x87, 0x35, 0x9c, 0x6e, 0xd8, 0xb4, 0x41, 0xe4, 0x1c, 0xef, 0xbb, 0x39, 0x54, 0x42, 0xa6, + 0x56, 0xcd, 0x95, 0xd4, 0xfe, 0xd6, 0x00, 0x0d, 0x77, 0x26, 0x7b, 0x6e, 0xbf, 0x6d, 0x67, 0x72, + 0x86, 0x77, 0x13, 0x5e, 0x84, 0x39, 0x5f, 0x2a, 0xc1, 0x2d, 0x68, 0xe3, 0x6f, 0xbb, 0xbb, 0xbd, + 0x84, 0x17, 0x8f, 0xed, 0x48, 0x2e, 0x30, 0x59, 0x28, 0x63, 0x41, 0xab, 0x88, 0x2f, 0x43, 0x99, + 0x5a, 0xad, 0xa4, 0xf1, 0x3b, 0x4e, 0x3d, 0xf8, 0x27, 0xe3, 0x1a, 0x5c, 0x77, 0xde, 0x3f, 0xfa, + 0xde, 0xcd, 0xdd, 0x57, 0x49, 0xd1, 0xba, 0xa4, 0xe8, 0xa7, 0xa4, 0xe8, 0xad, 0xa2, 0xde, 0xba, + 0xa2, 0xde, 0x77, 0x45, 0xbd, 0xa7, 0x51, 0xac, 0xec, 0x62, 0x35, 0x0b, 0x22, 0x48, 0xd8, 0xb8, + 0x8e, 0x72, 0x2f, 0xed, 0x0b, 0xe8, 0x67, 0xf6, 0x17, 0xb1, 0x68, 0x33, 0xda, 0xd7, 0x4c, 0x9a, + 0x59, 0xd7, 0x95, 0xb9, 0xfa, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x52, 0x3e, 0xbb, 0xe0, 0x66, 0x01, + 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -99,6 +147,28 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.HistoricalEntries != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.HistoricalEntries)) + i-- + dAtA[i] = 0x20 + } + if m.MaxValidators != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.MaxValidators)) + i-- + dAtA[i] = 0x18 + } + if len(m.EpochIdentifier) > 0 { + i -= len(m.EpochIdentifier) + copy(dAtA[i:], m.EpochIdentifier) + i = encodeVarintParams(dAtA, i, uint64(len(m.EpochIdentifier))) + i-- + dAtA[i] = 0x12 + } + if m.EpochsUntilUnbonded != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.EpochsUntilUnbonded)) + i-- + dAtA[i] = 0x8 + } return len(dAtA) - i, nil } @@ -119,6 +189,19 @@ func (m *Params) Size() (n int) { } var l int _ = l + if m.EpochsUntilUnbonded != 0 { + n += 1 + sovParams(uint64(m.EpochsUntilUnbonded)) + } + l = len(m.EpochIdentifier) + if l > 0 { + n += 1 + l + sovParams(uint64(l)) + } + if m.MaxValidators != 0 { + n += 1 + sovParams(uint64(m.MaxValidators)) + } + if m.HistoricalEntries != 0 { + n += 1 + sovParams(uint64(m.HistoricalEntries)) + } return n } @@ -157,6 +240,95 @@ func (m *Params) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochsUntilUnbonded", wireType) + } + m.EpochsUntilUnbonded = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.EpochsUntilUnbonded |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EpochIdentifier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EpochIdentifier = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxValidators", wireType) + } + m.MaxValidators = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxValidators |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HistoricalEntries", wireType) + } + m.HistoricalEntries = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.HistoricalEntries |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:]) From cb08e29ba2fac1e19cea2377405a9da531525752 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 6 Feb 2024 17:45:24 +0000 Subject: [PATCH 08/32] feat(dogfood): load genesis state for bootstrap The bootstrapping smart contract is responsible for accepting user deposits, operator registration, and delegations. These operations may flow freely until 24 hours (say) before the spawn time of Exocore, at which the contract will be locked. During this time, the genesis state of Exocore will be amended to record the initial deposits, delegations, operator registrations and public keys. The last of these will feed into the dogfooding module which will mark these operators as part of the initial validator set and allow block production. This PR includes the capability to load that state, and save the newly created operator information to disk. In addition, the staking hooks have been set up (partially) in this PR, which allow the SDK's slashing keeper to record validator signing rates for downtime slashing. --- proto/buf.lock | 10 +- proto/buf.yaml | 2 +- proto/exocore/dogfood/v1/dogfood.proto | 24 ++ proto/exocore/dogfood/v1/genesis.proto | 8 + x/dogfood/genesis.go | 8 +- x/dogfood/keeper/hooks.go | 34 ++ x/dogfood/keeper/keeper.go | 32 +- x/dogfood/keeper/validators.go | 261 +++++++++++++++ x/dogfood/module.go | 4 +- x/dogfood/types/dogfood.pb.go | 429 +++++++++++++++++++++++++ x/dogfood/types/expected_keepers.go | 19 ++ x/dogfood/types/genesis.pb.go | 98 +++++- x/dogfood/types/keys.go | 23 ++ x/dogfood/types/validator.go | 45 +++ 14 files changed, 972 insertions(+), 25 deletions(-) create mode 100644 proto/exocore/dogfood/v1/dogfood.proto create mode 100644 x/dogfood/keeper/hooks.go create mode 100644 x/dogfood/keeper/validators.go create mode 100644 x/dogfood/types/dogfood.pb.go create mode 100644 x/dogfood/types/validator.go diff --git a/proto/buf.lock b/proto/buf.lock index face468fb..d025fc2f3 100644 --- a/proto/buf.lock +++ b/proto/buf.lock @@ -5,15 +5,19 @@ deps: owner: cosmos repository: cosmos-proto commit: 1935555c206d4afb9e94615dfd0fad31 + digest: shake256:c74d91a3ac7ae07d579e90eee33abf9b29664047ac8816500cf22c081fec0d72d62c89ce0bebafc1f6fec7aa5315be72606717740ca95007248425102c365377 - remote: buf.build owner: cosmos repository: cosmos-sdk - commit: 508e19f5f37549e3a471a2a59b903c00 + commit: 954f7b05f38440fc8250134b15adec47 + digest: shake256:2ab4404fd04a7d1d52df0e2d0f2d477a3d83ffd88d876957bf3fedfd702c8e52833d65b3ce1d89a3c5adf2aab512616b0e4f51d8463f07eda9a8a3317ee3ac54 - remote: buf.build owner: cosmos repository: gogo-proto - commit: 34d970b699f84aa382f3c29773a60836 + commit: 88ef6483f90f478fb938c37dde52ece3 + digest: shake256:89c45df2aa11e0cff97b0d695436713db3d993d76792e9f8dc1ae90e6ab9a9bec55503d48ceedd6b86069ab07d3041b32001b2bfe0227fa725dd515ff381e5ba - remote: buf.build owner: googleapis repository: googleapis - commit: 783e4b5374fa488ab068d08af9658438 + commit: e874a0be2bf140a5a4c7d4122c635823 + digest: shake256:4fe3036b4d706f6ee2b13c730bd04777f021dfd02ed27e6e40480acfe664a7548238312ee0727fd77648a38d227e296d43f4a38a34cdd46068156211016d9657 diff --git a/proto/buf.yaml b/proto/buf.yaml index d7876a9fc..00eff3659 100644 --- a/proto/buf.yaml +++ b/proto/buf.yaml @@ -1,7 +1,7 @@ version: v1 name: buf.build/evmos/evmos deps: - - buf.build/cosmos/cosmos-sdk + - buf.build/cosmos/cosmos-sdk:v0.47.0 - buf.build/cosmos/cosmos-proto - buf.build/cosmos/gogo-proto - buf.build/googleapis/googleapis diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto new file mode 100644 index 000000000..e51f4a408 --- /dev/null +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package exocore.dogfood.v1; + +import "gogoproto/gogo.proto"; +import "google/protobuf/any.proto"; +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; + +// ExocoreValidator is a validator that is part of the Exocore network. It is +// used to validate and sign blocks and transactions. +message ExocoreValidator { + // The address, as derived from the consensus key. It has no relation + // with the operator's account address. + bytes address = 1; + // Last known power + int64 power = 2; + // pubkey is the consensus public key of the validator, as a Protobuf Any. + google.protobuf.Any pubkey = 3 [ + (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", + (gogoproto.moretags) = "yaml:\"consensus_pubkey\"" + ]; +} \ No newline at end of file diff --git a/proto/exocore/dogfood/v1/genesis.proto b/proto/exocore/dogfood/v1/genesis.proto index 4cb6bca2f..02b53d840 100644 --- a/proto/exocore/dogfood/v1/genesis.proto +++ b/proto/exocore/dogfood/v1/genesis.proto @@ -3,11 +3,19 @@ syntax = "proto3"; package exocore.dogfood.v1; import "gogoproto/gogo.proto"; + +import "tendermint/abci/types.proto"; + import "exocore/dogfood/v1/params.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; // GenesisState defines the dogfood module's genesis state. message GenesisState { + // Parameters of the module. Params params = 1 [(gogoproto.nullable) = false]; + + // Validator set, stored by ExocoreValidatorKey. + repeated .tendermint.abci.ValidatorUpdate val_set = 2 + [ (gogoproto.nullable) = false ]; } diff --git a/x/dogfood/genesis.go b/x/dogfood/genesis.go index 15eef3d3e..de40ed814 100644 --- a/x/dogfood/genesis.go +++ b/x/dogfood/genesis.go @@ -3,12 +3,18 @@ package dogfood import ( "github.com/ExocoreNetwork/exocore/x/dogfood/keeper" "github.com/ExocoreNetwork/exocore/x/dogfood/types" + abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // InitGenesis initializes the module's state from a provided genesis state. -func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { +func InitGenesis( + ctx sdk.Context, + k keeper.Keeper, + genState types.GenesisState, +) []abci.ValidatorUpdate { k.SetParams(ctx, genState.Params) + return k.ApplyValidatorChanges(ctx, genState.ValSet) } // ExportGenesis returns the module's exported genesis diff --git a/x/dogfood/keeper/hooks.go b/x/dogfood/keeper/hooks.go new file mode 100644 index 000000000..cfbd66959 --- /dev/null +++ b/x/dogfood/keeper/hooks.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// interface guard +var _ types.DogfoodHooks = &MultiDogfoodHooks{} + +// MultiDogfoodHooks is a collection of DogfoodHooks. It calls the hook for each element in the +// collection one-by-one. The hook is called in the order in which the collection is created. +type MultiDogfoodHooks []types.DogfoodHooks + +// NewMultiDogfoodHooks is used to create a collective object of dogfood hooks from a list of +// the hooks. It follows the "accept interface, return concrete types" philosophy. Other modules +// may set the hooks by calling k := (*k).SetHooks(NewMultiDogfoodHooks(hookI)) +func NewMultiDogfoodHooks(hooks ...types.DogfoodHooks) MultiDogfoodHooks { + return hooks +} + +// AfterValidatorBonded is the implementation of types.DogfoodHooks for MultiDogfoodHooks. +func (hooks MultiDogfoodHooks) AfterValidatorBonded( + ctx sdk.Context, + consAddr sdk.ConsAddress, + operator sdk.ValAddress, +) error { + for _, hook := range hooks { + if err := hook.AfterValidatorBonded(ctx, consAddr, operator); err != nil { + return err + } + } + return nil +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index 5abed0dd1..b90ec9095 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -17,13 +17,19 @@ type ( cdc codec.BinaryCodec storeKey storetypes.StoreKey paramstore paramtypes.Subspace + + dogfoodHooks types.DogfoodHooks + + epochsKeeper types.EpochsKeeper } ) +// NewKeeper creates a new dogfood keeper. func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, ps paramtypes.Subspace, + epochsKeeper types.EpochsKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -31,12 +37,32 @@ func NewKeeper( } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, + cdc: cdc, + storeKey: storeKey, + paramstore: ps, + epochsKeeper: epochsKeeper, } } +// Logger returns a logger object for use within the module. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } + +// SetHooks sets the hooks on the keeper. It intentionally has a pointer receiver so that +// changes can be saved to the object. +func (k *Keeper) SetHooks(sh types.DogfoodHooks) *Keeper { + if k.dogfoodHooks != nil { + panic("cannot set dogfood hooks twice") + } + if sh == nil { + panic("cannot set nil dogfood hooks") + } + k.dogfoodHooks = sh + return k +} + +// Hooks returns the hooks registered to the module. +func (k Keeper) Hooks() types.DogfoodHooks { + return k.dogfoodHooks +} diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go new file mode 100644 index 000000000..d1b5e3e37 --- /dev/null +++ b/x/dogfood/keeper/validators.go @@ -0,0 +1,261 @@ +// This file is a duplicate of the subscriber module's validators file with minor changes. +// The function ApplyValidatorChanges can likely be carved out into a shared package. + +package keeper + +import ( + "time" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + abci "github.com/cometbft/cometbft/abci/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// UnbondingTime returns the time duration of the unbonding period. It is part of the +// implementation of the staking keeper expected by IBC. +// It is calculated as the number of epochs until unbonded multiplied by the duration of an +// epoch. This function is used by IBC's client keeper to validate the self client, and +// nowhere else. As long as it reports a consistent value, it's fine. +func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration { + count := k.GetEpochsUntilUnbonded(ctx) + identifier := k.GetEpochIdentifier(ctx) + epoch, found := k.epochsKeeper.GetEpochInfo(ctx, identifier) + if !found { + panic("epoch info not found") + } + durationPerEpoch := epoch.Duration + return time.Duration(count) * durationPerEpoch +} + +// ApplyValidatorChanges returns the validator set as is. However, it also +// stores the validators that are added or those that are removed, and updates +// the power for the existing validators. It also allows any hooks registered +// on the keeper to be executed. +func (k Keeper) ApplyValidatorChanges( + ctx sdk.Context, + changes []abci.ValidatorUpdate, +) []abci.ValidatorUpdate { + ret := []abci.ValidatorUpdate{} + for _, change := range changes { + // convert TM pubkey to SDK pubkey + pubkey, err := cryptocodec.FromTmProtoPublicKey(change.GetPubKey()) + if err != nil { + // An error here would indicate that the validator updates + // received from other modules are invalid. + panic(err) + } + addr := pubkey.Address() + val, found := k.GetValidator(ctx, addr) + + if found { + // update or delete an existing validator + if change.Power < 1 { + k.DeleteValidator(ctx, addr) + } else { + val.Power = change.Power + k.SetValidator(ctx, val) + } + } else if change.Power > 0 { + // create a new validator - the address is just derived from the public key and has + // no correlation with the operator address on Exocore + ocVal, err := types.NewExocoreValidator(addr, change.Power, pubkey) + if err != nil { + // An error here would indicate that the validator updates + // received are invalid. + panic(err) + } + + k.SetValidator(ctx, ocVal) + err = k.Hooks().AfterValidatorBonded(ctx, sdk.ConsAddress(addr), nil) + if err != nil { + // AfterValidatorBonded is hooked by the Slashing module and should not return + // an error. If any other module were to hook it, they should also not. + panic(err) + } + } else { + // edge case: we received an update for 0 power + // but the validator is already deleted. Do not forward + // to tendermint. + continue + } + + ret = append(ret, change) + } + return ret +} + +// SetValidator stores a validator based on the pub key derived address. This +// is accessible in the genesis state via `val_set`. +func (k Keeper) SetValidator(ctx sdk.Context, validator types.ExocoreValidator) { + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(&validator) + + store.Set(types.ExocoreValidatorKey(validator.Address), bz) +} + +// GetValidator gets a validator based on the pub key derived address. +func (k Keeper) GetValidator( + ctx sdk.Context, addr []byte, +) (validator types.ExocoreValidator, found bool) { + store := ctx.KVStore(k.storeKey) + v := store.Get(types.ExocoreValidatorKey(addr)) + if v == nil { + return + } + k.cdc.MustUnmarshal(v, &validator) + found = true + + return +} + +// DeleteValidator deletes a validator based on the pub key derived address. +func (k Keeper) DeleteValidator(ctx sdk.Context, addr []byte) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ExocoreValidatorKey(addr)) +} + +// GetAllExocoreValidators returns all validators in the store. +func (k Keeper) GetAllExocoreValidators( + ctx sdk.Context, +) (validators []types.ExocoreValidator) { + store := ctx.KVStore(k.storeKey) + iterator := sdk.KVStorePrefixIterator(store, []byte{types.ExocoreValidatorBytePrefix}) + + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + val := types.ExocoreValidator{} + k.cdc.MustUnmarshal(iterator.Value(), &val) + validators = append(validators, val) + } + + return validators +} + +// GetHistoricalInfo gets the historical info at a given height. It is part of the +// implementation of the staking keeper expected by IBC. +func (k Keeper) GetHistoricalInfo( + ctx sdk.Context, height int64, +) (stakingtypes.HistoricalInfo, bool) { + store := ctx.KVStore(k.storeKey) + key := types.HistoricalInfoKey(height) + + value := store.Get(key) + if value == nil { + return stakingtypes.HistoricalInfo{}, false + } + + return stakingtypes.MustUnmarshalHistoricalInfo(k.cdc, value), true +} + +// SetHistoricalInfo sets the historical info at a given height. This is +// (intentionally) not exported in the genesis state. +func (k Keeper) SetHistoricalInfo( + ctx sdk.Context, height int64, hi *stakingtypes.HistoricalInfo, +) { + store := ctx.KVStore(k.storeKey) + key := types.HistoricalInfoKey(height) + value := k.cdc.MustMarshal(hi) + + store.Set(key, value) +} + +// DeleteHistoricalInfo deletes the historical info at a given height. +func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { + store := ctx.KVStore(k.storeKey) + key := types.HistoricalInfoKey(height) + + store.Delete(key) +} + +// TrackHistoricalInfo saves the latest historical-info and deletes the oldest +// heights that are below pruning height. +func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { + numHistoricalEntries := k.GetHistoricalEntries(ctx) + + // Prune store to ensure we only have parameter-defined historical entries. + // In most cases, this will involve removing a single historical entry. + // In the rare scenario when the historical entries gets reduced to a lower value k' + // from the original value k. k - k' entries must be deleted from the store. + // Since the entries to be deleted are always in a continuous range, we can iterate + // over the historical entries starting from the most recent version to be pruned + // and then return at the first empty entry. + for i := ctx.BlockHeight() - int64(numHistoricalEntries); i >= 0; i-- { + _, found := k.GetHistoricalInfo(ctx, i) + if found { + k.DeleteHistoricalInfo(ctx, i) + } else { + break + } + } + + // if there is no need to persist historicalInfo, return. + if numHistoricalEntries == 0 { + return + } + + // Create HistoricalInfo struct + lastVals := []stakingtypes.Validator{} + for _, v := range k.GetAllExocoreValidators(ctx) { + pk, err := v.ConsPubKey() + if err != nil { + // This should never happen as the pubkey is assumed + // to be stored correctly earlier. + panic(err) + } + val, err := stakingtypes.NewValidator(nil, pk, stakingtypes.Description{}) + if err != nil { + // This should never happen as the pubkey is assumed + // to be stored correctly earlier. + panic(err) + } + + // Set validator to bonded status. + val.Status = stakingtypes.Bonded + // Compute tokens from voting power. + val.Tokens = sdk.TokensFromConsensusPower( + v.Power, + // TODO(mm) + // note that this is not super relevant for the historical info + // since IBC does not seem to use the tokens field. + sdk.NewInt(1), + ) + lastVals = append(lastVals, val) + } + + // Create historical info entry which sorts the validator set by voting power. + historicalEntry := stakingtypes.NewHistoricalInfo( + ctx.BlockHeader(), lastVals, + // TODO(mm) + // this should match the power reduction number above + // and is also thus not relevant. + sdk.NewInt(1), + ) + + // Set latest HistoricalInfo at current height. + k.SetHistoricalInfo(ctx, ctx.BlockHeight(), &historicalEntry) +} + +// MustGetCurrentValidatorsAsABCIUpdates gets all validators converted +// to the ABCI validator update type. It panics in case of failure. +func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.ValidatorUpdate { + vals := k.GetAllExocoreValidators(ctx) + valUpdates := make([]abci.ValidatorUpdate, 0, len(vals)) + for _, v := range vals { + pk, err := v.ConsPubKey() + if err != nil { + // This should never happen as the pubkey is assumed + // to be stored correctly earlier. + panic(err) + } + tmPK, err := cryptocodec.ToTmProtoPublicKey(pk) + if err != nil { + // This should never happen as the pubkey is assumed + // to be stored correctly earlier. + panic(err) + } + valUpdates = append(valUpdates, abci.ValidatorUpdate{PubKey: tmPK, Power: v.Power}) + } + return valUpdates +} diff --git a/x/dogfood/module.go b/x/dogfood/module.go index e8ea80431..2ac7087e3 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -141,9 +141,7 @@ func (am AppModule) InitGenesis( // Initialize global index to index in genesis state cdc.MustUnmarshalJSON(gs, &genState) - InitGenesis(ctx, am.keeper, genState) - - return []abci.ValidatorUpdate{} + return InitGenesis(ctx, am.keeper, genState) } // ExportGenesis returns the module's exported genesis state as raw JSON bytes. diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go new file mode 100644 index 000000000..64cadbb85 --- /dev/null +++ b/x/dogfood/types/dogfood.pb.go @@ -0,0 +1,429 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: exocore/dogfood/v1/dogfood.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/cosmos/gogoproto/gogoproto" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// ExocoreValidator is a validator that is part of the Exocore network. It is +// used to validate and sign blocks and transactions. +type ExocoreValidator struct { + // The address, as derived from the consensus key. It has no relation + // with the operator's account address. + Address []byte `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + // Last known power + Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` + // pubkey is the consensus public key of the validator, as a Protobuf Any. + Pubkey *types.Any `protobuf:"bytes,3,opt,name=pubkey,proto3" json:"pubkey,omitempty" yaml:"consensus_pubkey"` +} + +func (m *ExocoreValidator) Reset() { *m = ExocoreValidator{} } +func (m *ExocoreValidator) String() string { return proto.CompactTextString(m) } +func (*ExocoreValidator) ProtoMessage() {} +func (*ExocoreValidator) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{0} +} +func (m *ExocoreValidator) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ExocoreValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ExocoreValidator.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 *ExocoreValidator) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExocoreValidator.Merge(m, src) +} +func (m *ExocoreValidator) XXX_Size() int { + return m.Size() +} +func (m *ExocoreValidator) XXX_DiscardUnknown() { + xxx_messageInfo_ExocoreValidator.DiscardUnknown(m) +} + +var xxx_messageInfo_ExocoreValidator proto.InternalMessageInfo + +func (m *ExocoreValidator) GetAddress() []byte { + if m != nil { + return m.Address + } + return nil +} + +func (m *ExocoreValidator) GetPower() int64 { + if m != nil { + return m.Power + } + return 0 +} + +func (m *ExocoreValidator) GetPubkey() *types.Any { + if m != nil { + return m.Pubkey + } + return nil +} + +func init() { + proto.RegisterType((*ExocoreValidator)(nil), "exocore.dogfood.v1.ExocoreValidator") +} + +func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } + +var fileDescriptor_071b9989c501c3f2 = []byte{ + // 302 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0x31, 0x4e, 0xf3, 0x30, + 0x14, 0xc7, 0xeb, 0xaf, 0xfa, 0x8a, 0x14, 0x18, 0x50, 0x14, 0x89, 0xd0, 0xc1, 0x44, 0x9d, 0xba, + 0x60, 0xab, 0x74, 0x63, 0xa3, 0x12, 0x53, 0x25, 0x84, 0x3a, 0x30, 0xb0, 0x54, 0x4e, 0xe2, 0x9a, + 0xaa, 0x49, 0x5e, 0x64, 0x3b, 0x6d, 0x7d, 0x0b, 0x2e, 0xc1, 0x0d, 0x38, 0x04, 0x62, 0xea, 0xc8, + 0x84, 0x50, 0x72, 0x03, 0x4e, 0x80, 0x88, 0x63, 0xb6, 0xf7, 0xf3, 0xff, 0x3d, 0xfb, 0xe7, 0xe7, + 0x45, 0x7c, 0x0f, 0x09, 0x48, 0x4e, 0x53, 0x10, 0x2b, 0x80, 0x94, 0x6e, 0x27, 0xae, 0x24, 0xa5, + 0x04, 0x0d, 0xbe, 0xdf, 0x75, 0x10, 0x77, 0xbc, 0x9d, 0x0c, 0x03, 0x01, 0x02, 0xda, 0x98, 0xfe, + 0x56, 0xb6, 0x73, 0x78, 0x2e, 0x00, 0x44, 0xc6, 0x69, 0x4b, 0x71, 0xb5, 0xa2, 0xac, 0x30, 0x2e, + 0x4a, 0x40, 0xe5, 0xa0, 0x96, 0x76, 0xc6, 0x82, 0x8d, 0x46, 0x2f, 0xc8, 0x3b, 0xbd, 0xb5, 0x4f, + 0x3c, 0xb0, 0x6c, 0x9d, 0x32, 0x0d, 0xd2, 0x0f, 0xbd, 0x23, 0x96, 0xa6, 0x92, 0x2b, 0x15, 0xa2, + 0x08, 0x8d, 0x4f, 0x16, 0x0e, 0xfd, 0xc0, 0xfb, 0x5f, 0xc2, 0x8e, 0xcb, 0xf0, 0x5f, 0x84, 0xc6, + 0xfd, 0x85, 0x05, 0x9f, 0x79, 0x83, 0xb2, 0x8a, 0x37, 0xdc, 0x84, 0xfd, 0x08, 0x8d, 0x8f, 0xaf, + 0x02, 0x62, 0x5d, 0x88, 0x73, 0x21, 0x37, 0x85, 0x99, 0x4d, 0xbf, 0x3f, 0x2f, 0xce, 0x0c, 0xcb, + 0xb3, 0xeb, 0x51, 0x02, 0x85, 0xe2, 0x85, 0xaa, 0xd4, 0xd2, 0xce, 0x8d, 0xde, 0x5f, 0x2f, 0x83, + 0xce, 0x2b, 0x91, 0xa6, 0xd4, 0x40, 0xee, 0xab, 0x78, 0xce, 0xcd, 0xa2, 0xbb, 0x78, 0x36, 0x7f, + 0xab, 0x31, 0x3a, 0xd4, 0x18, 0x7d, 0xd5, 0x18, 0x3d, 0x37, 0xb8, 0x77, 0x68, 0x70, 0xef, 0xa3, + 0xc1, 0xbd, 0xc7, 0x89, 0x58, 0xeb, 0xa7, 0x2a, 0x26, 0x09, 0xe4, 0xb4, 0xfb, 0xc9, 0x1d, 0xd7, + 0x3b, 0x90, 0x1b, 0xea, 0xb6, 0xbb, 0xff, 0xdb, 0xaf, 0x36, 0x25, 0x57, 0xf1, 0xa0, 0xf5, 0x9a, + 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x39, 0xda, 0x59, 0x49, 0x7f, 0x01, 0x00, 0x00, +} + +func (m *ExocoreValidator) 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 *ExocoreValidator) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ExocoreValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Pubkey != nil { + { + size, err := m.Pubkey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDogfood(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.Power != 0 { + i = encodeVarintDogfood(dAtA, i, uint64(m.Power)) + i-- + dAtA[i] = 0x10 + } + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintDogfood(dAtA []byte, offset int, v uint64) int { + offset -= sovDogfood(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *ExocoreValidator) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Address) + if l > 0 { + n += 1 + l + sovDogfood(uint64(l)) + } + if m.Power != 0 { + n += 1 + sovDogfood(uint64(m.Power)) + } + if m.Pubkey != nil { + l = m.Pubkey.Size() + n += 1 + l + sovDogfood(uint64(l)) + } + return n +} + +func sovDogfood(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozDogfood(x uint64) (n int) { + return sovDogfood(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ExocoreValidator) 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 ErrIntOverflowDogfood + } + 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: ExocoreValidator: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ExocoreValidator: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = append(m.Address[:0], dAtA[iNdEx:postIndex]...) + if m.Address == nil { + m.Address = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType) + } + m.Power = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Power |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Pubkey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Pubkey == nil { + m.Pubkey = &types.Any{} + } + if err := m.Pubkey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipDogfood(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDogfood + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDogfood + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowDogfood + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthDogfood + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupDogfood + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthDogfood + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthDogfood = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowDogfood = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupDogfood = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index ab1254f4c..b498ad09b 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -1 +1,20 @@ package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + epochsTypes "github.com/evmos/evmos/v14/x/epochs/types" +) + +// EpochsKeeper represents the expected keeper interface for the epochs module. +type EpochsKeeper interface { + GetEpochInfo(sdk.Context, string) (epochsTypes.EpochInfo, bool) +} + +// DogfoodHooks represent the event hooks for dogfood module. Ideally, these should +// match those of the staking module but for now it is only a subset of them. The side effects +// of calling the other hooks are not relevant to running the chain, so they can be skipped. +type DogfoodHooks interface { + AfterValidatorBonded( + sdk.Context, sdk.ConsAddress, sdk.ValAddress, + ) error +} diff --git a/x/dogfood/types/genesis.pb.go b/x/dogfood/types/genesis.pb.go index a70ecb578..b3744468b 100644 --- a/x/dogfood/types/genesis.pb.go +++ b/x/dogfood/types/genesis.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + types "github.com/cometbft/cometbft/abci/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" io "io" @@ -25,7 +26,10 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // GenesisState defines the dogfood module's genesis state. type GenesisState struct { + // Parameters of the module. Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + // Validator set, stored by ExocoreValidatorKey. + ValSet []types.ValidatorUpdate `protobuf:"bytes,2,rep,name=val_set,json=valSet,proto3" json:"val_set"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -68,6 +72,13 @@ func (m *GenesisState) GetParams() Params { return Params{} } +func (m *GenesisState) GetValSet() []types.ValidatorUpdate { + if m != nil { + return m.ValSet + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "exocore.dogfood.v1.GenesisState") } @@ -75,20 +86,25 @@ func init() { func init() { proto.RegisterFile("exocore/dogfood/v1/genesis.proto", fileDescriptor_1a9d908a27866b1b) } var fileDescriptor_1a9d908a27866b1b = []byte{ - // 202 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x48, 0xad, 0xc8, 0x4f, - 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x4f, - 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0xaa, - 0xd0, 0x83, 0xaa, 0xd0, 0x2b, 0x33, 0x94, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x4b, 0xeb, 0x83, - 0x58, 0x10, 0x95, 0x52, 0xf2, 0x58, 0xcc, 0x2a, 0x48, 0x2c, 0x4a, 0xcc, 0x85, 0x1a, 0xa5, 0xe4, - 0xc1, 0xc5, 0xe3, 0x0e, 0x31, 0x3b, 0xb8, 0x24, 0xb1, 0x24, 0x55, 0xc8, 0x82, 0x8b, 0x0d, 0x22, - 0x2f, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1, 0x6d, 0x24, 0xa5, 0x87, 0x69, 0x97, 0x5e, 0x00, 0x58, 0x85, - 0x13, 0xcb, 0x89, 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0xf5, 0x4e, 0xde, 0x27, 0x1e, 0xc9, 0x31, 0x5e, - 0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, - 0xdc, 0x78, 0x2c, 0xc7, 0x10, 0x65, 0x98, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, - 0xab, 0xef, 0x0a, 0x31, 0xcd, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x5b, 0x1f, 0xe6, 0xbc, 0x0a, - 0xb8, 0x03, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0xae, 0x33, 0x06, 0x04, 0x00, 0x00, - 0xff, 0xff, 0xda, 0xc5, 0xe8, 0xc9, 0x0c, 0x01, 0x00, 0x00, + // 273 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x8f, 0x31, 0x4b, 0xc3, 0x40, + 0x14, 0xc7, 0x73, 0x2a, 0x15, 0x52, 0xa7, 0xe0, 0x50, 0x22, 0x5c, 0x83, 0x53, 0xa7, 0x3b, 0x52, + 0x17, 0x37, 0xa1, 0x20, 0x0e, 0x82, 0x88, 0x45, 0x07, 0x17, 0xb9, 0x24, 0xcf, 0x78, 0x98, 0xe4, + 0x85, 0xcb, 0x33, 0xd6, 0x8f, 0xe0, 0xe6, 0xc7, 0xea, 0xd8, 0xd1, 0x49, 0x24, 0xf9, 0x22, 0xd2, + 0xe4, 0xaa, 0x83, 0xdd, 0x0e, 0xee, 0xc7, 0xfb, 0xff, 0x7e, 0x6e, 0x00, 0x0b, 0x8c, 0xd1, 0x80, + 0x4c, 0x30, 0x7d, 0x44, 0x4c, 0x64, 0x1d, 0xca, 0x14, 0x0a, 0xa8, 0x74, 0x25, 0x4a, 0x83, 0x84, + 0x9e, 0x67, 0x09, 0x61, 0x09, 0x51, 0x87, 0xfe, 0x61, 0x8a, 0x29, 0x76, 0xdf, 0x72, 0xfd, 0xea, + 0x49, 0xff, 0x88, 0xa0, 0x48, 0xc0, 0xe4, 0xba, 0x20, 0xa9, 0xa2, 0x58, 0x4b, 0x7a, 0x2b, 0xc1, + 0x9e, 0xf1, 0xc7, 0x5b, 0x86, 0x4a, 0x65, 0x54, 0x6e, 0x81, 0xe3, 0x77, 0xe6, 0x1e, 0x5c, 0xf4, + 0xcb, 0x73, 0x52, 0x04, 0xde, 0xa9, 0x3b, 0xe8, 0x81, 0x11, 0x0b, 0xd8, 0x64, 0x38, 0xf5, 0xc5, + 0x7f, 0x13, 0x71, 0xdd, 0x11, 0xb3, 0xbd, 0xe5, 0xd7, 0xd8, 0xb9, 0xb1, 0xbc, 0x77, 0xe6, 0xee, + 0xd7, 0x2a, 0x7b, 0xa8, 0x80, 0x46, 0x3b, 0xc1, 0xee, 0x64, 0x38, 0x0d, 0xc4, 0x9f, 0x9a, 0x58, + 0xab, 0x89, 0x3b, 0x95, 0xe9, 0x44, 0x11, 0x9a, 0xdb, 0x32, 0x51, 0x04, 0x9b, 0x03, 0xb5, 0xca, + 0xe6, 0x40, 0xb3, 0xcb, 0x65, 0xc3, 0xd9, 0xaa, 0xe1, 0xec, 0xbb, 0xe1, 0xec, 0xa3, 0xe5, 0xce, + 0xaa, 0xe5, 0xce, 0x67, 0xcb, 0x9d, 0xfb, 0x30, 0xd5, 0xf4, 0xf4, 0x12, 0x89, 0x18, 0x73, 0x79, + 0xde, 0xeb, 0x5c, 0x01, 0xbd, 0xa2, 0x79, 0x96, 0x9b, 0xc0, 0xc5, 0x6f, 0x62, 0xd7, 0x1f, 0x0d, + 0xba, 0xbe, 0x93, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x26, 0x56, 0x05, 0x51, 0x6b, 0x01, 0x00, + 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -111,6 +127,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ValSet) > 0 { + for iNdEx := len(m.ValSet) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ValSet[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } { size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -143,6 +173,12 @@ func (m *GenesisState) Size() (n int) { _ = l l = m.Params.Size() n += 1 + l + sovGenesis(uint64(l)) + if len(m.ValSet) > 0 { + for _, e := range m.ValSet { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -214,6 +250,40 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValSet", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValSet = append(m.ValSet, types.ValidatorUpdate{}) + if err := m.ValSet[len(m.ValSet)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 1256e87e4..f7efde563 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -1,5 +1,9 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + const ( // ModuleName defines the module name ModuleName = "dogfood" @@ -7,3 +11,22 @@ const ( // StoreKey defines the primary module store key StoreKey = ModuleName ) + +const ( + // ExocoreValidatorBytePrefix is the prefix for the validator store. + ExocoreValidatorBytePrefix byte = iota + 1 + + // HistoricalInfoBytePrefix is the prefix for the historical info store. + HistoricalInfoBytePrefix +) + +// ExocoreValidatorKey returns the key for the validator store. +func ExocoreValidatorKey(address sdk.AccAddress) []byte { + return append([]byte{ExocoreValidatorBytePrefix}, address.Bytes()...) +} + +// HistoricalInfoKey returns the key for the historical info store. +func HistoricalInfoKey(height int64) []byte { + bz := sdk.Uint64ToBigEndian(uint64(height)) + return append([]byte{HistoricalInfoBytePrefix}, bz...) +} diff --git a/x/dogfood/types/validator.go b/x/dogfood/types/validator.go new file mode 100644 index 000000000..dafb75065 --- /dev/null +++ b/x/dogfood/types/validator.go @@ -0,0 +1,45 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// NewExocoreValidator creates an ExocoreValidator with the specified (consensus) address, vote +// power and consensus public key. If the public key is malformed, it returns an error. +func NewExocoreValidator( + address []byte, power int64, pubKey cryptotypes.PubKey, +) (ExocoreValidator, error) { + pkAny, err := codectypes.NewAnyWithValue(pubKey) + if err != nil { + return ExocoreValidator{}, errorsmod.Wrap(err, "failed to pack public key") + } + return ExocoreValidator{ + Address: address, + Power: power, + Pubkey: pkAny, + }, nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces. +// It is required to ensure that ConsPubKey below works. +func (ecv ExocoreValidator) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + var pk cryptotypes.PubKey + return unpacker.UnpackAny(ecv.Pubkey, &pk) +} + +// ConsPubKey returns the validator PubKey as a cryptotypes.PubKey. +func (ecv ExocoreValidator) ConsPubKey() (cryptotypes.PubKey, error) { + pk, ok := ecv.Pubkey.GetCachedValue().(cryptotypes.PubKey) + if !ok { + return nil, errorsmod.Wrapf( + sdkerrors.ErrInvalidType, + "expecting cryptotypes.PubKey, got %T", + pk, + ) + } + + return pk, nil +} From b4f4df5606d22d30ef4916019ac8e205c78375f4 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:01:50 +0000 Subject: [PATCH 09/32] feat(dogfood): implement operator hooks --- proto/exocore/dogfood/v1/dogfood.proto | 58 ++ x/dogfood/keeper/impl_operator_hooks.go | 107 +++ x/dogfood/keeper/keeper.go | 35 + x/dogfood/keeper/opt_out.go | 162 ++++ x/dogfood/keeper/queue.go | 45 ++ x/dogfood/keeper/unbonding.go | 58 ++ x/dogfood/types/dogfood.pb.go | 955 +++++++++++++++++++++++- x/dogfood/types/expected_keepers.go | 14 +- x/dogfood/types/keys.go | 40 + x/dogfood/types/utils.go | 31 + 10 files changed, 1477 insertions(+), 28 deletions(-) create mode 100644 x/dogfood/keeper/impl_operator_hooks.go create mode 100644 x/dogfood/keeper/opt_out.go create mode 100644 x/dogfood/keeper/queue.go create mode 100644 x/dogfood/keeper/unbonding.go create mode 100644 x/dogfood/types/utils.go diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index e51f4a408..1259ac803 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -5,6 +5,7 @@ package exocore.dogfood.v1; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; import "cosmos_proto/cosmos.proto"; +import "tendermint/crypto/keys.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; @@ -21,4 +22,61 @@ message ExocoreValidator { (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\"" ]; +} + +// OperationType is used to indicate the type of operation that is being +// cached by the module to create the updated validator set. +enum OperationType { + option (gogoproto.goproto_enum_prefix) = false; + // KeyOpUnspecified is used to indicate that the operation type is not specified. + // This should never be used. + OPERATION_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "KeyOpUnspecified" ]; + // KeyAddition is used to indicate that the operation is a key addition. + OPERATION_TYPE_ADDITION_OR_UPDATE = 1 [ (gogoproto.enumvalue_customname) = "KeyAdditionOrUpdate" ]; + // KeyRemoval is used to indicate that the operation is a key removal. Typically + // this is done due to key replacement mechanism and not directly. + OPERATION_TYPE_REMOVAL = 2 [ (gogoproto.enumvalue_customname) = "KeyRemoval" ]; +} + +// QueueResultType is used to indicate the result of the queue operation. +enum QueueResultType { + option (gogoproto.goproto_enum_prefix) = false; + // QueueResultUnspecified is used to indicate that the queue result type is not specified. + QUEUE_RESULT_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "QueueResultUnspecified" ]; + // QueueResultSuccess is used to indicate that the queue operation was successful. + QUEUE_RESULT_TYPE_SUCCESS = 1 [ (gogoproto.enumvalue_customname) = "QueueResultSuccess" ]; + // QueueResultExists is used to indicate that the queue operation failed because the + // operation already exists in the queue. + QUEUE_RESULT_TYPE_EXISTS = 2 [ (gogoproto.enumvalue_customname) = "QueueResultExists" ]; + // QueueResultRemoved is used to indicate that the queue operation resulted in an existing + // operation being removed from the queue. + QUEUE_RESULT_TYPE_REMOVED = 3 [ (gogoproto.enumvalue_customname) = "QueueResultRemoved" ]; +} + +// Operation is used to indicate the operation that is being cached by the module +// to create the updated validator set. +message Operation { + // OperationType is the type of the operation (addition / removal). + OperationType operation_type = 1; + // OperatorAddress is the sdk.AccAddress of the operator. + bytes operator_address = 2; + // PubKey is the public key for which the operation is being applied. + tendermint.crypto.PublicKey pub_key = 3 [(gogoproto.nullable) = false]; +} + +// Operations is a collection of Operation. +message Operations { + repeated Operation list = 1 [(gogoproto.nullable) = false]; +} + +// AccountAddresses represents a list of account addresses. It is used to store the list of +// operator addresses whose operations are maturing at an epoch. +message AccountAddresses { + repeated bytes list = 1; +} + +// ConsensusAddresses represents a list of account addresses. It is used to store the list of +// addresses (which correspond to operator public keys) to delete at the end of an epoch. +message ConsensusAddresses { + repeated bytes list = 1; } \ No newline at end of file diff --git a/x/dogfood/keeper/impl_operator_hooks.go b/x/dogfood/keeper/impl_operator_hooks.go new file mode 100644 index 000000000..e5a42d615 --- /dev/null +++ b/x/dogfood/keeper/impl_operator_hooks.go @@ -0,0 +1,107 @@ +package keeper + +import ( + "strings" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// OperatorHooksWrapper is the wrapper structure that implements the operator hooks for the +// dogfood keeper. +type OperatorHooksWrapper struct { + keeper *Keeper +} + +// Interface guards +var _ types.OperatorHooks = OperatorHooksWrapper{} + +func (k *Keeper) OperatorHooks() OperatorHooksWrapper { + return OperatorHooksWrapper{k} +} + +// Hooks assumptions: Assuming I is opt-in, O is opt-out and R is key replacement, these are all +// possible within the same epoch, for a fresh operator. +// I O +// I R +// I R O +// This is not possible for a fresh operator to do: +// I O R +// R I O +// R I +// For an operator that is already opted in, the list looks like follows: +// R O +// O I +// O I R +// R O I +// The impossible list looks like: +// O R +// O R I +// TODO: list out operation results for each of these, and make sure everything is covered below + +// AfterOperatorOptIn is the implementation of the operator hooks. +func (h OperatorHooksWrapper) AfterOperatorOptIn( + ctx sdk.Context, addr sdk.AccAddress, + chainID string, pubKey tmprotocrypto.PublicKey, +) { + if strings.Compare(ctx.ChainID(), chainID) == 0 { + // res == Removed, it means operator has opted back in + // res == Success, there is no additional information to store + // res == Exists, there is nothing to do + if res := h.keeper.QueueOperation( + ctx, addr, pubKey, types.KeyAdditionOrUpdate, + ); res == types.QueueResultRemoved { + // the old operation was key removal, which is now removed from the queue. + // so all of the changes that were associated with it need to be undone. + h.keeper.ClearUnbondingInformation(ctx, addr, pubKey) + } + } +} + +// AfterOperatorKeyReplacement is the implementation of the operator hooks. +func (h OperatorHooksWrapper) AfterOperatorKeyReplacement( + ctx sdk.Context, addr sdk.AccAddress, + newKey tmprotocrypto.PublicKey, oldKey tmprotocrypto.PublicKey, + chainID string, +) { + if strings.Compare(chainID, ctx.ChainID()) == 0 { + // res == Removed, it means operator has added their original key again + // res == Success, there is no additional information to store + // res == Exists, there is no nothing to do + if res := h.keeper.QueueOperation( + ctx, addr, newKey, types.KeyAdditionOrUpdate, + ); res == types.QueueResultRemoved { + // see AfterOperatorOptIn for explanation + h.keeper.ClearUnbondingInformation(ctx, addr, newKey) + } + // res == Removed, it means operator had added this key and is now removing it. + // no additional information to clear. + // res == Success, the old key should be pruned from the operator module. + // res == Exists, there is nothing to do. + if res := h.keeper.QueueOperation( + ctx, addr, oldKey, types.KeyRemoval, + ); res == types.QueueResultSuccess { + // the old key can be marked for pruning + h.keeper.SetUnbondingInformation(ctx, addr, oldKey, false) + } + } +} + +// AfterOperatorOptOutInitiated is the implementation of the operator hooks. +func (h OperatorHooksWrapper) AfterOperatorOptOutInitiated( + ctx sdk.Context, addr sdk.AccAddress, + chainID string, pubKey tmprotocrypto.PublicKey, +) { + if strings.Compare(chainID, ctx.ChainID()) == 0 { + // res == Removed means operator had opted in and is now opting out. nothing to do if + // it is within the same epoch. + // res == Success, set up pruning deadline and opt out completion deadline + // res == Exists, there is nothing to do (should never happen) + if res := h.keeper.QueueOperation( + ctx, addr, pubKey, types.KeyRemoval, + ); res == types.QueueResultSuccess { + h.keeper.SetUnbondingInformation(ctx, addr, pubKey, true) + } + } +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index b90ec9095..47e766553 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -66,3 +66,38 @@ func (k *Keeper) SetHooks(sh types.DogfoodHooks) *Keeper { func (k Keeper) Hooks() types.DogfoodHooks { return k.dogfoodHooks } + +// GetQueuedKeyOperations returns the list of operations that are queued for execution at the +// end of the current epoch. +func (k Keeper) GetQueuedOperations( + ctx sdk.Context, +) []types.Operation { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.QueuedOperationsKey()) + if bz == nil { + return []types.Operation{} + } + var operations types.Operations + if err := operations.Unmarshal(bz); err != nil { + // TODO(mm): any failure to unmarshal is treated as no operations or panic? + return []types.Operation{} + } + return operations.GetList() +} + +// ClearQueuedOperations clears the operations to be executed at the end of the epoch. +func (k Keeper) ClearQueuedOperations(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.QueuedOperationsKey()) +} + +// setQueuedOperations is a private, internal function used to update the current queue of +// operations to be executed at the end of the epoch with the supplied value. +func (k Keeper) setQueuedOperations(ctx sdk.Context, operations types.Operations) { + store := ctx.KVStore(k.storeKey) + bz, err := operations.Marshal() + if err != nil { + panic(err) + } + store.Set(types.QueuedOperationsKey(), bz) +} diff --git a/x/dogfood/keeper/opt_out.go b/x/dogfood/keeper/opt_out.go new file mode 100644 index 000000000..939d747e3 --- /dev/null +++ b/x/dogfood/keeper/opt_out.go @@ -0,0 +1,162 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AppendOptOutToFinish appends an operator address to the list of operator addresses that have +// opted out and will be finished at the end of the provided epoch. +func (k Keeper) AppendOptOutToFinish( + ctx sdk.Context, epoch int64, operatorAddr sdk.AccAddress, +) { + prev := k.GetOptOutsToFinish(ctx, epoch) + next := types.AccountAddresses{List: append(prev, operatorAddr)} + k.setOptOutsToFinish(ctx, epoch, next) +} + +// GetOptOutsToFinish returns the list of operator addresses that have opted out and will be +// finished at the end of the provided epoch. +func (k Keeper) GetOptOutsToFinish( + ctx sdk.Context, epoch int64, +) [][]byte { + store := ctx.KVStore(k.storeKey) + key := types.OptOutsToFinishKey(epoch) + bz := store.Get(key) + if bz == nil { + return [][]byte{} + } + var res types.AccountAddresses + if err := res.Unmarshal(bz); err != nil { + panic(err) + } + return res.GetList() +} + +// setOptOutsToFinish sets the list of operator addresses that have opted out and will be +// finished at the end of the provided epoch. +func (k Keeper) setOptOutsToFinish( + ctx sdk.Context, epoch int64, addrs types.AccountAddresses, +) { + store := ctx.KVStore(k.storeKey) + key := types.OptOutsToFinishKey(epoch) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(key, bz) +} + +// RemoveOptOutToFinish removes an operator address from the list of operator addresses that +// have opted out and will be finished at the end of the provided epoch. +func (k Keeper) RemoveOptOutToFinish(ctx sdk.Context, epoch int64, addr sdk.AccAddress) { + prev := k.GetOptOutsToFinish(ctx, epoch) + next := types.AccountAddresses{ + List: types.RemoveFromBytesList(prev, addr), + } + k.setOptOutsToFinish(ctx, epoch, next) +} + +// ClearOptOutsToFinish clears the list of operator addresses that have opted out and will be +// finished at the end of the provided epoch. +func (k Keeper) ClearOptOutsToFinish(ctx sdk.Context, epoch int64) { + store := ctx.KVStore(k.storeKey) + key := types.OptOutsToFinishKey(epoch) + store.Delete(key) +} + +// SetOperatorOptOutFinishEpoch sets the epoch at which an operator's opt out will be finished. +func (k Keeper) SetOperatorOptOutFinishEpoch( + ctx sdk.Context, operatorAddr sdk.AccAddress, epoch int64, +) { + store := ctx.KVStore(k.storeKey) + key := types.OperatorOptOutFinishEpochKey(operatorAddr) + bz := sdk.Uint64ToBigEndian(uint64(epoch)) + store.Set(key, bz) +} + +// GetOperatorOptOutFinishEpoch returns the epoch at which an operator's opt out will be +// finished. +func (k Keeper) GetOperatorOptOutFinishEpoch( + ctx sdk.Context, operatorAddr sdk.AccAddress, +) int64 { + store := ctx.KVStore(k.storeKey) + key := types.OperatorOptOutFinishEpochKey(operatorAddr) + bz := store.Get(key) + if bz == nil { + return -1 + } + return int64(sdk.BigEndianToUint64(bz)) +} + +// DeleteOperatorOptOutFinishEpoch deletes the epoch at which an operator's opt out will be +// finished. +func (k Keeper) DeleteOperatorOptOutFinishEpoch( + ctx sdk.Context, operatorAddr sdk.AccAddress, +) { + store := ctx.KVStore(k.storeKey) + key := types.OperatorOptOutFinishEpochKey(operatorAddr) + store.Delete(key) +} + +// AppendConsensusAddrToPrune appends a consensus address to the list of consensus addresses to +// prune at the end of the epoch. +func (k Keeper) AppendConsensusAddrToPrune( + ctx sdk.Context, epoch int64, operatorAddr sdk.ConsAddress, +) { + prev := k.GetConsensusAddrsToPrune(ctx, epoch) + next := types.ConsensusAddresses{List: append(prev, operatorAddr)} + k.setConsensusAddrsToPrune(ctx, epoch, next) +} + +// GetConsensusAddrsToPrune returns the list of consensus addresses to prune at the end of the +// epoch. +func (k Keeper) GetConsensusAddrsToPrune( + ctx sdk.Context, epoch int64, +) [][]byte { + store := ctx.KVStore(k.storeKey) + key := types.ConsensusAddrsToPruneKey(epoch) + bz := store.Get(key) + if bz == nil { + return [][]byte{} + } + var res types.ConsensusAddresses + if err := res.Unmarshal(bz); err != nil { + panic(err) + } + return res.GetList() +} + +// DeleteConsensusAddrToPrune deletes a consensus address from the list of consensus addresses +// to prune at the end of the provided epoch. +func (k Keeper) DeleteConsensusAddrToPrune( + ctx sdk.Context, epoch int64, addr sdk.ConsAddress, +) { + prev := k.GetConsensusAddrsToPrune(ctx, epoch) + next := types.ConsensusAddresses{ + List: types.RemoveFromBytesList(prev, addr.Bytes()), + } + k.setConsensusAddrsToPrune(ctx, epoch, next) +} + +// ClearConsensusAddrsToPrune clears the list of consensus addresses to prune at the end of the +// epoch. +func (k Keeper) ClearConsensusAddrsToPrune(ctx sdk.Context, epoch int64) { + store := ctx.KVStore(k.storeKey) + key := types.ConsensusAddrsToPruneKey(epoch) + store.Delete(key) +} + +// setConsensusAddrsToPrune sets the list of consensus addresses to prune at the end of the +// epoch. +func (k Keeper) setConsensusAddrsToPrune( + ctx sdk.Context, epoch int64, addrs types.ConsensusAddresses, +) { + store := ctx.KVStore(k.storeKey) + key := types.ConsensusAddrsToPruneKey(epoch) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(key, bz) +} diff --git a/x/dogfood/keeper/queue.go b/x/dogfood/keeper/queue.go new file mode 100644 index 000000000..591962d5f --- /dev/null +++ b/x/dogfood/keeper/queue.go @@ -0,0 +1,45 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// QueueOperation adds an operation to the consensus public key queue. If a similar operation +// already exists, the queue is not modified and QueueResultExists is returned. If a reverse +// operation already exists (removal + addition, or addition + removal), the old operation is +// dropped from the queue and QueueResultRemoved is returned. In the case that the operation is +// added to the queue, QueueResultSuccess is returned. +func (k Keeper) QueueOperation( + ctx sdk.Context, addr sdk.AccAddress, + key tmprotocrypto.PublicKey, operationType types.OperationType, +) types.QueueResultType { + if operationType == types.KeyOpUnspecified { + // should never happen + panic("invalid operation type") + } + currentQueue := k.GetQueuedOperations(ctx) + indexToDelete := len(currentQueue) + for i, operation := range currentQueue { + if operation.PubKey.Equal(key) { + if operation.OperationType == operationType { + return types.QueueResultExists + } else { + indexToDelete = i + break + } + } + } + ret := types.QueueResultSuccess + if indexToDelete > len(currentQueue) { + currentQueue = append(currentQueue[:indexToDelete], currentQueue[indexToDelete+1:]...) + ret = types.QueueResultRemoved + } else { + operation := types.Operation{OperationType: operationType, OperatorAddress: addr, PubKey: key} + currentQueue = append(currentQueue, operation) + } + operations := types.Operations{List: currentQueue} + k.setQueuedOperations(ctx, operations) + return ret +} diff --git a/x/dogfood/keeper/unbonding.go b/x/dogfood/keeper/unbonding.go new file mode 100644 index 000000000..4987e523a --- /dev/null +++ b/x/dogfood/keeper/unbonding.go @@ -0,0 +1,58 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// ClearUnbondingInformation clears all information related to an operator's opt out +// or key replacement. This is done because the operator has opted back in or has +// replaced their key (again) with the original one. +func (k Keeper) ClearUnbondingInformation( + ctx sdk.Context, addr sdk.AccAddress, pubKey tmprotocrypto.PublicKey, +) { + optOutEpoch := k.GetOperatorOptOutFinishEpoch(ctx, addr) + k.DeleteOperatorOptOutFinishEpoch(ctx, addr) + k.RemoveOptOutToFinish(ctx, optOutEpoch, addr) + consAddress, err := types.TMCryptoPublicKeyToConsAddr(pubKey) + if err != nil { + panic(err) + } + k.DeleteConsensusAddrToPrune(ctx, optOutEpoch, consAddress) +} + +// SetUnbondingInformation sets information related to an operator's opt out or key replacement. +func (k Keeper) SetUnbondingInformation( + ctx sdk.Context, addr sdk.AccAddress, pubKey tmprotocrypto.PublicKey, isOptingOut bool, +) { + unbondingCompletionEpoch := k.GetUnbondingCompletionEpoch(ctx) + k.AppendOptOutToFinish(ctx, unbondingCompletionEpoch, addr) + if isOptingOut { + k.SetOperatorOptOutFinishEpoch(ctx, addr, unbondingCompletionEpoch) + } + consAddress, err := types.TMCryptoPublicKeyToConsAddr(pubKey) + if err != nil { + panic(err) + } + k.AppendConsensusAddrToPrune(ctx, unbondingCompletionEpoch, consAddress) +} + +// GetUnbondingCompletionEpoch returns the epoch at the end of which +// an unbonding triggered in this epoch will be completed. +func (k Keeper) GetUnbondingCompletionEpoch( + ctx sdk.Context, +) int64 { + unbondingEpochs := k.GetEpochsUntilUnbonded(ctx) + epochInfo, found := k.epochsKeeper.GetEpochInfo( + ctx, k.GetEpochIdentifier(ctx), + ) + if !found { + panic("current epoch not found") + } + // if i execute the transaction at epoch 5, the vote power change + // goes into effect at the beginning of epoch 6. the information + // should be held for 7 epochs, so it should be deleted at the + // beginning of epoch 13 or the end of epoch 12. + return epochInfo.CurrentEpoch + int64(unbondingEpochs) +} diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index 64cadbb85..3a64b1dea 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -5,6 +5,7 @@ package types import ( fmt "fmt" + crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" _ "github.com/cosmos/cosmos-proto" types "github.com/cosmos/cosmos-sdk/codec/types" _ "github.com/cosmos/gogoproto/gogoproto" @@ -25,6 +26,79 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// OperationType is used to indicate the type of operation that is being +// cached by the module to create the updated validator set. +type OperationType int32 + +const ( + // KeyOpUnspecified is used to indicate that the operation type is not specified. + // This should never be used. + KeyOpUnspecified OperationType = 0 + // KeyAddition is used to indicate that the operation is a key addition. + KeyAdditionOrUpdate OperationType = 1 + // KeyRemoval is used to indicate that the operation is a key removal. Typically + // this is done due to key replacement mechanism and not directly. + KeyRemoval OperationType = 2 +) + +var OperationType_name = map[int32]string{ + 0: "OPERATION_TYPE_UNSPECIFIED", + 1: "OPERATION_TYPE_ADDITION_OR_UPDATE", + 2: "OPERATION_TYPE_REMOVAL", +} + +var OperationType_value = map[string]int32{ + "OPERATION_TYPE_UNSPECIFIED": 0, + "OPERATION_TYPE_ADDITION_OR_UPDATE": 1, + "OPERATION_TYPE_REMOVAL": 2, +} + +func (x OperationType) String() string { + return proto.EnumName(OperationType_name, int32(x)) +} + +func (OperationType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{0} +} + +// QueueResultType is used to indicate the result of the queue operation. +type QueueResultType int32 + +const ( + // QueueResultUnspecified is used to indicate that the queue result type is not specified. + QueueResultUnspecified QueueResultType = 0 + // QueueResultSuccess is used to indicate that the queue operation was successful. + QueueResultSuccess QueueResultType = 1 + // QueueResultExists is used to indicate that the queue operation failed because the + // operation already exists in the queue. + QueueResultExists QueueResultType = 2 + // QueueResultRemoved is used to indicate that the queue operation resulted in an existing + // operation being removed from the queue. + QueueResultRemoved QueueResultType = 3 +) + +var QueueResultType_name = map[int32]string{ + 0: "QUEUE_RESULT_TYPE_UNSPECIFIED", + 1: "QUEUE_RESULT_TYPE_SUCCESS", + 2: "QUEUE_RESULT_TYPE_EXISTS", + 3: "QUEUE_RESULT_TYPE_REMOVED", +} + +var QueueResultType_value = map[string]int32{ + "QUEUE_RESULT_TYPE_UNSPECIFIED": 0, + "QUEUE_RESULT_TYPE_SUCCESS": 1, + "QUEUE_RESULT_TYPE_EXISTS": 2, + "QUEUE_RESULT_TYPE_REMOVED": 3, +} + +func (x QueueResultType) String() string { + return proto.EnumName(QueueResultType_name, int32(x)) +} + +func (QueueResultType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{1} +} + // ExocoreValidator is a validator that is part of the Exocore network. It is // used to validate and sign blocks and transactions. type ExocoreValidator struct { @@ -91,33 +165,267 @@ func (m *ExocoreValidator) GetPubkey() *types.Any { return nil } +// Operation is used to indicate the operation that is being cached by the module +// to create the updated validator set. +type Operation struct { + // OperationType is the type of the operation (addition / removal). + OperationType OperationType `protobuf:"varint,1,opt,name=operation_type,json=operationType,proto3,enum=exocore.dogfood.v1.OperationType" json:"operation_type,omitempty"` + // OperatorAddress is the sdk.AccAddress of the operator. + OperatorAddress []byte `protobuf:"bytes,2,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` + // PubKey is the public key for which the operation is being applied. + PubKey crypto.PublicKey `protobuf:"bytes,3,opt,name=pub_key,json=pubKey,proto3" json:"pub_key"` +} + +func (m *Operation) Reset() { *m = Operation{} } +func (m *Operation) String() string { return proto.CompactTextString(m) } +func (*Operation) ProtoMessage() {} +func (*Operation) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{1} +} +func (m *Operation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Operation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Operation.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 *Operation) XXX_Merge(src proto.Message) { + xxx_messageInfo_Operation.Merge(m, src) +} +func (m *Operation) XXX_Size() int { + return m.Size() +} +func (m *Operation) XXX_DiscardUnknown() { + xxx_messageInfo_Operation.DiscardUnknown(m) +} + +var xxx_messageInfo_Operation proto.InternalMessageInfo + +func (m *Operation) GetOperationType() OperationType { + if m != nil { + return m.OperationType + } + return KeyOpUnspecified +} + +func (m *Operation) GetOperatorAddress() []byte { + if m != nil { + return m.OperatorAddress + } + return nil +} + +func (m *Operation) GetPubKey() crypto.PublicKey { + if m != nil { + return m.PubKey + } + return crypto.PublicKey{} +} + +// Operations is a collection of Operation. +type Operations struct { + List []Operation `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` +} + +func (m *Operations) Reset() { *m = Operations{} } +func (m *Operations) String() string { return proto.CompactTextString(m) } +func (*Operations) ProtoMessage() {} +func (*Operations) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{2} +} +func (m *Operations) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Operations) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Operations.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 *Operations) XXX_Merge(src proto.Message) { + xxx_messageInfo_Operations.Merge(m, src) +} +func (m *Operations) XXX_Size() int { + return m.Size() +} +func (m *Operations) XXX_DiscardUnknown() { + xxx_messageInfo_Operations.DiscardUnknown(m) +} + +var xxx_messageInfo_Operations proto.InternalMessageInfo + +func (m *Operations) GetList() []Operation { + if m != nil { + return m.List + } + return nil +} + +// AccountAddresses represents a list of account addresses. It is used to store the list of +// operator addresses whose operations are maturing at an epoch. +type AccountAddresses struct { + List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` +} + +func (m *AccountAddresses) Reset() { *m = AccountAddresses{} } +func (m *AccountAddresses) String() string { return proto.CompactTextString(m) } +func (*AccountAddresses) ProtoMessage() {} +func (*AccountAddresses) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{3} +} +func (m *AccountAddresses) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccountAddresses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccountAddresses.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 *AccountAddresses) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountAddresses.Merge(m, src) +} +func (m *AccountAddresses) XXX_Size() int { + return m.Size() +} +func (m *AccountAddresses) XXX_DiscardUnknown() { + xxx_messageInfo_AccountAddresses.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountAddresses proto.InternalMessageInfo + +func (m *AccountAddresses) GetList() [][]byte { + if m != nil { + return m.List + } + return nil +} + +// ConsensusAddresses represents a list of account addresses. It is used to store the list of +// addresses (which correspond to operator public keys) to delete at the end of an epoch. +type ConsensusAddresses struct { + List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` +} + +func (m *ConsensusAddresses) Reset() { *m = ConsensusAddresses{} } +func (m *ConsensusAddresses) String() string { return proto.CompactTextString(m) } +func (*ConsensusAddresses) ProtoMessage() {} +func (*ConsensusAddresses) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{4} +} +func (m *ConsensusAddresses) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsensusAddresses) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsensusAddresses.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 *ConsensusAddresses) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsensusAddresses.Merge(m, src) +} +func (m *ConsensusAddresses) XXX_Size() int { + return m.Size() +} +func (m *ConsensusAddresses) XXX_DiscardUnknown() { + xxx_messageInfo_ConsensusAddresses.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsensusAddresses proto.InternalMessageInfo + +func (m *ConsensusAddresses) GetList() [][]byte { + if m != nil { + return m.List + } + return nil +} + func init() { + proto.RegisterEnum("exocore.dogfood.v1.OperationType", OperationType_name, OperationType_value) + proto.RegisterEnum("exocore.dogfood.v1.QueueResultType", QueueResultType_name, QueueResultType_value) proto.RegisterType((*ExocoreValidator)(nil), "exocore.dogfood.v1.ExocoreValidator") + proto.RegisterType((*Operation)(nil), "exocore.dogfood.v1.Operation") + proto.RegisterType((*Operations)(nil), "exocore.dogfood.v1.Operations") + proto.RegisterType((*AccountAddresses)(nil), "exocore.dogfood.v1.AccountAddresses") + proto.RegisterType((*ConsensusAddresses)(nil), "exocore.dogfood.v1.ConsensusAddresses") } func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } var fileDescriptor_071b9989c501c3f2 = []byte{ - // 302 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0x31, 0x4e, 0xf3, 0x30, - 0x14, 0xc7, 0xeb, 0xaf, 0xfa, 0x8a, 0x14, 0x18, 0x50, 0x14, 0x89, 0xd0, 0xc1, 0x44, 0x9d, 0xba, - 0x60, 0xab, 0x74, 0x63, 0xa3, 0x12, 0x53, 0x25, 0x84, 0x3a, 0x30, 0xb0, 0x54, 0x4e, 0xe2, 0x9a, - 0xaa, 0x49, 0x5e, 0x64, 0x3b, 0x6d, 0x7d, 0x0b, 0x2e, 0xc1, 0x0d, 0x38, 0x04, 0x62, 0xea, 0xc8, - 0x84, 0x50, 0x72, 0x03, 0x4e, 0x80, 0x88, 0x63, 0xb6, 0xf7, 0xf3, 0xff, 0x3d, 0xfb, 0xe7, 0xe7, - 0x45, 0x7c, 0x0f, 0x09, 0x48, 0x4e, 0x53, 0x10, 0x2b, 0x80, 0x94, 0x6e, 0x27, 0xae, 0x24, 0xa5, - 0x04, 0x0d, 0xbe, 0xdf, 0x75, 0x10, 0x77, 0xbc, 0x9d, 0x0c, 0x03, 0x01, 0x02, 0xda, 0x98, 0xfe, - 0x56, 0xb6, 0x73, 0x78, 0x2e, 0x00, 0x44, 0xc6, 0x69, 0x4b, 0x71, 0xb5, 0xa2, 0xac, 0x30, 0x2e, - 0x4a, 0x40, 0xe5, 0xa0, 0x96, 0x76, 0xc6, 0x82, 0x8d, 0x46, 0x2f, 0xc8, 0x3b, 0xbd, 0xb5, 0x4f, - 0x3c, 0xb0, 0x6c, 0x9d, 0x32, 0x0d, 0xd2, 0x0f, 0xbd, 0x23, 0x96, 0xa6, 0x92, 0x2b, 0x15, 0xa2, - 0x08, 0x8d, 0x4f, 0x16, 0x0e, 0xfd, 0xc0, 0xfb, 0x5f, 0xc2, 0x8e, 0xcb, 0xf0, 0x5f, 0x84, 0xc6, - 0xfd, 0x85, 0x05, 0x9f, 0x79, 0x83, 0xb2, 0x8a, 0x37, 0xdc, 0x84, 0xfd, 0x08, 0x8d, 0x8f, 0xaf, - 0x02, 0x62, 0x5d, 0x88, 0x73, 0x21, 0x37, 0x85, 0x99, 0x4d, 0xbf, 0x3f, 0x2f, 0xce, 0x0c, 0xcb, - 0xb3, 0xeb, 0x51, 0x02, 0x85, 0xe2, 0x85, 0xaa, 0xd4, 0xd2, 0xce, 0x8d, 0xde, 0x5f, 0x2f, 0x83, - 0xce, 0x2b, 0x91, 0xa6, 0xd4, 0x40, 0xee, 0xab, 0x78, 0xce, 0xcd, 0xa2, 0xbb, 0x78, 0x36, 0x7f, - 0xab, 0x31, 0x3a, 0xd4, 0x18, 0x7d, 0xd5, 0x18, 0x3d, 0x37, 0xb8, 0x77, 0x68, 0x70, 0xef, 0xa3, - 0xc1, 0xbd, 0xc7, 0x89, 0x58, 0xeb, 0xa7, 0x2a, 0x26, 0x09, 0xe4, 0xb4, 0xfb, 0xc9, 0x1d, 0xd7, - 0x3b, 0x90, 0x1b, 0xea, 0xb6, 0xbb, 0xff, 0xdb, 0xaf, 0x36, 0x25, 0x57, 0xf1, 0xa0, 0xf5, 0x9a, - 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x39, 0xda, 0x59, 0x49, 0x7f, 0x01, 0x00, 0x00, + // 705 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xcf, 0x4e, 0xdb, 0x4a, + 0x14, 0xc6, 0xe3, 0x84, 0x0b, 0xba, 0xc3, 0x3f, 0xdf, 0xb9, 0x29, 0x04, 0x0b, 0x82, 0xc9, 0xa2, + 0x4a, 0x91, 0x6a, 0x0b, 0x68, 0x55, 0xa9, 0x55, 0x2b, 0x99, 0xc4, 0x55, 0xa3, 0x50, 0x12, 0xec, + 0x18, 0xb5, 0xdd, 0x58, 0x8e, 0x7d, 0x48, 0x2d, 0x12, 0x8f, 0xe5, 0xb1, 0x01, 0xbf, 0x41, 0x95, + 0x55, 0x5f, 0x20, 0xab, 0xaa, 0x6f, 0x50, 0xa9, 0xab, 0xee, 0x51, 0x57, 0x2c, 0xbb, 0x42, 0x15, + 0xbc, 0x41, 0x77, 0xdd, 0x55, 0xf1, 0x1f, 0x48, 0x09, 0x62, 0xe7, 0x6f, 0xce, 0xf9, 0x66, 0x7e, + 0xdf, 0x91, 0x67, 0x10, 0x0f, 0x27, 0xc4, 0x24, 0x1e, 0x88, 0x16, 0xe9, 0x1c, 0x10, 0x62, 0x89, + 0x47, 0x1b, 0xe9, 0xa7, 0xe0, 0x7a, 0xc4, 0x27, 0x18, 0x27, 0x1d, 0x42, 0xba, 0x7c, 0xb4, 0xc1, + 0xe5, 0x3b, 0xa4, 0x43, 0xa2, 0xb2, 0x38, 0xfc, 0x8a, 0x3b, 0xb9, 0xa5, 0x0e, 0x21, 0x9d, 0x2e, + 0x88, 0x91, 0x6a, 0x07, 0x07, 0xa2, 0xe1, 0x84, 0x69, 0xc9, 0x24, 0xb4, 0x47, 0xa8, 0x1e, 0x7b, + 0x62, 0x91, 0x94, 0x96, 0x7d, 0x70, 0x2c, 0xf0, 0x7a, 0xb6, 0xe3, 0x8b, 0xa6, 0x17, 0xba, 0x3e, + 0x11, 0x0f, 0x21, 0x4c, 0xaa, 0xa5, 0xcf, 0x0c, 0x62, 0xe5, 0x18, 0x60, 0xdf, 0xe8, 0xda, 0x96, + 0xe1, 0x13, 0x0f, 0x17, 0xd0, 0x94, 0x61, 0x59, 0x1e, 0x50, 0x5a, 0x60, 0x78, 0xa6, 0x3c, 0xa3, + 0xa4, 0x12, 0xe7, 0xd1, 0x3f, 0x2e, 0x39, 0x06, 0xaf, 0x90, 0xe5, 0x99, 0x72, 0x4e, 0x89, 0x05, + 0x36, 0xd0, 0xa4, 0x1b, 0xb4, 0x0f, 0x21, 0x2c, 0xe4, 0x78, 0xa6, 0x3c, 0xbd, 0x99, 0x17, 0x62, + 0x52, 0x21, 0x25, 0x15, 0x24, 0x27, 0xdc, 0xde, 0xfa, 0x75, 0xbe, 0xba, 0x18, 0x1a, 0xbd, 0xee, + 0xd3, 0x92, 0x49, 0x1c, 0x0a, 0x0e, 0x0d, 0xa8, 0x1e, 0xfb, 0x4a, 0xdf, 0xbf, 0x3c, 0xcc, 0x27, + 0xd4, 0x31, 0xa3, 0xd0, 0x0c, 0xda, 0x75, 0x08, 0x95, 0x64, 0xe3, 0xd2, 0x37, 0x06, 0xfd, 0xdb, + 0x70, 0xc1, 0x33, 0x7c, 0x9b, 0x38, 0xf8, 0x15, 0x9a, 0x23, 0xa9, 0xd0, 0xfd, 0xd0, 0x85, 0x88, + 0x73, 0x6e, 0x73, 0x4d, 0x18, 0x1f, 0xa6, 0x70, 0x65, 0x6b, 0x85, 0x2e, 0x28, 0xb3, 0x64, 0x54, + 0xe2, 0x07, 0x88, 0x8d, 0x17, 0x88, 0xa7, 0xa7, 0x99, 0xb3, 0x51, 0xe6, 0xf9, 0x74, 0x5d, 0x4a, + 0xb2, 0x3f, 0x43, 0x53, 0x6e, 0xd0, 0xd6, 0xaf, 0x63, 0x2e, 0x0b, 0xd7, 0xa3, 0x1d, 0xc1, 0xee, + 0xda, 0x66, 0x1d, 0xc2, 0xed, 0x89, 0xd3, 0xf3, 0xd5, 0x4c, 0xc4, 0x5f, 0x87, 0xb0, 0x24, 0x23, + 0x74, 0xc5, 0x41, 0xf1, 0x13, 0x34, 0xd1, 0xb5, 0xa9, 0x5f, 0x60, 0xf8, 0x5c, 0x79, 0x7a, 0x73, + 0xe5, 0x4e, 0xea, 0x64, 0xa3, 0xc8, 0x50, 0xba, 0x8f, 0x58, 0xc9, 0x34, 0x49, 0xe0, 0xf8, 0x09, + 0x15, 0x50, 0x8c, 0x47, 0x36, 0x9b, 0x49, 0xfa, 0xca, 0x08, 0x57, 0xd2, 0x19, 0xdf, 0xd9, 0xb9, + 0xfe, 0x95, 0x41, 0xb3, 0x7f, 0x4d, 0x08, 0x3f, 0x42, 0x5c, 0xa3, 0x29, 0x2b, 0x52, 0xab, 0xd6, + 0xd8, 0xd5, 0x5b, 0x6f, 0x9b, 0xb2, 0xae, 0xed, 0xaa, 0x4d, 0xb9, 0x52, 0x7b, 0x59, 0x93, 0xab, + 0x6c, 0x86, 0xcb, 0xf7, 0x07, 0x3c, 0x5b, 0x87, 0xb0, 0xe1, 0x6a, 0x0e, 0x75, 0xc1, 0xb4, 0x0f, + 0x6c, 0xb0, 0xf0, 0x0b, 0xb4, 0x76, 0xc3, 0x25, 0x55, 0xab, 0xb5, 0x48, 0x35, 0x14, 0x5d, 0x6b, + 0x56, 0xa5, 0x96, 0xcc, 0x32, 0xdc, 0x62, 0x7f, 0xc0, 0xff, 0x5f, 0x87, 0x50, 0xb2, 0x2c, 0x7b, + 0x78, 0x62, 0xc3, 0xd3, 0x5c, 0xcb, 0xf0, 0x01, 0xaf, 0xa3, 0x85, 0x1b, 0x7e, 0x45, 0x7e, 0xdd, + 0xd8, 0x97, 0x76, 0xd8, 0x2c, 0x37, 0xd7, 0x1f, 0xf0, 0x68, 0xf8, 0x37, 0x40, 0x8f, 0x1c, 0x19, + 0x5d, 0x6e, 0xe2, 0xc3, 0xa7, 0x62, 0x66, 0xfd, 0x37, 0x83, 0xe6, 0xf7, 0x02, 0x08, 0x40, 0x01, + 0x1a, 0x74, 0xfd, 0x88, 0xfd, 0x39, 0x5a, 0xd9, 0xd3, 0x64, 0x6d, 0x68, 0x56, 0xb5, 0x9d, 0xd6, + 0x6d, 0xf8, 0x5c, 0x7f, 0xc0, 0x2f, 0x8c, 0xf8, 0x46, 0x43, 0x3c, 0x46, 0x4b, 0xe3, 0x76, 0x55, + 0xab, 0x54, 0x64, 0x55, 0x65, 0x19, 0x6e, 0xa1, 0x3f, 0xe0, 0xf1, 0x88, 0x55, 0x0d, 0x4c, 0x73, + 0xf8, 0x67, 0x6c, 0xa1, 0xc2, 0xb8, 0x4d, 0x7e, 0x53, 0x53, 0x5b, 0x2a, 0x9b, 0xe5, 0xee, 0xf5, + 0x07, 0xfc, 0x7f, 0x23, 0x2e, 0xf9, 0xc4, 0xa6, 0x3e, 0xbd, 0xfd, 0xac, 0x28, 0xb3, 0x5c, 0x65, + 0x73, 0x63, 0x67, 0x45, 0xd9, 0xc1, 0x8a, 0xb3, 0x6f, 0xd7, 0x4f, 0x2f, 0x8a, 0xcc, 0xd9, 0x45, + 0x91, 0xf9, 0x79, 0x51, 0x64, 0x3e, 0x5e, 0x16, 0x33, 0x67, 0x97, 0xc5, 0xcc, 0x8f, 0xcb, 0x62, + 0xe6, 0xdd, 0x46, 0xc7, 0xf6, 0xdf, 0x07, 0x6d, 0xc1, 0x24, 0x3d, 0x31, 0xb9, 0xd8, 0xbb, 0xe0, + 0x1f, 0x13, 0xef, 0x50, 0x4c, 0x9f, 0xa2, 0x93, 0xab, 0xc7, 0x68, 0x78, 0x75, 0x68, 0x7b, 0x32, + 0xba, 0xa6, 0x5b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xf3, 0x23, 0x11, 0xac, 0x04, 0x00, + 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { @@ -167,6 +475,152 @@ func (m *ExocoreValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Operation) 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 *Operation) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Operation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.PubKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDogfood(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.OperatorAddress) > 0 { + i -= len(m.OperatorAddress) + copy(dAtA[i:], m.OperatorAddress) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.OperatorAddress))) + i-- + dAtA[i] = 0x12 + } + if m.OperationType != 0 { + i = encodeVarintDogfood(dAtA, i, uint64(m.OperationType)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *Operations) 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 *Operations) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Operations) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDogfood(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *AccountAddresses) 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 *AccountAddresses) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccountAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.List[iNdEx]) + copy(dAtA[i:], m.List[iNdEx]) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.List[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *ConsensusAddresses) 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 *ConsensusAddresses) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsensusAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.List[iNdEx]) + copy(dAtA[i:], m.List[iNdEx]) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.List[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintDogfood(dAtA []byte, offset int, v uint64) int { offset -= sovDogfood(v) base := offset @@ -198,15 +652,78 @@ func (m *ExocoreValidator) Size() (n int) { return n } -func sovDogfood(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 +func (m *Operation) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.OperationType != 0 { + n += 1 + sovDogfood(uint64(m.OperationType)) + } + l = len(m.OperatorAddress) + if l > 0 { + n += 1 + l + sovDogfood(uint64(l)) + } + l = m.PubKey.Size() + n += 1 + l + sovDogfood(uint64(l)) + return n } -func sozDogfood(x uint64) (n int) { - return sovDogfood(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + +func (m *Operations) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, e := range m.List { + l = e.Size() + n += 1 + l + sovDogfood(uint64(l)) + } + } + return n } -func (m *ExocoreValidator) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 + +func (m *AccountAddresses) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, b := range m.List { + l = len(b) + n += 1 + l + sovDogfood(uint64(l)) + } + } + return n +} + +func (m *ConsensusAddresses) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, b := range m.List { + l = len(b) + n += 1 + l + sovDogfood(uint64(l)) + } + } + return n +} + +func sovDogfood(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozDogfood(x uint64) (n int) { + return sovDogfood(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *ExocoreValidator) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 for iNdEx < l { preIndex := iNdEx var wire uint64 @@ -343,6 +860,390 @@ func (m *ExocoreValidator) Unmarshal(dAtA []byte) error { } return nil } +func (m *Operation) 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 ErrIntOverflowDogfood + } + 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: Operation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Operation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OperationType", wireType) + } + m.OperationType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.OperationType |= OperationType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.OperatorAddress = append(m.OperatorAddress[:0], dAtA[iNdEx:postIndex]...) + if m.OperatorAddress == nil { + m.OperatorAddress = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.PubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Operations) 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 ErrIntOverflowDogfood + } + 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: Operations: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Operations: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, Operation{}) + if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *AccountAddresses) 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 ErrIntOverflowDogfood + } + 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: AccountAddresses: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AccountAddresses: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, make([]byte, postIndex-iNdEx)) + copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConsensusAddresses) 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 ErrIntOverflowDogfood + } + 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: ConsensusAddresses: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsensusAddresses: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, make([]byte, postIndex-iNdEx)) + copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipDogfood(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index b498ad09b..1880294b6 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -1,6 +1,7 @@ package types import ( + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" epochsTypes "github.com/evmos/evmos/v14/x/epochs/types" ) @@ -10,7 +11,7 @@ type EpochsKeeper interface { GetEpochInfo(sdk.Context, string) (epochsTypes.EpochInfo, bool) } -// DogfoodHooks represent the event hooks for dogfood module. Ideally, these should +// DogfoodHooks represents the event hooks for dogfood module. Ideally, these should // match those of the staking module but for now it is only a subset of them. The side effects // of calling the other hooks are not relevant to running the chain, so they can be skipped. type DogfoodHooks interface { @@ -18,3 +19,14 @@ type DogfoodHooks interface { sdk.Context, sdk.ConsAddress, sdk.ValAddress, ) error } + +// OperatorHooks is the interface for the operator module's hooks. The functions are called +// whenever an operator opts in to a Cosmos chain, opts out of a Cosmos chain, or replaces their +// public key with another one. +type OperatorHooks interface { + AfterOperatorOptIn(sdk.Context, sdk.AccAddress, string, tmprotocrypto.PublicKey) + AfterOperatorKeyReplacement( + sdk.Context, sdk.AccAddress, tmprotocrypto.PublicKey, tmprotocrypto.PublicKey, string, + ) + AfterOperatorOptOutInitiated(sdk.Context, sdk.AccAddress, string, tmprotocrypto.PublicKey) +} diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index f7efde563..b0b823c05 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -18,6 +18,21 @@ const ( // HistoricalInfoBytePrefix is the prefix for the historical info store. HistoricalInfoBytePrefix + + // QueuedOperationsByte is the byte used to store the queue of operations. + QueuedOperationsByte + + // OptOutsToFinishBytePrefix is the byte used to store the list of operator addresses whose + // opt outs are maturing at the provided epoch. + OptOutsToFinishBytePrefix + + // OperatorOptOutFinishEpochBytePrefix is the byte prefix to store the epoch at which an + // operator's opt out will mature. + OperatorOptOutFinishEpochBytePrefix + + // ConsensusAddrsToPruneBytePrefix is the byte prefix to store the list of consensus + // addresses that can be pruned from the operator module at the provided epoch. + ConsensusAddrsToPruneBytePrefix ) // ExocoreValidatorKey returns the key for the validator store. @@ -30,3 +45,28 @@ func HistoricalInfoKey(height int64) []byte { bz := sdk.Uint64ToBigEndian(uint64(height)) return append([]byte{HistoricalInfoBytePrefix}, bz...) } + +// QueuedOperationsKey returns the key for the queued operations store. +func QueuedOperationsKey() []byte { + return []byte{QueuedOperationsByte} +} + +// OptOutsToFinishKey returns the key for the operator opt out maturity store (epoch -> list of +// addresses). +func OptOutsToFinishKey(epoch int64) []byte { + return append([]byte{OptOutsToFinishBytePrefix}, sdk.Uint64ToBigEndian(uint64(epoch))...) +} + +// OperatorOptOutFinishEpochKey is the key for the operator opt out maturity store +// (sdk.AccAddress -> epoch) +func OperatorOptOutFinishEpochKey(address sdk.AccAddress) []byte { + return append([]byte{OperatorOptOutFinishEpochBytePrefix}, address.Bytes()...) +} + +// ConsensusAddrsToPruneKey is the key to lookup the list of operator consensus addresses that +// can be pruned from the operator module at the provided epoch. +func ConsensusAddrsToPruneKey(epoch int64) []byte { + return append( + []byte{ConsensusAddrsToPruneBytePrefix}, + sdk.Uint64ToBigEndian(uint64(epoch))...) +} diff --git a/x/dogfood/types/utils.go b/x/dogfood/types/utils.go new file mode 100644 index 000000000..079a21dec --- /dev/null +++ b/x/dogfood/types/utils.go @@ -0,0 +1,31 @@ +package types + +import ( + "bytes" + + sdk "github.com/cosmos/cosmos-sdk/types" + + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" +) + +// TMCryptoPublicKeyToConsAddr converts a TM public key to an SDK public key +// and returns the associated consensus address. +func TMCryptoPublicKeyToConsAddr(k tmprotocrypto.PublicKey) (sdk.ConsAddress, error) { + sdkK, err := cryptocodec.FromTmProtoPublicKey(k) + if err != nil { + return nil, err + } + return sdk.GetConsAddress(sdkK), nil +} + +// RemoveFromBytesList removes an address from a list of addresses +// or a byte slice from a list of byte slices. +func RemoveFromBytesList(list [][]byte, addr []byte) [][]byte { + for i, a := range list { + if bytes.Equal(a, addr) { + return append(list[:i], list[i+1:]...) + } + } + panic("address not found in list") +} From fdf9b9a367acd3388478faaf244bebe469af0095 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:33:33 +0000 Subject: [PATCH 10/32] docs(dogfood): explain the operator queue logic The operator module should restrict an operator from doing things that are logically not possible. For example, an operator that is already opted in should not be able to opt in again. Similarly, an operator who has opted out of a chain should not be able to replace the key for that chain without opting back in. Based on these assumptions, the comment maps out the list of possible operations that can happen within an epoch and is used to ensure that all of the cases result in the unbonding period being enforced accurately. --- x/dogfood/keeper/impl_operator_hooks.go | 42 +++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/x/dogfood/keeper/impl_operator_hooks.go b/x/dogfood/keeper/impl_operator_hooks.go index e5a42d615..9e0c22af2 100644 --- a/x/dogfood/keeper/impl_operator_hooks.go +++ b/x/dogfood/keeper/impl_operator_hooks.go @@ -32,13 +32,51 @@ func (k *Keeper) OperatorHooks() OperatorHooksWrapper { // R I // For an operator that is already opted in, the list looks like follows: // R O -// O I +// O I (reversing the decision to opt out) // O I R // R O I // The impossible list looks like: // O R // O R I -// TODO: list out operation results for each of these, and make sure everything is covered below +// Replacing the key with the same key is not possible, so it is not covered. +// The assumption is that these are enforced (allowed/denied) by the operator module. + +// Cases for a fresh operator: +// I + O => KeyAdditionOrUpdate + KeyRemoval => Success + Removed => covered. +// I + R => KeyAdditionOrUpdate (old) + KeyAdditionOrUpdate (new) + KeyRemoval (old) => +// Success + Success + Removed + => not considered unbonding of the old key since it +// was not yet effective => covered. +// I + R + O => KeyAdditionOrUpdate (old) + KeyAdditionOrUpdate (new) + KeyRemoval (old) + +// KeyRemoval (new) => +// Success (old) + Success (new) + Removed (old) + Removed (new) => covered + +// Cases for an operator that has already opted in: +// R + O => KeyAdditionOrUpdate (new) + KeyRemoval (old) + KeyRemoval (new) => +// Success (new) + Success (old) + Removed (new) => +// unbonding data made (old) => covered. +// O + I +// O + I case 1 => KeyRemoval (old) + KeyAdditionOrUpdate (new) => Success (old) + Success (new) +// => unbonding data made (old) => covered. +// O + I case 2 => KeyRemoval (old) + KeyAdditionOrUpdate (old) => Success (old) + Removed (old) +// => unbonding data made (old) and then cleared => covered. +// O + I + R +// O + I + R case 1 => KeyRemoval (old) + KeyAdditionOrUpdate (old) + KeyRemoval (old) + +// KeyAdditionOrUpdate (new) => Success (old) + Removed (old) + Success (old) + +// Success (new) => unbonding data old made + cleared + made => covered. +// O + I + R case 2 => +// AfterOperatorOptOut(old) => Success => unbonding data made for old +// AfterOperatorOptIn(new) => Success => no data changed +// AfterOperatorKeyReplacement(new, new2) => +// new2 operation KeyAdditionOrUpdate => Success => no data changed +// new operation KeyRemoval => Removed => no data changed +// => covered +// R + O + I => KeyAdditionOrUpdate (new) + KeyRemoval (old) + KeyRemoval (new) + +// KeyAdditionOrUpdate (X) +// Success + Success (=> unbonding data for old) + Removed (=> no data) + +// case 1 => X == new => Success => no change => covered +// case 2 => X == old => Removed => unbonding data for old removed => covered. +// case 3 => X == abc => Success => no change and unbonding data for old is not removed => +// covered. // AfterOperatorOptIn is the implementation of the operator hooks. func (h OperatorHooksWrapper) AfterOperatorOptIn( From 50d098daa4d994055905149d63c4d85e7787a5c3 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:14:29 +0000 Subject: [PATCH 11/32] feat(dogfood): implement delegation hooks Whenever a delegation or undelegation event happens in the delegation module, the hooks are called. For both of these events, as long as the operator is not in the process of opting out from the chain, consensus key operations are queued to be applied at the end of the current epoch. For undelegation, specifically, the `recordKey` identifier of the undelegation is used to mark within the delegation module that the undelegation should be held until released at some point in the future (as opposed to releasing it after a fixed number of blocks, which is the default behaviour). This point in the future is calculated as the earlier of the unbonding period end, or the operator's opt out period end (if the operator is opting out). --- proto/exocore/dogfood/v1/dogfood.proto | 7 + x/dogfood/keeper/impl_delegation_hooks.go | 126 +++++++++++++ x/dogfood/keeper/keeper.go | 18 +- x/dogfood/keeper/unbonding.go | 55 ++++++ x/dogfood/types/dogfood.pb.go | 219 +++++++++++++++++++--- x/dogfood/types/expected_keepers.go | 23 +++ x/dogfood/types/keys.go | 12 ++ 7 files changed, 434 insertions(+), 26 deletions(-) create mode 100644 x/dogfood/keeper/impl_delegation_hooks.go diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index 1259ac803..a27fc45e6 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -79,4 +79,11 @@ message AccountAddresses { // addresses (which correspond to operator public keys) to delete at the end of an epoch. message ConsensusAddresses { repeated bytes list = 1; +} + +// RecordKeys is a collection of record keys. This is used to store a list of +// undelegation records to mature in the delegation module at the end of the +// epoch. +message RecordKeys { + repeated bytes list = 1; } \ No newline at end of file diff --git a/x/dogfood/keeper/impl_delegation_hooks.go b/x/dogfood/keeper/impl_delegation_hooks.go new file mode 100644 index 000000000..21a8da737 --- /dev/null +++ b/x/dogfood/keeper/impl_delegation_hooks.go @@ -0,0 +1,126 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// DelegationHooksWrapper is the wrapper structure that implements the delegation hooks for the +// dogfood keeper. +type DelegationHooksWrapper struct { + keeper *Keeper +} + +// Interface guard +var _ types.DelegationHooks = DelegationHooksWrapper{} + +// DelegationHooks returns the delegation hooks wrapper. It follows the "accept interfaces, +// return concretes" pattern. +func (k *Keeper) DelegationHooks() DelegationHooksWrapper { + return DelegationHooksWrapper{k} +} + +// AfterDelegation is called after a delegation is made. +func (wrapper DelegationHooksWrapper) AfterDelegation( + ctx sdk.Context, operator sdk.AccAddress, +) { + found, pubKey, err := wrapper.keeper.operatorKeeper.GetOperatorConsKeyForChainId( + ctx, operator, ctx.ChainID(), + ) + if err != nil { + // the operator keeper can offer two errors: not an operator and not a chain. + // both of these should not happen here because the dogfooding genesis will + // register the chain, and the operator must be known to the delegation module + // when it calls this hook. + panic(err) + } + if found { + if !wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( + ctx, operator, ctx.ChainID(), + ) { + // only queue the operation if operator is still opted into the chain. + res := wrapper.keeper.QueueOperation( + ctx, operator, pubKey, types.KeyAdditionOrUpdate, + ) + switch res { + case types.QueueResultExists: + // nothing to do because the operation is in the queue already. + case types.QueueResultRemoved: + // a KeyRemoval was in the queue which has now been cleared from the queue. + // the KeyRemoval can only be in the queue if the operator is opting out from + // the chain, or has replaced their key. if it is the former, it means that + // there is some inconsistency. if it is the latter, it means that the operator + // module just reported the old key in `GetOperatorConsKeyForChainId`, which + // should not happen. + panic("unexpected removal of operation from queue") + case types.QueueResultSuccess: + // best case, nothing to do. + case types.QueueResultUnspecified: + panic("unspecified queue result") + } + } + } +} + +// AfterUndelegationStarted is called after an undelegation is started. +func (wrapper DelegationHooksWrapper) AfterUndelegationStarted( + ctx sdk.Context, operator sdk.AccAddress, recordKey []byte, +) { + found, pubKey, err := wrapper.keeper.operatorKeeper.GetOperatorConsKeyForChainId( + ctx, operator, ctx.ChainID(), + ) + if err != nil { + panic(err) + } + if found { + // note that this is still key addition or update because undelegation does not remove + // the operator from the list. it only decreases their vote power. + if !wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( + ctx, operator, ctx.ChainID(), + ) { + // only queue the operation if operator is still opted into the chain. + res := wrapper.keeper.QueueOperation( + ctx, operator, pubKey, types.KeyAdditionOrUpdate, + ) + switch res { + case types.QueueResultExists: + // nothing to do + case types.QueueResultRemoved: + // KeyRemoval + KeyAdditionOrUpdate => Removed + // KeyRemoval can happen + // 1. if the operator is opting out from the chain,which is inconsistent. + // 2. if the operator is replacing their old key, which should not be returned + // by `GetOperatorConsKeyForChainId`. + panic("unexpected removal of operation from queue") + case types.QueueResultSuccess: + // best case, nothing to do. + case types.QueueResultUnspecified: + panic("unspecified queue result") + } + } + // now handle the unbonding timeline. + wrapper.keeper.delegationKeeper.IncrementUndelegationHoldCount(ctx, recordKey) + // mark for unbonding release. + // note that we aren't supporting redelegation yet, so this undelegated amount will be + // held until the end of the unbonding period or the operator opt out period, whichever + // is first. + var unbondingCompletionEpoch int64 + if wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( + ctx, operator, ctx.ChainID(), + ) { + unbondingCompletionEpoch = wrapper.keeper.GetOperatorOptOutFinishEpoch( + ctx, operator, + ) + } else { + unbondingCompletionEpoch = wrapper.keeper.GetUnbondingCompletionEpoch(ctx) + } + wrapper.keeper.AppendUndelegationToMature(ctx, unbondingCompletionEpoch, recordKey) + } +} + +// AfterUndelegationCompleted is called after an undelegation is completed. +func (DelegationHooksWrapper) AfterUndelegationCompleted( + sdk.Context, sdk.AccAddress, +) { + // no-op +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index 47e766553..8061edd8b 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -18,9 +18,13 @@ type ( storeKey storetypes.StoreKey paramstore paramtypes.Subspace + // internal hooks to allow other modules to subscriber to our events dogfoodHooks types.DogfoodHooks - epochsKeeper types.EpochsKeeper + // external keepers as interfaces + epochsKeeper types.EpochsKeeper + operatorKeeper types.OperatorKeeper + delegationKeeper types.DelegationKeeper } ) @@ -30,6 +34,8 @@ func NewKeeper( storeKey storetypes.StoreKey, ps paramtypes.Subspace, epochsKeeper types.EpochsKeeper, + operatorKeeper types.OperatorKeeper, + delegationKeeper types.DelegationKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -37,10 +43,12 @@ func NewKeeper( } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, - epochsKeeper: epochsKeeper, + cdc: cdc, + storeKey: storeKey, + paramstore: ps, + epochsKeeper: epochsKeeper, + operatorKeeper: operatorKeeper, + delegationKeeper: delegationKeeper, } } diff --git a/x/dogfood/keeper/unbonding.go b/x/dogfood/keeper/unbonding.go index 4987e523a..a973754c5 100644 --- a/x/dogfood/keeper/unbonding.go +++ b/x/dogfood/keeper/unbonding.go @@ -56,3 +56,58 @@ func (k Keeper) GetUnbondingCompletionEpoch( // beginning of epoch 13 or the end of epoch 12. return epochInfo.CurrentEpoch + int64(unbondingEpochs) } + +// AppendUndelegationsToMature stores that the undelegation with recordKey should be +// released at the end of the provided epoch. +func (k Keeper) AppendUndelegationToMature( + ctx sdk.Context, epoch int64, recordKey []byte, +) { + prev := k.GetUndelegationsToMature(ctx, epoch) + next := types.RecordKeys{ + List: append(prev, recordKey), + } + k.setUndelegationsToMature(ctx, epoch, next) +} + +// GetUndelegationsToMature returns all undelegation entries that should be released +// at the end of the provided epoch. +func (k Keeper) GetUndelegationsToMature( + ctx sdk.Context, epoch int64, +) [][]byte { + store := ctx.KVStore(k.storeKey) + key := types.UnbondingReleaseMaturityKey(epoch) + bz := store.Get(key) + if bz == nil { + return [][]byte{} + } + var res types.RecordKeys + if err := res.Unmarshal(bz); err != nil { + // should never happen + panic(err) + } + return res.GetList() +} + +// ClearUndelegationsToMature is a pruning method which is called after we mature +// the undelegation entries. +func (k Keeper) ClearUndelegationsToMature( + ctx sdk.Context, epoch int64, +) { + store := ctx.KVStore(k.storeKey) + key := types.UnbondingReleaseMaturityKey(epoch) + store.Delete(key) +} + +// setUndelegationsToMature sets all undelegation entries that should be released +// at the end of the provided epoch. +func (k Keeper) setUndelegationsToMature( + ctx sdk.Context, epoch int64, recordKeys types.RecordKeys, +) { + store := ctx.KVStore(k.storeKey) + key := types.UnbondingReleaseMaturityKey(epoch) + val, err := recordKeys.Marshal() + if err != nil { + panic(err) + } + store.Set(key, val) +} diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index 3a64b1dea..fa4d626f1 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -367,6 +367,53 @@ func (m *ConsensusAddresses) GetList() [][]byte { return nil } +// RecordKeys is a collection of record keys. This is used to store a list of +// undelegation records to mature in the delegation module at the end of the +// epoch. +type RecordKeys struct { + List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` +} + +func (m *RecordKeys) Reset() { *m = RecordKeys{} } +func (m *RecordKeys) String() string { return proto.CompactTextString(m) } +func (*RecordKeys) ProtoMessage() {} +func (*RecordKeys) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{5} +} +func (m *RecordKeys) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RecordKeys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RecordKeys.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 *RecordKeys) XXX_Merge(src proto.Message) { + xxx_messageInfo_RecordKeys.Merge(m, src) +} +func (m *RecordKeys) XXX_Size() int { + return m.Size() +} +func (m *RecordKeys) XXX_DiscardUnknown() { + xxx_messageInfo_RecordKeys.DiscardUnknown(m) +} + +var xxx_messageInfo_RecordKeys proto.InternalMessageInfo + +func (m *RecordKeys) GetList() [][]byte { + if m != nil { + return m.List + } + return nil +} + func init() { proto.RegisterEnum("exocore.dogfood.v1.OperationType", OperationType_name, OperationType_value) proto.RegisterEnum("exocore.dogfood.v1.QueueResultType", QueueResultType_name, QueueResultType_value) @@ -375,12 +422,13 @@ func init() { proto.RegisterType((*Operations)(nil), "exocore.dogfood.v1.Operations") proto.RegisterType((*AccountAddresses)(nil), "exocore.dogfood.v1.AccountAddresses") proto.RegisterType((*ConsensusAddresses)(nil), "exocore.dogfood.v1.ConsensusAddresses") + proto.RegisterType((*RecordKeys)(nil), "exocore.dogfood.v1.RecordKeys") } func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } var fileDescriptor_071b9989c501c3f2 = []byte{ - // 705 bytes of a gzipped FileDescriptorProto + // 715 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x94, 0xcf, 0x4e, 0xdb, 0x4a, 0x14, 0xc6, 0xe3, 0x84, 0x0b, 0xba, 0xc3, 0x3f, 0xdf, 0xb9, 0x29, 0x04, 0x0b, 0x82, 0xc9, 0xa2, 0x4a, 0x91, 0x6a, 0x0b, 0x68, 0x55, 0xa9, 0x55, 0x2b, 0x99, 0xc4, 0x55, 0xa3, 0x50, 0x12, 0xec, @@ -406,26 +454,26 @@ var fileDescriptor_071b9989c501c3f2 = []byte{ 0xda, 0x66, 0x1d, 0xc2, 0xed, 0x89, 0xd3, 0xf3, 0xd5, 0x4c, 0xc4, 0x5f, 0x87, 0xb0, 0x24, 0x23, 0x74, 0xc5, 0x41, 0xf1, 0x13, 0x34, 0xd1, 0xb5, 0xa9, 0x5f, 0x60, 0xf8, 0x5c, 0x79, 0x7a, 0x73, 0xe5, 0x4e, 0xea, 0x64, 0xa3, 0xc8, 0x50, 0xba, 0x8f, 0x58, 0xc9, 0x34, 0x49, 0xe0, 0xf8, 0x09, - 0x15, 0x50, 0x8c, 0x47, 0x36, 0x9b, 0x49, 0xfa, 0xca, 0x08, 0x57, 0xd2, 0x19, 0xdf, 0xd9, 0xb9, - 0xfe, 0x95, 0x41, 0xb3, 0x7f, 0x4d, 0x08, 0x3f, 0x42, 0x5c, 0xa3, 0x29, 0x2b, 0x52, 0xab, 0xd6, - 0xd8, 0xd5, 0x5b, 0x6f, 0x9b, 0xb2, 0xae, 0xed, 0xaa, 0x4d, 0xb9, 0x52, 0x7b, 0x59, 0x93, 0xab, - 0x6c, 0x86, 0xcb, 0xf7, 0x07, 0x3c, 0x5b, 0x87, 0xb0, 0xe1, 0x6a, 0x0e, 0x75, 0xc1, 0xb4, 0x0f, - 0x6c, 0xb0, 0xf0, 0x0b, 0xb4, 0x76, 0xc3, 0x25, 0x55, 0xab, 0xb5, 0x48, 0x35, 0x14, 0x5d, 0x6b, - 0x56, 0xa5, 0x96, 0xcc, 0x32, 0xdc, 0x62, 0x7f, 0xc0, 0xff, 0x5f, 0x87, 0x50, 0xb2, 0x2c, 0x7b, - 0x78, 0x62, 0xc3, 0xd3, 0x5c, 0xcb, 0xf0, 0x01, 0xaf, 0xa3, 0x85, 0x1b, 0x7e, 0x45, 0x7e, 0xdd, - 0xd8, 0x97, 0x76, 0xd8, 0x2c, 0x37, 0xd7, 0x1f, 0xf0, 0x68, 0xf8, 0x37, 0x40, 0x8f, 0x1c, 0x19, - 0x5d, 0x6e, 0xe2, 0xc3, 0xa7, 0x62, 0x66, 0xfd, 0x37, 0x83, 0xe6, 0xf7, 0x02, 0x08, 0x40, 0x01, - 0x1a, 0x74, 0xfd, 0x88, 0xfd, 0x39, 0x5a, 0xd9, 0xd3, 0x64, 0x6d, 0x68, 0x56, 0xb5, 0x9d, 0xd6, - 0x6d, 0xf8, 0x5c, 0x7f, 0xc0, 0x2f, 0x8c, 0xf8, 0x46, 0x43, 0x3c, 0x46, 0x4b, 0xe3, 0x76, 0x55, - 0xab, 0x54, 0x64, 0x55, 0x65, 0x19, 0x6e, 0xa1, 0x3f, 0xe0, 0xf1, 0x88, 0x55, 0x0d, 0x4c, 0x73, - 0xf8, 0x67, 0x6c, 0xa1, 0xc2, 0xb8, 0x4d, 0x7e, 0x53, 0x53, 0x5b, 0x2a, 0x9b, 0xe5, 0xee, 0xf5, - 0x07, 0xfc, 0x7f, 0x23, 0x2e, 0xf9, 0xc4, 0xa6, 0x3e, 0xbd, 0xfd, 0xac, 0x28, 0xb3, 0x5c, 0x65, - 0x73, 0x63, 0x67, 0x45, 0xd9, 0xc1, 0x8a, 0xb3, 0x6f, 0xd7, 0x4f, 0x2f, 0x8a, 0xcc, 0xd9, 0x45, - 0x91, 0xf9, 0x79, 0x51, 0x64, 0x3e, 0x5e, 0x16, 0x33, 0x67, 0x97, 0xc5, 0xcc, 0x8f, 0xcb, 0x62, - 0xe6, 0xdd, 0x46, 0xc7, 0xf6, 0xdf, 0x07, 0x6d, 0xc1, 0x24, 0x3d, 0x31, 0xb9, 0xd8, 0xbb, 0xe0, - 0x1f, 0x13, 0xef, 0x50, 0x4c, 0x9f, 0xa2, 0x93, 0xab, 0xc7, 0x68, 0x78, 0x75, 0x68, 0x7b, 0x32, - 0xba, 0xa6, 0x5b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xf3, 0x23, 0x11, 0xac, 0x04, 0x00, - 0x00, + 0x15, 0x50, 0x8c, 0x47, 0x36, 0x9b, 0x49, 0xfa, 0xca, 0x08, 0x57, 0xd2, 0x19, 0xdf, 0xdd, 0xc9, + 0x23, 0xa4, 0x80, 0x49, 0x3c, 0xab, 0x0e, 0xe1, 0xad, 0x1d, 0xeb, 0x5f, 0x19, 0x34, 0xfb, 0xd7, + 0x0c, 0xf1, 0x23, 0xc4, 0x35, 0x9a, 0xb2, 0x22, 0xb5, 0x6a, 0x8d, 0x5d, 0xbd, 0xf5, 0xb6, 0x29, + 0xeb, 0xda, 0xae, 0xda, 0x94, 0x2b, 0xb5, 0x97, 0x35, 0xb9, 0xca, 0x66, 0xb8, 0x7c, 0x7f, 0xc0, + 0xb3, 0x75, 0x08, 0x1b, 0xae, 0xe6, 0x50, 0x17, 0x4c, 0xfb, 0xc0, 0x06, 0x0b, 0xbf, 0x40, 0x6b, + 0x37, 0x5c, 0x52, 0xb5, 0x5a, 0x8b, 0x54, 0x43, 0xd1, 0xb5, 0x66, 0x55, 0x6a, 0xc9, 0x2c, 0xc3, + 0x2d, 0xf6, 0x07, 0xfc, 0xff, 0x75, 0x08, 0x25, 0xcb, 0xb2, 0x87, 0x27, 0x36, 0x3c, 0xcd, 0xb5, + 0x0c, 0x1f, 0xf0, 0x3a, 0x5a, 0xb8, 0xe1, 0x57, 0xe4, 0xd7, 0x8d, 0x7d, 0x69, 0x87, 0xcd, 0x72, + 0x73, 0xfd, 0x01, 0x8f, 0x86, 0xff, 0x0b, 0xf4, 0xc8, 0x91, 0xd1, 0xe5, 0x26, 0x3e, 0x7c, 0x2a, + 0x66, 0xd6, 0x7f, 0x33, 0x68, 0x7e, 0x2f, 0x80, 0x00, 0x14, 0xa0, 0x41, 0xd7, 0x8f, 0xd8, 0x9f, + 0xa3, 0x95, 0x3d, 0x4d, 0xd6, 0x86, 0x66, 0x55, 0xdb, 0x69, 0xdd, 0x86, 0xcf, 0xf5, 0x07, 0xfc, + 0xc2, 0x88, 0x6f, 0x34, 0xc4, 0x63, 0xb4, 0x34, 0x6e, 0x57, 0xb5, 0x4a, 0x45, 0x56, 0x55, 0x96, + 0xe1, 0x16, 0xfa, 0x03, 0x1e, 0x8f, 0x58, 0xd5, 0xc0, 0x34, 0x87, 0xff, 0xce, 0x16, 0x2a, 0x8c, + 0xdb, 0xe4, 0x37, 0x35, 0xb5, 0xa5, 0xb2, 0x59, 0xee, 0x5e, 0x7f, 0xc0, 0xff, 0x37, 0xe2, 0x92, + 0x4f, 0x6c, 0xea, 0xd3, 0xdb, 0xcf, 0x8a, 0x32, 0xcb, 0x55, 0x36, 0x37, 0x76, 0x56, 0x94, 0x1d, + 0xac, 0x38, 0xfb, 0x76, 0xfd, 0xf4, 0xa2, 0xc8, 0x9c, 0x5d, 0x14, 0x99, 0x9f, 0x17, 0x45, 0xe6, + 0xe3, 0x65, 0x31, 0x73, 0x76, 0x59, 0xcc, 0xfc, 0xb8, 0x2c, 0x66, 0xde, 0x6d, 0x74, 0x6c, 0xff, + 0x7d, 0xd0, 0x16, 0x4c, 0xd2, 0x13, 0x93, 0xab, 0xbf, 0x0b, 0xfe, 0x31, 0xf1, 0x0e, 0xc5, 0xf4, + 0xb1, 0x3a, 0xb9, 0x7a, 0xae, 0x86, 0x97, 0x8b, 0xb6, 0x27, 0xa3, 0x8b, 0xbc, 0xf5, 0x27, 0x00, + 0x00, 0xff, 0xff, 0xbd, 0x64, 0x30, 0xab, 0xce, 0x04, 0x00, 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { @@ -621,6 +669,38 @@ func (m *ConsensusAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *RecordKeys) 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 *RecordKeys) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RecordKeys) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.List[iNdEx]) + copy(dAtA[i:], m.List[iNdEx]) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.List[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintDogfood(dAtA []byte, offset int, v uint64) int { offset -= sovDogfood(v) base := offset @@ -715,6 +795,21 @@ func (m *ConsensusAddresses) Size() (n int) { return n } +func (m *RecordKeys) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, b := range m.List { + l = len(b) + n += 1 + l + sovDogfood(uint64(l)) + } + } + return n +} + func sovDogfood(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1244,6 +1339,88 @@ func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { } return nil } +func (m *RecordKeys) 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 ErrIntOverflowDogfood + } + 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: RecordKeys: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RecordKeys: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, make([]byte, postIndex-iNdEx)) + copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipDogfood(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index 1880294b6..585c28b38 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -30,3 +30,26 @@ type OperatorHooks interface { ) AfterOperatorOptOutInitiated(sdk.Context, sdk.AccAddress, string, tmprotocrypto.PublicKey) } + +// DelegationHooks represent the event hooks for delegation module. +type DelegationHooks interface { + AfterDelegation(sdk.Context, sdk.AccAddress) + AfterUndelegationStarted(sdk.Context, sdk.AccAddress, []byte) + AfterUndelegationCompleted(sdk.Context, sdk.AccAddress) +} + +// OperatorKeeper represents the expected keeper interface for the operator module. +type OperatorKeeper interface { + GetOperatorConsKeyForChainId( + sdk.Context, sdk.AccAddress, string, + ) (bool, tmprotocrypto.PublicKey, error) + IsOperatorOptingOutFromChainId( + sdk.Context, sdk.AccAddress, string, + ) bool +} + +// DelegationKeeper represents the expected keeper interface for the delegation module. +type DelegationKeeper interface { + IncrementUndelegationHoldCount(sdk.Context, []byte) + DecrementUndelegationHoldCount(sdk.Context, []byte) +} diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index b0b823c05..e7e0e4aab 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -33,6 +33,10 @@ const ( // ConsensusAddrsToPruneBytePrefix is the byte prefix to store the list of consensus // addresses that can be pruned from the operator module at the provided epoch. ConsensusAddrsToPruneBytePrefix + + // UnbondingReleaseMaturityBytePrefix is the byte prefix to store the list of undelegations + // that will mature at the provided epoch. + UnbondingReleaseMaturityBytePrefix ) // ExocoreValidatorKey returns the key for the validator store. @@ -70,3 +74,11 @@ func ConsensusAddrsToPruneKey(epoch int64) []byte { []byte{ConsensusAddrsToPruneBytePrefix}, sdk.Uint64ToBigEndian(uint64(epoch))...) } + +// UnbondingReleaseMaturityKey is the key to lookup the list of undelegations that will mature +// at the provided epoch. +func UnbondingReleaseMaturityKey(epoch int64) []byte { + return append( + []byte{UnbondingReleaseMaturityBytePrefix}, + sdk.Uint64ToBigEndian(uint64(epoch))...) +} From ebc853022aec2b2c83ce09b94f89a9a50d78784c Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:18:50 +0000 Subject: [PATCH 12/32] fix(dogfood): upd delegation hook interface --- x/dogfood/keeper/impl_delegation_hooks.go | 2 +- x/dogfood/types/expected_keepers.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x/dogfood/keeper/impl_delegation_hooks.go b/x/dogfood/keeper/impl_delegation_hooks.go index 21a8da737..e32442853 100644 --- a/x/dogfood/keeper/impl_delegation_hooks.go +++ b/x/dogfood/keeper/impl_delegation_hooks.go @@ -120,7 +120,7 @@ func (wrapper DelegationHooksWrapper) AfterUndelegationStarted( // AfterUndelegationCompleted is called after an undelegation is completed. func (DelegationHooksWrapper) AfterUndelegationCompleted( - sdk.Context, sdk.AccAddress, + sdk.Context, sdk.AccAddress, []byte, ) { // no-op } diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index 585c28b38..f6d85f8c6 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -35,7 +35,7 @@ type OperatorHooks interface { type DelegationHooks interface { AfterDelegation(sdk.Context, sdk.AccAddress) AfterUndelegationStarted(sdk.Context, sdk.AccAddress, []byte) - AfterUndelegationCompleted(sdk.Context, sdk.AccAddress) + AfterUndelegationCompleted(sdk.Context, sdk.AccAddress, []byte) } // OperatorKeeper represents the expected keeper interface for the operator module. From 5d0a0cd4ebd94b92e3b9bb1f5f65ac8852116aac Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:50:24 +0000 Subject: [PATCH 13/32] feat(dogfood): implement epochs hooks + end block The epochs hooks are used by the dogfood module to subscribe to the start and end times of epochs. After an epoch ends, the operations that are currently in the queue are upgraded to "pending", which are applied at the end of the block. The upgrades are also made to undelegation maturity, operator opt out, and operator key replacement data. Once the pending actions are applied, they are cleared from the queue. This branch is merged into dogfood-part5, which forms the basis of #121. --- x/dogfood/keeper/abci.go | 182 ++++++++++++++++++++++++++ x/dogfood/keeper/impl_epochs_hooks.go | 61 +++++++++ x/dogfood/keeper/keeper.go | 3 + x/dogfood/types/expected_keepers.go | 13 ++ x/dogfood/types/keys.go | 37 ++++++ 5 files changed, 296 insertions(+) create mode 100644 x/dogfood/keeper/abci.go create mode 100644 x/dogfood/keeper/impl_epochs_hooks.go diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go new file mode 100644 index 000000000..043045680 --- /dev/null +++ b/x/dogfood/keeper/abci.go @@ -0,0 +1,182 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { + // start with undelegations + undelegations := k.GetPendingUndelegations(ctx) + for _, undelegation := range undelegations.GetList() { + k.delegationKeeper.DecrementUndelegationHoldCount(ctx, undelegation) + } + k.ClearPendingUndelegations(ctx) + // then opt outs (consensus addresses should be done after opt out) + optOuts := k.GetPendingOptOuts(ctx) + for _, addr := range optOuts.GetList() { + k.operatorKeeper.CompleteOperatorOptOutFromChainId(ctx, addr, ctx.ChainID()) + } + k.ClearPendingOptOuts(ctx) + // then consensus addresses + consensusAddrs := k.GetPendingConsensusAddrs(ctx) + for _, consensusAddr := range consensusAddrs.GetList() { + k.operatorKeeper.DeleteOperatorAddressForChainIdAndConsAddr( + ctx, ctx.ChainID(), consensusAddr, + ) + } + k.ClearPendingConsensusAddrs(ctx) + // finally, operations + operations := k.GetPendingOperations(ctx) + res := make([]abci.ValidatorUpdate, 0, len(operations.GetList())) + for _, operation := range operations.GetList() { + switch operation.OperationType { + case types.KeyAdditionOrUpdate: + power, err := k.restakingKeeper.GetOperatorAssetValue( + ctx, operation.OperatorAddress, + ) + if err != nil { + panic(err) + } + res = append(res, abci.ValidatorUpdate{ + PubKey: operation.PubKey, + Power: power, + }) + case types.KeyRemoval: + res = append(res, abci.ValidatorUpdate{ + PubKey: operation.PubKey, + Power: 0, + }) + case types.KeyOpUnspecified: + panic("unspecified operation type") + } + } + return res +} + +// SetPendingOperations sets the pending operations to be applied at the end of the block. +func (k Keeper) SetPendingOperations(ctx sdk.Context, operations types.Operations) { + store := ctx.KVStore(k.storeKey) + bz, err := operations.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingOperationsKey(), bz) +} + +// GetPendingOperations returns the pending operations to be applied at the end of the block. +func (k Keeper) GetPendingOperations(ctx sdk.Context) types.Operations { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingOperationsKey()) + if bz == nil { + return types.Operations{} + } + var operations types.Operations + if err := operations.Unmarshal(bz); err != nil { + panic(err) + } + return operations +} + +// ClearPendingOperations clears the pending operations to be applied at the end of the block. +func (k Keeper) ClearPendingOperations(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingOperationsKey()) +} + +// SetPendingOptOuts sets the pending opt-outs to be applied at the end of the block. +func (k Keeper) SetPendingOptOuts(ctx sdk.Context, addrs types.AccountAddresses) { + store := ctx.KVStore(k.storeKey) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingOptOutsKey(), bz) +} + +// GetPendingOptOuts returns the pending opt-outs to be applied at the end of the block. +func (k Keeper) GetPendingOptOuts(ctx sdk.Context) types.AccountAddresses { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingOptOutsKey()) + if bz == nil { + return types.AccountAddresses{} + } + var addrs types.AccountAddresses + if err := addrs.Unmarshal(bz); err != nil { + panic(err) + } + return addrs +} + +// ClearPendingOptOuts clears the pending opt-outs to be applied at the end of the block. +func (k Keeper) ClearPendingOptOuts(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingOptOutsKey()) +} + +// SetPendingConsensusAddrs sets the pending consensus addresses to be pruned at the end of the +// block. +func (k Keeper) SetPendingConsensusAddrs(ctx sdk.Context, addrs types.ConsensusAddresses) { + store := ctx.KVStore(k.storeKey) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingConsensusAddrsKey(), bz) +} + +// GetPendingConsensusAddrs returns the pending consensus addresses to be pruned at the end of +// the block. +func (k Keeper) GetPendingConsensusAddrs(ctx sdk.Context) types.ConsensusAddresses { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingConsensusAddrsKey()) + if bz == nil { + return types.ConsensusAddresses{} + } + var addrs types.ConsensusAddresses + if err := addrs.Unmarshal(bz); err != nil { + panic(err) + } + return addrs +} + +// ClearPendingConsensusAddrs clears the pending consensus addresses to be pruned at the end of +// the block. +func (k Keeper) ClearPendingConsensusAddrs(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingConsensusAddrsKey()) +} + +// SetPendingUndelegations sets the pending undelegations to be released at the end of the +// block. +func (k Keeper) SetPendingUndelegations(ctx sdk.Context, undelegations types.RecordKeys) { + store := ctx.KVStore(k.storeKey) + bz, err := undelegations.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingUndelegationsKey(), bz) +} + +// GetPendingUndelegations returns the pending undelegations to be released at the end of the +// block. +func (k Keeper) GetPendingUndelegations(ctx sdk.Context) types.RecordKeys { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingUndelegationsKey()) + if bz == nil { + return types.RecordKeys{} + } + var undelegations types.RecordKeys + if err := undelegations.Unmarshal(bz); err != nil { + panic(err) + } + return undelegations +} + +// ClearPendingUndelegations clears the pending undelegations to be released at the end of the +// block. +func (k Keeper) ClearPendingUndelegations(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingUndelegationsKey()) +} diff --git a/x/dogfood/keeper/impl_epochs_hooks.go b/x/dogfood/keeper/impl_epochs_hooks.go new file mode 100644 index 000000000..c68604316 --- /dev/null +++ b/x/dogfood/keeper/impl_epochs_hooks.go @@ -0,0 +1,61 @@ +package keeper + +import ( + "strings" + + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var ( + _ = sdk.NewCoin("stake", sdk.NewInt(1)) +) + +// EpochsHooksWrapper is the wrapper structure that implements the epochs hooks for the dogfood +// keeper. +type EpochsHooksWrapper struct { + keeper *Keeper +} + +// Interface guard +var _ types.EpochsHooks = EpochsHooksWrapper{} + +// EpochsHooks returns the epochs hooks wrapper. It follows the "accept interfaces, return +// concretes" pattern. +func (k *Keeper) EpochsHooks() EpochsHooksWrapper { + return EpochsHooksWrapper{k} +} + +// AfterEpochEnd is called after an epoch ends. +func (wrapper EpochsHooksWrapper) AfterEpochEnd( + ctx sdk.Context, identifier string, epoch int64, +) { + if strings.Compare(identifier, wrapper.keeper.GetEpochIdentifier(ctx)) == 0 { + // we will upgrade all of the queued information to "pending", which will be applied at + // the end of the block. + // note that this hook is called during BeginBlock, and the "pending" operations will be + // applied within this block. however, for clarity, it is highlighted that unbonding + // takes N epochs + 1 block to complete. + operations := wrapper.keeper.GetQueuedOperations(ctx) + wrapper.keeper.SetPendingOperations(ctx, types.Operations{List: operations}) + wrapper.keeper.ClearQueuedOperations(ctx) + optOuts := wrapper.keeper.GetOptOutsToFinish(ctx, epoch) + wrapper.keeper.SetPendingOptOuts(ctx, types.AccountAddresses{List: optOuts}) + wrapper.keeper.ClearOptOutsToFinish(ctx, epoch) + consAddresses := wrapper.keeper.GetConsensusAddrsToPrune(ctx, epoch) + wrapper.keeper.SetPendingConsensusAddrs( + ctx, types.ConsensusAddresses{List: consAddresses}, + ) + wrapper.keeper.ClearConsensusAddrsToPrune(ctx, epoch) + undelegations := wrapper.keeper.GetUndelegationsToMature(ctx, epoch) + wrapper.keeper.SetPendingUndelegations(ctx, types.RecordKeys{List: undelegations}) + wrapper.keeper.ClearUndelegationsToMature(ctx, epoch) + } +} + +// BeforeEpochStart is called before an epoch starts. +func (wrapper EpochsHooksWrapper) BeforeEpochStart( + ctx sdk.Context, identifier string, epoch int64, +) { + // nothing to do +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index 8061edd8b..103d60c97 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -25,6 +25,7 @@ type ( epochsKeeper types.EpochsKeeper operatorKeeper types.OperatorKeeper delegationKeeper types.DelegationKeeper + restakingKeeper types.RestakingKeeper } ) @@ -36,6 +37,7 @@ func NewKeeper( epochsKeeper types.EpochsKeeper, operatorKeeper types.OperatorKeeper, delegationKeeper types.DelegationKeeper, + restakingKeeper types.RestakingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -49,6 +51,7 @@ func NewKeeper( epochsKeeper: epochsKeeper, operatorKeeper: operatorKeeper, delegationKeeper: delegationKeeper, + restakingKeeper: restakingKeeper, } } diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index f6d85f8c6..9dfd255ea 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -46,6 +46,8 @@ type OperatorKeeper interface { IsOperatorOptingOutFromChainId( sdk.Context, sdk.AccAddress, string, ) bool + CompleteOperatorOptOutFromChainId(sdk.Context, sdk.AccAddress, string) + DeleteOperatorAddressForChainIdAndConsAddr(sdk.Context, string, sdk.ConsAddress) } // DelegationKeeper represents the expected keeper interface for the delegation module. @@ -53,3 +55,14 @@ type DelegationKeeper interface { IncrementUndelegationHoldCount(sdk.Context, []byte) DecrementUndelegationHoldCount(sdk.Context, []byte) } + +// EpochsHooks represents the event hooks for the epochs module. +type EpochsHooks interface { + AfterEpochEnd(sdk.Context, string, int64) + BeforeEpochStart(sdk.Context, string, int64) +} + +// RestakingKeeper represents the expected keeper interface for the restaking module. +type RestakingKeeper interface { + GetOperatorAssetValue(sdk.Context, sdk.AccAddress) (int64, error) +} diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index e7e0e4aab..40aa58676 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -37,6 +37,22 @@ const ( // UnbondingReleaseMaturityBytePrefix is the byte prefix to store the list of undelegations // that will mature at the provided epoch. UnbondingReleaseMaturityBytePrefix + + // PendingOperationsByte is the byte used to store the list of operations to be applied at + // the end of the current block. + PendingOperationsByte + + // PendingOptOutsByte is the byte used to store the list of operator addresses whose opt + // outs will be made effective at the end of the current block. + PendingOptOutsByte + + // PendingConsensusAddrsByte is the byte used to store the list of consensus addresses to be + // pruned at the end of the block. + PendingConsensusAddrsByte + + // PendingUndelegationsByte is the byte used to store the list of undelegations that will + // mature at the end of the current block. + PendingUndelegationsByte ) // ExocoreValidatorKey returns the key for the validator store. @@ -82,3 +98,24 @@ func UnbondingReleaseMaturityKey(epoch int64) []byte { []byte{UnbondingReleaseMaturityBytePrefix}, sdk.Uint64ToBigEndian(uint64(epoch))...) } + +// PendingOperationsKey returns the key for the pending operations store. +func PendingOperationsKey() []byte { + return []byte{PendingOperationsByte} +} + +// PendingOptOutsKey returns the key for the pending opt-outs store. +func PendingOptOutsKey() []byte { + return []byte{PendingOptOutsByte} +} + +// PendingConsensusAddrsByte is the byte used to store the list of consensus addresses to be +// pruned at the end of the block. +func PendingConsensusAddrsKey() []byte { + return []byte{PendingConsensusAddrsByte} +} + +// PendingUndelegationsKey returns the key for the pending undelegations store. +func PendingUndelegationsKey() []byte { + return []byte{PendingUndelegationsByte} +} From a2aa2e106c43e60d908526a928b8fa035ba7391f Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Thu, 8 Feb 2024 16:54:31 +0000 Subject: [PATCH 14/32] fix(dogfood): call `EndBlock` from module --- x/dogfood/module.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/dogfood/module.go b/x/dogfood/module.go index 2ac7087e3..bfd476b9a 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -159,6 +159,6 @@ func (AppModule) ConsensusVersion() uint64 { return 1 } func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} // EndBlock contains the logic that is automatically triggered at the end of each block -func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - return []abci.ValidatorUpdate{} +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { + return am.keeper.EndBlock(ctx) } From cc56595c94ff9b3043b84d9ee5732d48d52529d7 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:24:17 +0000 Subject: [PATCH 15/32] feat(dogfood): retrieve val set from id The validator set is not bound to change at each block. It can only change at the end of an epoch, or following a slashing event. Therefore, storing the historical information for each block is redundant. Instead, we create a validator set id corresponding to each validator set, and map each height to a validator set id. The mapping and the validator set id are pruned once the historical info for a height is not required. TODO: actually store the validator set against each id, within the `EndBlock` function at the end of the epoch. --- proto/exocore/dogfood/v1/dogfood.proto | 20 + x/dogfood/genesis.go | 26 -- x/dogfood/keeper/genesis.go | 34 ++ x/dogfood/keeper/validators.go | 210 ++++++---- x/dogfood/module.go | 6 +- x/dogfood/types/dogfood.pb.go | 519 ++++++++++++++++++++++++- x/dogfood/types/keys.go | 28 +- 7 files changed, 719 insertions(+), 124 deletions(-) delete mode 100644 x/dogfood/genesis.go create mode 100644 x/dogfood/keeper/genesis.go diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index e51f4a408..429f893b2 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -4,7 +4,10 @@ package exocore.dogfood.v1; import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; + import "cosmos_proto/cosmos.proto"; +import "cosmos/staking/v1beta1/staking.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; @@ -21,4 +24,21 @@ message ExocoreValidator { (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\"" ]; +} + +// Validators is a list of validators stored according to the staking module. +message Validators { + repeated cosmos.staking.v1beta1.Validator list = 1 [(gogoproto.nullable) = false]; +} + +// HeaderSubset is a subset of the block header that is relevant to the IBC codebase. It is +// stored for each height and then converted to the `tm.Header` object after queried. It is +// pruned when the information is no longer needed according to the `HistoricalEntries` param. +message HeaderSubset { + // timestamp of the block + google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + // validators for the next block + bytes next_validators_hash = 2; + // state after txs from the previous block + bytes app_hash = 3; } \ No newline at end of file diff --git a/x/dogfood/genesis.go b/x/dogfood/genesis.go deleted file mode 100644 index de40ed814..000000000 --- a/x/dogfood/genesis.go +++ /dev/null @@ -1,26 +0,0 @@ -package dogfood - -import ( - "github.com/ExocoreNetwork/exocore/x/dogfood/keeper" - "github.com/ExocoreNetwork/exocore/x/dogfood/types" - abci "github.com/cometbft/cometbft/abci/types" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// InitGenesis initializes the module's state from a provided genesis state. -func InitGenesis( - ctx sdk.Context, - k keeper.Keeper, - genState types.GenesisState, -) []abci.ValidatorUpdate { - k.SetParams(ctx, genState.Params) - return k.ApplyValidatorChanges(ctx, genState.ValSet) -} - -// ExportGenesis returns the module's exported genesis -func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { - genesis := types.DefaultGenesis() - genesis.Params = k.GetDogfoodParams(ctx) - - return genesis -} diff --git a/x/dogfood/keeper/genesis.go b/x/dogfood/keeper/genesis.go new file mode 100644 index 000000000..16f51892b --- /dev/null +++ b/x/dogfood/keeper/genesis.go @@ -0,0 +1,34 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func (k Keeper) InitGenesis( + ctx sdk.Context, + genState types.GenesisState, +) []abci.ValidatorUpdate { + k.SetParams(ctx, genState.Params) + // the `params` validator is not super useful to validate state level information + // so, it must be done here. by extension, the `InitGenesis` of the epochs module + // should be called before that of this module. + _, found := k.epochsKeeper.GetEpochInfo(ctx, genState.Params.EpochIdentifier) + if !found { + // the panic is suitable here because it is being done at genesis, when the node + // is not running. it means that the genesis file is malformed. + panic("epoch info not found") + + } + return k.ApplyValidatorChanges(ctx, genState.ValSet) +} + +// ExportGenesis returns the module's exported genesis +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetDogfoodParams(ctx) + + return genesis +} diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index d1b5e3e37..15c5d229b 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -8,6 +8,7 @@ import ( "github.com/ExocoreNetwork/exocore/x/dogfood/types" abci "github.com/cometbft/cometbft/abci/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -21,10 +22,8 @@ import ( func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration { count := k.GetEpochsUntilUnbonded(ctx) identifier := k.GetEpochIdentifier(ctx) - epoch, found := k.epochsKeeper.GetEpochInfo(ctx, identifier) - if !found { - panic("epoch info not found") - } + // no need to check for found, as the epoch info is validated at genesis. + epoch, _ := k.epochsKeeper.GetEpochInfo(ctx, identifier) durationPerEpoch := epoch.Duration return time.Duration(count) * durationPerEpoch } @@ -138,103 +137,111 @@ func (k Keeper) GetAllExocoreValidators( func (k Keeper) GetHistoricalInfo( ctx sdk.Context, height int64, ) (stakingtypes.HistoricalInfo, bool) { - store := ctx.KVStore(k.storeKey) - key := types.HistoricalInfoKey(height) - - value := store.Get(key) - if value == nil { + headerSubset, found := k.GetBlockHeader(ctx, height) + if !found { + // only panic in the case of an unmarshal error return stakingtypes.HistoricalInfo{}, false } - - return stakingtypes.MustUnmarshalHistoricalInfo(k.cdc, value), true + valSetID, found := k.GetValidatorSetID(ctx, height) + if !found { + // only panic in the case of an unmarshal error + return stakingtypes.HistoricalInfo{}, false + } + valSet, found := k.GetValidatorSet(ctx, valSetID) + if !found { + // only panic in the case of an unmarshal error + return stakingtypes.HistoricalInfo{}, false + } + header := tmproto.Header{ + Time: headerSubset.Time, + NextValidatorsHash: headerSubset.NextValidatorsHash, + AppHash: headerSubset.AppHash, + } + return stakingtypes.NewHistoricalInfo( + header, stakingtypes.Validators(valSet.GetList()), sdk.DefaultPowerReduction, + ), true } -// SetHistoricalInfo sets the historical info at a given height. This is +// SetValidatorSet sets the validator set at a given id. This is // (intentionally) not exported in the genesis state. -func (k Keeper) SetHistoricalInfo( - ctx sdk.Context, height int64, hi *stakingtypes.HistoricalInfo, +func (k Keeper) SetValidatorSet( + ctx sdk.Context, id uint64, vs *types.Validators, ) { store := ctx.KVStore(k.storeKey) - key := types.HistoricalInfoKey(height) - value := k.cdc.MustMarshal(hi) - + key := types.ValidatorSetKey(id) + value := k.cdc.MustMarshal(vs) store.Set(key, value) } -// DeleteHistoricalInfo deletes the historical info at a given height. -func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) { +// GetValidatorSet gets the validator set at a given id. +func (k Keeper) GetValidatorSet( + ctx sdk.Context, id uint64, +) (*types.Validators, bool) { store := ctx.KVStore(k.storeKey) - key := types.HistoricalInfoKey(height) + key := types.ValidatorSetKey(id) + if !store.Has(key) { + return nil, false + } + value := store.Get(key) + var hi types.Validators + k.cdc.MustUnmarshal(value, &hi) + return &hi, true +} +// DeleteValidatorSet deletes the validator set at a given id. +func (k Keeper) DeleteValidatorSet(ctx sdk.Context, id uint64) { + store := ctx.KVStore(k.storeKey) + key := types.ValidatorSetKey(id) store.Delete(key) } -// TrackHistoricalInfo saves the latest historical-info and deletes the oldest -// heights that are below pruning height. +// TrackHistoricalInfo saves the latest historical info and deletes the ones eligible to be +// pruned. The historical info is stored in two parts: one is the header and the other is the +// validator set. Within an epoch, the validator set will only change if there is a slashing +// event. Otherwise, it is constant. The header, however, will change at every block. Since +// the Cosmos SDK does not allow for the retrieval of a past block header, we store the header +// ourselves in this function. The validator set is stored when it changes at the end of an +// epoch or at a slashing event in the corresponding functions. func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { + // Get the number of historical entries to persist, as the number of block heights. numHistoricalEntries := k.GetHistoricalEntries(ctx) - // Prune store to ensure we only have parameter-defined historical entries. - // In most cases, this will involve removing a single historical entry. - // In the rare scenario when the historical entries gets reduced to a lower value k' - // from the original value k. k - k' entries must be deleted from the store. - // Since the entries to be deleted are always in a continuous range, we can iterate - // over the historical entries starting from the most recent version to be pruned - // and then return at the first empty entry. + // we are deleting headers, say, from, 0 to 999 at block 1999 + // for these headers, we must find the corresponding validator set ids to delete. + // they must be only deleted if no other block is using them. + lastDeletedID := uint64(0) // contract: starts from 1. for i := ctx.BlockHeight() - int64(numHistoricalEntries); i >= 0; i-- { - _, found := k.GetHistoricalInfo(ctx, i) + _, found := k.GetBlockHeader(ctx, i) if found { - k.DeleteHistoricalInfo(ctx, i) + // because they are deleted together, and saved one after the other, + // since the block header exists, so must the validator set id. + lastDeletedID, _ = k.GetValidatorSetID(ctx, i+1) + // clear both the header and the mapping + k.DeleteBlockHeader(ctx, i) + k.DeleteValidatorSetID(ctx, i) } else { break } } + // contract: TrackHistoricalInfo must be called after storing the validator set + // for the current block. + currentID, _ := k.GetValidatorSetID(ctx, ctx.BlockHeight()) + for i := lastDeletedID; i < currentID; i++ { + k.DeleteValidatorSet(ctx, i) + } // if there is no need to persist historicalInfo, return. if numHistoricalEntries == 0 { return } - // Create HistoricalInfo struct - lastVals := []stakingtypes.Validator{} - for _, v := range k.GetAllExocoreValidators(ctx) { - pk, err := v.ConsPubKey() - if err != nil { - // This should never happen as the pubkey is assumed - // to be stored correctly earlier. - panic(err) - } - val, err := stakingtypes.NewValidator(nil, pk, stakingtypes.Description{}) - if err != nil { - // This should never happen as the pubkey is assumed - // to be stored correctly earlier. - panic(err) - } + // store the header + k.StoreBlockHeader(ctx) - // Set validator to bonded status. - val.Status = stakingtypes.Bonded - // Compute tokens from voting power. - val.Tokens = sdk.TokensFromConsensusPower( - v.Power, - // TODO(mm) - // note that this is not super relevant for the historical info - // since IBC does not seem to use the tokens field. - sdk.NewInt(1), - ) - lastVals = append(lastVals, val) - } - - // Create historical info entry which sorts the validator set by voting power. - historicalEntry := stakingtypes.NewHistoricalInfo( - ctx.BlockHeader(), lastVals, - // TODO(mm) - // this should match the power reduction number above - // and is also thus not relevant. - sdk.NewInt(1), - ) - - // Set latest HistoricalInfo at current height. - k.SetHistoricalInfo(ctx, ctx.BlockHeight(), &historicalEntry) + // we have stored: + // before TrackHistoricalInfo: ValidatorSetID for height, and the validator set. + // within TrackHistoricalInfo: the header. + // this is enough information to answer the GetHistoricalInfo query. } // MustGetCurrentValidatorsAsABCIUpdates gets all validators converted @@ -259,3 +266,66 @@ func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.Va } return valUpdates } + +// GetValidatorSetID returns the identifier of the validator set at a given height. +// It is used to "share" the validator set entries across multiple heights within an epoch. +// Typically, the validator set should change only at the end of an epoch. However, in the +// case of a slashing occurrence, the validator set may change within an epoch. +func (k Keeper) GetValidatorSetID(ctx sdk.Context, height int64) (uint64, bool) { + store := ctx.KVStore(k.storeKey) + key := types.ValidatorSetIDKey(height) + value := store.Get(key) + if value == nil { + return 0, false + } + return sdk.BigEndianToUint64(value), true +} + +// SetValidatorSetID sets the identifier of the validator set at a given height. +func (k Keeper) SetValidatorSetID(ctx sdk.Context, height int64, id uint64) { + store := ctx.KVStore(k.storeKey) + key := types.ValidatorSetIDKey(height) + value := sdk.Uint64ToBigEndian(id) + store.Set(key, value) +} + +// DeleteValidatorSetID deletes the identifier of the validator set at a given height. +func (k Keeper) DeleteValidatorSetID(ctx sdk.Context, height int64) { + store := ctx.KVStore(k.storeKey) + key := types.ValidatorSetIDKey(height) + store.Delete(key) +} + +// GetBlockHeader returns the block header at a given height. +func (k Keeper) GetBlockHeader(ctx sdk.Context, height int64) (types.HeaderSubset, bool) { + store := ctx.KVStore(k.storeKey) + key := types.HeaderKey(height) + var header types.HeaderSubset + value := store.Get(key) + if value == nil { + return header, false + } + k.cdc.MustUnmarshal(value, &header) + return header, true +} + +// SetBlockHeader sets the block header at a given height. +func (k Keeper) DeleteBlockHeader(ctx sdk.Context, height int64) { + store := ctx.KVStore(k.storeKey) + key := types.HeaderKey(height) + store.Delete(key) +} + +// StoreBlockHeader stores the block header subset as of the current height. +func (k Keeper) StoreBlockHeader(ctx sdk.Context) { + key := types.HeaderKey(ctx.BlockHeight()) + sdkHeader := ctx.BlockHeader() + header := types.HeaderSubset{ + Time: sdkHeader.Time, + NextValidatorsHash: sdkHeader.NextValidatorsHash, + AppHash: sdkHeader.GetAppHash(), + } + store := ctx.KVStore(k.storeKey) + value := k.cdc.MustMarshal(&header) + store.Set(key, value) +} diff --git a/x/dogfood/module.go b/x/dogfood/module.go index 2ac7087e3..4be32e0a3 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -141,12 +141,12 @@ func (am AppModule) InitGenesis( // Initialize global index to index in genesis state cdc.MustUnmarshalJSON(gs, &genState) - return InitGenesis(ctx, am.keeper, genState) + return am.keeper.InitGenesis(ctx, genState) } // ExportGenesis returns the module's exported genesis state as raw JSON bytes. func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { - genState := ExportGenesis(ctx, am.keeper) + genState := am.keeper.ExportGenesis(ctx) return cdc.MustMarshalJSON(genState) } @@ -159,6 +159,6 @@ func (AppModule) ConsensusVersion() uint64 { return 1 } func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} // EndBlock contains the logic that is automatically triggered at the end of each block -func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { +func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index 64cadbb85..1e5f859ed 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -7,17 +7,22 @@ import ( fmt "fmt" _ "github.com/cosmos/cosmos-proto" types "github.com/cosmos/cosmos-sdk/codec/types" + types1 "github.com/cosmos/cosmos-sdk/x/staking/types" _ "github.com/cosmos/gogoproto/gogoproto" proto "github.com/cosmos/gogoproto/proto" + github_com_cosmos_gogoproto_types "github.com/cosmos/gogoproto/types" + _ "google.golang.org/protobuf/types/known/timestamppb" io "io" math "math" math_bits "math/bits" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var _ = time.Kitchen // This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. @@ -91,33 +96,156 @@ func (m *ExocoreValidator) GetPubkey() *types.Any { return nil } +// Validators is a list of validators stored according to the staking module. +type Validators struct { + List []types1.Validator `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` +} + +func (m *Validators) Reset() { *m = Validators{} } +func (m *Validators) String() string { return proto.CompactTextString(m) } +func (*Validators) ProtoMessage() {} +func (*Validators) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{1} +} +func (m *Validators) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Validators) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Validators.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 *Validators) XXX_Merge(src proto.Message) { + xxx_messageInfo_Validators.Merge(m, src) +} +func (m *Validators) XXX_Size() int { + return m.Size() +} +func (m *Validators) XXX_DiscardUnknown() { + xxx_messageInfo_Validators.DiscardUnknown(m) +} + +var xxx_messageInfo_Validators proto.InternalMessageInfo + +func (m *Validators) GetList() []types1.Validator { + if m != nil { + return m.List + } + return nil +} + +// HeaderSubset is a subset of the block header that is relevant to the IBC codebase. It is +// stored for each height and then converted to the `tm.Header` object after queried. It is +// pruned when the information is no longer needed according to the `HistoricalEntries` param. +type HeaderSubset struct { + // timestamp of the block + Time time.Time `protobuf:"bytes,1,opt,name=time,proto3,stdtime" json:"time"` + // validators for the next block + NextValidatorsHash []byte `protobuf:"bytes,2,opt,name=next_validators_hash,json=nextValidatorsHash,proto3" json:"next_validators_hash,omitempty"` + // state after txs from the previous block + AppHash []byte `protobuf:"bytes,3,opt,name=app_hash,json=appHash,proto3" json:"app_hash,omitempty"` +} + +func (m *HeaderSubset) Reset() { *m = HeaderSubset{} } +func (m *HeaderSubset) String() string { return proto.CompactTextString(m) } +func (*HeaderSubset) ProtoMessage() {} +func (*HeaderSubset) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{2} +} +func (m *HeaderSubset) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HeaderSubset) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HeaderSubset.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 *HeaderSubset) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeaderSubset.Merge(m, src) +} +func (m *HeaderSubset) XXX_Size() int { + return m.Size() +} +func (m *HeaderSubset) XXX_DiscardUnknown() { + xxx_messageInfo_HeaderSubset.DiscardUnknown(m) +} + +var xxx_messageInfo_HeaderSubset proto.InternalMessageInfo + +func (m *HeaderSubset) GetTime() time.Time { + if m != nil { + return m.Time + } + return time.Time{} +} + +func (m *HeaderSubset) GetNextValidatorsHash() []byte { + if m != nil { + return m.NextValidatorsHash + } + return nil +} + +func (m *HeaderSubset) GetAppHash() []byte { + if m != nil { + return m.AppHash + } + return nil +} + func init() { proto.RegisterType((*ExocoreValidator)(nil), "exocore.dogfood.v1.ExocoreValidator") + proto.RegisterType((*Validators)(nil), "exocore.dogfood.v1.Validators") + proto.RegisterType((*HeaderSubset)(nil), "exocore.dogfood.v1.HeaderSubset") } func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } var fileDescriptor_071b9989c501c3f2 = []byte{ - // 302 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x90, 0x31, 0x4e, 0xf3, 0x30, - 0x14, 0xc7, 0xeb, 0xaf, 0xfa, 0x8a, 0x14, 0x18, 0x50, 0x14, 0x89, 0xd0, 0xc1, 0x44, 0x9d, 0xba, - 0x60, 0xab, 0x74, 0x63, 0xa3, 0x12, 0x53, 0x25, 0x84, 0x3a, 0x30, 0xb0, 0x54, 0x4e, 0xe2, 0x9a, - 0xaa, 0x49, 0x5e, 0x64, 0x3b, 0x6d, 0x7d, 0x0b, 0x2e, 0xc1, 0x0d, 0x38, 0x04, 0x62, 0xea, 0xc8, - 0x84, 0x50, 0x72, 0x03, 0x4e, 0x80, 0x88, 0x63, 0xb6, 0xf7, 0xf3, 0xff, 0x3d, 0xfb, 0xe7, 0xe7, - 0x45, 0x7c, 0x0f, 0x09, 0x48, 0x4e, 0x53, 0x10, 0x2b, 0x80, 0x94, 0x6e, 0x27, 0xae, 0x24, 0xa5, - 0x04, 0x0d, 0xbe, 0xdf, 0x75, 0x10, 0x77, 0xbc, 0x9d, 0x0c, 0x03, 0x01, 0x02, 0xda, 0x98, 0xfe, - 0x56, 0xb6, 0x73, 0x78, 0x2e, 0x00, 0x44, 0xc6, 0x69, 0x4b, 0x71, 0xb5, 0xa2, 0xac, 0x30, 0x2e, - 0x4a, 0x40, 0xe5, 0xa0, 0x96, 0x76, 0xc6, 0x82, 0x8d, 0x46, 0x2f, 0xc8, 0x3b, 0xbd, 0xb5, 0x4f, - 0x3c, 0xb0, 0x6c, 0x9d, 0x32, 0x0d, 0xd2, 0x0f, 0xbd, 0x23, 0x96, 0xa6, 0x92, 0x2b, 0x15, 0xa2, - 0x08, 0x8d, 0x4f, 0x16, 0x0e, 0xfd, 0xc0, 0xfb, 0x5f, 0xc2, 0x8e, 0xcb, 0xf0, 0x5f, 0x84, 0xc6, - 0xfd, 0x85, 0x05, 0x9f, 0x79, 0x83, 0xb2, 0x8a, 0x37, 0xdc, 0x84, 0xfd, 0x08, 0x8d, 0x8f, 0xaf, - 0x02, 0x62, 0x5d, 0x88, 0x73, 0x21, 0x37, 0x85, 0x99, 0x4d, 0xbf, 0x3f, 0x2f, 0xce, 0x0c, 0xcb, - 0xb3, 0xeb, 0x51, 0x02, 0x85, 0xe2, 0x85, 0xaa, 0xd4, 0xd2, 0xce, 0x8d, 0xde, 0x5f, 0x2f, 0x83, - 0xce, 0x2b, 0x91, 0xa6, 0xd4, 0x40, 0xee, 0xab, 0x78, 0xce, 0xcd, 0xa2, 0xbb, 0x78, 0x36, 0x7f, - 0xab, 0x31, 0x3a, 0xd4, 0x18, 0x7d, 0xd5, 0x18, 0x3d, 0x37, 0xb8, 0x77, 0x68, 0x70, 0xef, 0xa3, - 0xc1, 0xbd, 0xc7, 0x89, 0x58, 0xeb, 0xa7, 0x2a, 0x26, 0x09, 0xe4, 0xb4, 0xfb, 0xc9, 0x1d, 0xd7, - 0x3b, 0x90, 0x1b, 0xea, 0xb6, 0xbb, 0xff, 0xdb, 0xaf, 0x36, 0x25, 0x57, 0xf1, 0xa0, 0xf5, 0x9a, - 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x39, 0xda, 0x59, 0x49, 0x7f, 0x01, 0x00, 0x00, + // 454 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x92, 0x31, 0x8e, 0xd3, 0x40, + 0x14, 0x86, 0x33, 0x24, 0x2c, 0xab, 0x49, 0x0a, 0x34, 0xb2, 0x84, 0x37, 0x85, 0x63, 0x2c, 0x8a, + 0x34, 0xd8, 0x38, 0xdb, 0x20, 0xa8, 0x88, 0x84, 0xb4, 0x68, 0x25, 0x84, 0x0c, 0xa2, 0xa0, 0x89, + 0xc6, 0xf6, 0xac, 0x63, 0x25, 0xf6, 0x1b, 0x79, 0xc6, 0xd9, 0xf8, 0x16, 0xdb, 0x70, 0x04, 0x6e, + 0xc0, 0x21, 0x56, 0x54, 0x5b, 0x52, 0x05, 0x94, 0xdc, 0x80, 0x13, 0x20, 0x7b, 0x66, 0x82, 0xc4, + 0x76, 0xf3, 0xfb, 0x7f, 0xff, 0xd3, 0xf7, 0x9e, 0x1f, 0x76, 0xd9, 0x16, 0x12, 0xa8, 0x58, 0x90, + 0x42, 0x76, 0x05, 0x90, 0x06, 0x9b, 0xd0, 0x3c, 0x7d, 0x5e, 0x81, 0x04, 0x42, 0x74, 0x85, 0x6f, + 0x3e, 0x6f, 0xc2, 0xb1, 0x95, 0x41, 0x06, 0x9d, 0x1d, 0xb4, 0x2f, 0x55, 0x39, 0x3e, 0xcb, 0x00, + 0xb2, 0x35, 0x0b, 0x3a, 0x15, 0xd7, 0x57, 0x01, 0x2d, 0x1b, 0x6d, 0x4d, 0xfe, 0xb7, 0x64, 0x5e, + 0x30, 0x21, 0x69, 0xc1, 0x4d, 0x36, 0x01, 0x51, 0x80, 0x58, 0xa8, 0xa6, 0x4a, 0x68, 0xeb, 0x99, + 0x52, 0x81, 0x90, 0x74, 0x95, 0x97, 0x59, 0xb0, 0x09, 0x63, 0x26, 0x69, 0x68, 0xb4, 0xaa, 0xf2, + 0xbe, 0x21, 0xfc, 0xf8, 0xad, 0x22, 0xfd, 0x4c, 0xd7, 0x79, 0x4a, 0x25, 0x54, 0xc4, 0xc6, 0x8f, + 0x68, 0x9a, 0x56, 0x4c, 0x08, 0x1b, 0xb9, 0x68, 0x3a, 0x8a, 0x8c, 0x24, 0x16, 0x7e, 0xc8, 0xe1, + 0x9a, 0x55, 0xf6, 0x03, 0x17, 0x4d, 0xfb, 0x91, 0x12, 0x84, 0xe2, 0x13, 0x5e, 0xc7, 0x2b, 0xd6, + 0xd8, 0x7d, 0x17, 0x4d, 0x87, 0x33, 0xcb, 0x57, 0xdc, 0xbe, 0xe1, 0xf6, 0xdf, 0x94, 0xcd, 0xfc, + 0xfc, 0xcf, 0x6e, 0xf2, 0xa4, 0xa1, 0xc5, 0xfa, 0x95, 0x97, 0x40, 0x29, 0x58, 0x29, 0x6a, 0xb1, + 0x50, 0x39, 0xef, 0xc7, 0xf7, 0xe7, 0x96, 0xa6, 0x4f, 0xaa, 0x86, 0x4b, 0xf0, 0x3f, 0xd4, 0xf1, + 0x25, 0x6b, 0x22, 0xdd, 0xd8, 0x7b, 0x87, 0xf1, 0x91, 0x4f, 0x90, 0xd7, 0x78, 0xb0, 0xce, 0x85, + 0xb4, 0x91, 0xdb, 0x9f, 0x0e, 0x67, 0x4f, 0x7d, 0x1d, 0x35, 0xa3, 0xe9, 0x51, 0xfd, 0x63, 0x62, + 0x3e, 0xb8, 0xdd, 0x4d, 0x7a, 0x51, 0x17, 0xf2, 0xbe, 0x22, 0x3c, 0xba, 0x60, 0x34, 0x65, 0xd5, + 0xc7, 0x3a, 0x16, 0x4c, 0x92, 0x97, 0x78, 0xd0, 0xee, 0xb5, 0x9b, 0x75, 0x38, 0x1b, 0xdf, 0x83, + 0xff, 0x64, 0x96, 0x3e, 0x3f, 0x6d, 0xdb, 0xdc, 0xfc, 0x9a, 0xa0, 0xa8, 0x4b, 0x90, 0x17, 0xd8, + 0x2a, 0xd9, 0x56, 0x2e, 0x36, 0x47, 0xb4, 0xc5, 0x92, 0x8a, 0x65, 0xb7, 0x9d, 0x51, 0x44, 0x5a, + 0xef, 0x1f, 0xf5, 0x05, 0x15, 0x4b, 0x72, 0x86, 0x4f, 0x29, 0xe7, 0xaa, 0xaa, 0xaf, 0x77, 0xcb, + 0x79, 0x6b, 0xcd, 0x2f, 0x6f, 0xf7, 0x0e, 0xba, 0xdb, 0x3b, 0xe8, 0xf7, 0xde, 0x41, 0x37, 0x07, + 0xa7, 0x77, 0x77, 0x70, 0x7a, 0x3f, 0x0f, 0x4e, 0xef, 0x4b, 0x98, 0xe5, 0x72, 0x59, 0xc7, 0x7e, + 0x02, 0x45, 0xa0, 0x7f, 0xd6, 0x7b, 0x26, 0xaf, 0xa1, 0x5a, 0x05, 0xe6, 0x0e, 0xb7, 0xc7, 0x4b, + 0x94, 0x0d, 0x67, 0x22, 0x3e, 0xe9, 0xe8, 0xcf, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x07, 0xfc, + 0xed, 0x55, 0xa9, 0x02, 0x00, 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { @@ -167,6 +295,88 @@ func (m *ExocoreValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *Validators) 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 *Validators) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Validators) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintDogfood(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *HeaderSubset) 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 *HeaderSubset) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeaderSubset) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AppHash) > 0 { + i -= len(m.AppHash) + copy(dAtA[i:], m.AppHash) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.AppHash))) + i-- + dAtA[i] = 0x1a + } + if len(m.NextValidatorsHash) > 0 { + i -= len(m.NextValidatorsHash) + copy(dAtA[i:], m.NextValidatorsHash) + i = encodeVarintDogfood(dAtA, i, uint64(len(m.NextValidatorsHash))) + i-- + dAtA[i] = 0x12 + } + n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):]) + if err2 != nil { + return 0, err2 + } + i -= n2 + i = encodeVarintDogfood(dAtA, i, uint64(n2)) + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + func encodeVarintDogfood(dAtA []byte, offset int, v uint64) int { offset -= sovDogfood(v) base := offset @@ -198,6 +408,40 @@ func (m *ExocoreValidator) Size() (n int) { return n } +func (m *Validators) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for _, e := range m.List { + l = e.Size() + n += 1 + l + sovDogfood(uint64(l)) + } + } + return n +} + +func (m *HeaderSubset) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time) + n += 1 + l + sovDogfood(uint64(l)) + l = len(m.NextValidatorsHash) + if l > 0 { + n += 1 + l + sovDogfood(uint64(l)) + } + l = len(m.AppHash) + if l > 0 { + n += 1 + l + sovDogfood(uint64(l)) + } + return n +} + func sovDogfood(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -343,6 +587,241 @@ func (m *ExocoreValidator) Unmarshal(dAtA []byte) error { } return nil } +func (m *Validators) 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 ErrIntOverflowDogfood + } + 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: Validators: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Validators: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.List = append(m.List, types1.Validator{}) + if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *HeaderSubset) 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 ErrIntOverflowDogfood + } + 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: HeaderSubset: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: HeaderSubset: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextValidatorsHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NextValidatorsHash = append(m.NextValidatorsHash[:0], dAtA[iNdEx:postIndex]...) + if m.NextValidatorsHash == nil { + m.NextValidatorsHash = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthDogfood + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) + if m.AppHash == nil { + m.AppHash = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipDogfood(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index f7efde563..e3875dc57 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -16,8 +16,14 @@ const ( // ExocoreValidatorBytePrefix is the prefix for the validator store. ExocoreValidatorBytePrefix byte = iota + 1 - // HistoricalInfoBytePrefix is the prefix for the historical info store. - HistoricalInfoBytePrefix + // ValidatorSetBytePrefix is the prefix for the historical validator set store. + ValidatorSetBytePrefix + + // ValidatorSetIDBytePrefix is the prefix for the validator set id store. + ValidatorSetIDBytePrefix + + // HeaderBytePrefix is the prefix for the header store. + HeaderBytePrefix ) // ExocoreValidatorKey returns the key for the validator store. @@ -25,8 +31,20 @@ func ExocoreValidatorKey(address sdk.AccAddress) []byte { return append([]byte{ExocoreValidatorBytePrefix}, address.Bytes()...) } -// HistoricalInfoKey returns the key for the historical info store. -func HistoricalInfoKey(height int64) []byte { +// ValidatorSetKey returns the key for the historical validator set store. +func ValidatorSetKey(id uint64) []byte { + bz := sdk.Uint64ToBigEndian(id) + return append([]byte{ValidatorSetBytePrefix}, bz...) +} + +// ValidatorSetIDKey returns the key for the validator set id store. +func ValidatorSetIDKey(height int64) []byte { + bz := sdk.Uint64ToBigEndian(uint64(height)) + return append([]byte{ValidatorSetIDBytePrefix}, bz...) +} + +// HeaderKey returns the key for the header store. +func HeaderKey(height int64) []byte { bz := sdk.Uint64ToBigEndian(uint64(height)) - return append([]byte{HistoricalInfoBytePrefix}, bz...) + return append([]byte{HeaderBytePrefix}, bz...) } From 3447309b9f3c1342bf4e2d1e3fa26dcace13ddbe Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:35:44 +0000 Subject: [PATCH 16/32] fix(dogfood): remove old key then add new --- x/dogfood/keeper/impl_operator_hooks.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/x/dogfood/keeper/impl_operator_hooks.go b/x/dogfood/keeper/impl_operator_hooks.go index 9e0c22af2..3599d6565 100644 --- a/x/dogfood/keeper/impl_operator_hooks.go +++ b/x/dogfood/keeper/impl_operator_hooks.go @@ -104,15 +104,7 @@ func (h OperatorHooksWrapper) AfterOperatorKeyReplacement( chainID string, ) { if strings.Compare(chainID, ctx.ChainID()) == 0 { - // res == Removed, it means operator has added their original key again - // res == Success, there is no additional information to store - // res == Exists, there is no nothing to do - if res := h.keeper.QueueOperation( - ctx, addr, newKey, types.KeyAdditionOrUpdate, - ); res == types.QueueResultRemoved { - // see AfterOperatorOptIn for explanation - h.keeper.ClearUnbondingInformation(ctx, addr, newKey) - } + // remove the old key // res == Removed, it means operator had added this key and is now removing it. // no additional information to clear. // res == Success, the old key should be pruned from the operator module. @@ -123,6 +115,16 @@ func (h OperatorHooksWrapper) AfterOperatorKeyReplacement( // the old key can be marked for pruning h.keeper.SetUnbondingInformation(ctx, addr, oldKey, false) } + // add the new key + // res == Removed, it means operator has added their original key again + // res == Success, there is no additional information to store + // res == Exists, there is no nothing to do + if res := h.keeper.QueueOperation( + ctx, addr, newKey, types.KeyAdditionOrUpdate, + ); res == types.QueueResultRemoved { + // see AfterOperatorOptIn for explanation + h.keeper.ClearUnbondingInformation(ctx, addr, newKey) + } } } From fe987cef101286d3c8e205b821700c188aee3394 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:41:30 +0000 Subject: [PATCH 17/32] fix(dogfood): RecordKeys > UndelegationRecordKeys The delegation module calls the records as undelegation records, and within itself stores the identifier for the record as the record key. The dogfood module should follow the same naming convention and call them undelegation record keys for clarity. --- proto/exocore/dogfood/v1/dogfood.proto | 7 +- x/dogfood/keeper/unbonding.go | 8 +- x/dogfood/types/dogfood.pb.go | 157 ++++++++++++------------- 3 files changed, 85 insertions(+), 87 deletions(-) diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index 587e5522f..21c5b350b 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -84,10 +84,9 @@ message ConsensusAddresses { repeated bytes list = 1; } -// RecordKeys is a collection of record keys. This is used to store a list of -// undelegation records to mature in the delegation module at the end of the -// epoch. -message RecordKeys { +// UndelegationRecordKeys is a collection of undelegation record keys. This is used to store a +// list of undelegation records to mature in the delegation module at the end of the epoch. +message UndelegationRecordKeys { repeated bytes list = 1; } diff --git a/x/dogfood/keeper/unbonding.go b/x/dogfood/keeper/unbonding.go index a973754c5..9e588e63a 100644 --- a/x/dogfood/keeper/unbonding.go +++ b/x/dogfood/keeper/unbonding.go @@ -63,7 +63,7 @@ func (k Keeper) AppendUndelegationToMature( ctx sdk.Context, epoch int64, recordKey []byte, ) { prev := k.GetUndelegationsToMature(ctx, epoch) - next := types.RecordKeys{ + next := types.UndelegationRecordKeys{ List: append(prev, recordKey), } k.setUndelegationsToMature(ctx, epoch, next) @@ -80,7 +80,7 @@ func (k Keeper) GetUndelegationsToMature( if bz == nil { return [][]byte{} } - var res types.RecordKeys + var res types.UndelegationRecordKeys if err := res.Unmarshal(bz); err != nil { // should never happen panic(err) @@ -101,11 +101,11 @@ func (k Keeper) ClearUndelegationsToMature( // setUndelegationsToMature sets all undelegation entries that should be released // at the end of the provided epoch. func (k Keeper) setUndelegationsToMature( - ctx sdk.Context, epoch int64, recordKeys types.RecordKeys, + ctx sdk.Context, epoch int64, undelegationRecords types.UndelegationRecordKeys, ) { store := ctx.KVStore(k.storeKey) key := types.UnbondingReleaseMaturityKey(epoch) - val, err := recordKeys.Marshal() + val, err := undelegationRecords.Marshal() if err != nil { panic(err) } diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index 0b5879f77..fc3868a19 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -372,25 +372,24 @@ func (m *ConsensusAddresses) GetList() [][]byte { return nil } -// RecordKeys is a collection of record keys. This is used to store a list of -// undelegation records to mature in the delegation module at the end of the -// epoch. -type RecordKeys struct { +// UndelegationRecordKeys is a collection of undelegation record keys. This is used to store a +// list of undelegation records to mature in the delegation module at the end of the epoch. +type UndelegationRecordKeys struct { List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` } -func (m *RecordKeys) Reset() { *m = RecordKeys{} } -func (m *RecordKeys) String() string { return proto.CompactTextString(m) } -func (*RecordKeys) ProtoMessage() {} -func (*RecordKeys) Descriptor() ([]byte, []int) { +func (m *UndelegationRecordKeys) Reset() { *m = UndelegationRecordKeys{} } +func (m *UndelegationRecordKeys) String() string { return proto.CompactTextString(m) } +func (*UndelegationRecordKeys) ProtoMessage() {} +func (*UndelegationRecordKeys) Descriptor() ([]byte, []int) { return fileDescriptor_071b9989c501c3f2, []int{5} } -func (m *RecordKeys) XXX_Unmarshal(b []byte) error { +func (m *UndelegationRecordKeys) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *RecordKeys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *UndelegationRecordKeys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_RecordKeys.Marshal(b, m, deterministic) + return xxx_messageInfo_UndelegationRecordKeys.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -400,19 +399,19 @@ func (m *RecordKeys) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { return b[:n], nil } } -func (m *RecordKeys) XXX_Merge(src proto.Message) { - xxx_messageInfo_RecordKeys.Merge(m, src) +func (m *UndelegationRecordKeys) XXX_Merge(src proto.Message) { + xxx_messageInfo_UndelegationRecordKeys.Merge(m, src) } -func (m *RecordKeys) XXX_Size() int { +func (m *UndelegationRecordKeys) XXX_Size() int { return m.Size() } -func (m *RecordKeys) XXX_DiscardUnknown() { - xxx_messageInfo_RecordKeys.DiscardUnknown(m) +func (m *UndelegationRecordKeys) XXX_DiscardUnknown() { + xxx_messageInfo_UndelegationRecordKeys.DiscardUnknown(m) } -var xxx_messageInfo_RecordKeys proto.InternalMessageInfo +var xxx_messageInfo_UndelegationRecordKeys proto.InternalMessageInfo -func (m *RecordKeys) GetList() [][]byte { +func (m *UndelegationRecordKeys) GetList() [][]byte { if m != nil { return m.List } @@ -538,7 +537,7 @@ func init() { proto.RegisterType((*Operations)(nil), "exocore.dogfood.v1.Operations") proto.RegisterType((*AccountAddresses)(nil), "exocore.dogfood.v1.AccountAddresses") proto.RegisterType((*ConsensusAddresses)(nil), "exocore.dogfood.v1.ConsensusAddresses") - proto.RegisterType((*RecordKeys)(nil), "exocore.dogfood.v1.RecordKeys") + proto.RegisterType((*UndelegationRecordKeys)(nil), "exocore.dogfood.v1.UndelegationRecordKeys") proto.RegisterType((*Validators)(nil), "exocore.dogfood.v1.Validators") proto.RegisterType((*HeaderSubset)(nil), "exocore.dogfood.v1.HeaderSubset") } @@ -546,61 +545,61 @@ func init() { func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } var fileDescriptor_071b9989c501c3f2 = []byte{ - // 849 bytes of a gzipped FileDescriptorProto + // 857 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xcf, 0x6f, 0xe3, 0x44, 0x14, 0x8e, 0x9b, 0xb2, 0xbb, 0x4c, 0xbb, 0x5d, 0x33, 0x84, 0x6e, 0x6a, 0xed, 0xa6, 0x6e, 0x84, - 0x50, 0xa8, 0x84, 0x4d, 0x5a, 0x10, 0x08, 0x04, 0x52, 0xda, 0x18, 0x35, 0xca, 0xd2, 0x64, 0xed, - 0x64, 0x05, 0x5c, 0xac, 0x89, 0xfd, 0x9a, 0x5a, 0x4d, 0x3c, 0x23, 0xcf, 0x38, 0x5b, 0xff, 0x07, - 0x28, 0xa7, 0xbd, 0x70, 0xcc, 0x09, 0xf1, 0x1f, 0x20, 0x71, 0xe2, 0xbe, 0xe2, 0xb4, 0x47, 0x4e, - 0x0b, 0x6a, 0xff, 0x03, 0x6e, 0xdc, 0x56, 0xfe, 0x95, 0x66, 0x9b, 0xaa, 0x37, 0xbf, 0x79, 0xef, - 0x7b, 0xf3, 0x7d, 0x7e, 0xdf, 0x3c, 0xa4, 0xc2, 0x39, 0x75, 0x68, 0x00, 0xba, 0x4b, 0x87, 0x27, - 0x94, 0xba, 0xfa, 0xa4, 0x9e, 0x7f, 0x6a, 0x2c, 0xa0, 0x82, 0x62, 0x9c, 0x55, 0x68, 0xf9, 0xf1, - 0xa4, 0xae, 0x94, 0x86, 0x74, 0x48, 0x93, 0xb4, 0x1e, 0x7f, 0xa5, 0x95, 0xca, 0xd6, 0x90, 0xd2, - 0xe1, 0x08, 0xf4, 0x24, 0x1a, 0x84, 0x27, 0x3a, 0xf1, 0xa3, 0x2c, 0xb5, 0x7d, 0x3d, 0x25, 0xbc, - 0x31, 0x70, 0x41, 0xc6, 0x2c, 0xc7, 0x3a, 0x94, 0x8f, 0x29, 0xb7, 0xd3, 0xa6, 0x69, 0x90, 0xa5, - 0x1e, 0x09, 0xf0, 0x5d, 0x08, 0xc6, 0x9e, 0x2f, 0x74, 0x27, 0x88, 0x98, 0xa0, 0xfa, 0x19, 0x44, - 0x79, 0xf6, 0xc3, 0xb4, 0x56, 0xe7, 0x82, 0x9c, 0x79, 0xfe, 0x50, 0x9f, 0xd4, 0x07, 0x20, 0x48, - 0x3d, 0x8f, 0xd3, 0xaa, 0xea, 0x6f, 0x12, 0x92, 0x8d, 0x54, 0xc7, 0x33, 0x32, 0xf2, 0x5c, 0x22, - 0x68, 0x80, 0xcb, 0xe8, 0x2e, 0x71, 0xdd, 0x00, 0x38, 0x2f, 0x4b, 0xaa, 0x54, 0x5b, 0x37, 0xf3, - 0x10, 0x97, 0xd0, 0x3b, 0x8c, 0x3e, 0x87, 0xa0, 0xbc, 0xa2, 0x4a, 0xb5, 0xa2, 0x99, 0x06, 0x98, - 0xa0, 0x3b, 0x2c, 0x1c, 0x9c, 0x41, 0x54, 0x2e, 0xaa, 0x52, 0x6d, 0x6d, 0xaf, 0xa4, 0xa5, 0xaa, - 0xb4, 0x5c, 0x95, 0xd6, 0xf0, 0xa3, 0x83, 0xfd, 0xff, 0x5e, 0x6f, 0x3f, 0x8c, 0xc8, 0x78, 0xf4, - 0x55, 0xd5, 0xa1, 0x3e, 0x07, 0x9f, 0x87, 0xdc, 0x4e, 0x71, 0xd5, 0xbf, 0x7e, 0xff, 0xa4, 0x94, - 0x69, 0x4b, 0x95, 0x68, 0xdd, 0x70, 0xd0, 0x86, 0xc8, 0xcc, 0x1a, 0x57, 0xff, 0x94, 0xd0, 0xbb, - 0x1d, 0x06, 0x01, 0x11, 0x1e, 0xf5, 0xf1, 0x11, 0xda, 0xa0, 0x79, 0x60, 0x8b, 0x88, 0x41, 0xc2, - 0x73, 0x63, 0x6f, 0x47, 0x5b, 0x9e, 0x89, 0x36, 0x87, 0xf5, 0x22, 0x06, 0xe6, 0x7d, 0xba, 0x18, - 0xe2, 0x8f, 0x91, 0x9c, 0x1e, 0xd0, 0xc0, 0xce, 0x35, 0xaf, 0x24, 0x9a, 0x1f, 0xe4, 0xe7, 0x8d, - 0x4c, 0xfb, 0xd7, 0xe8, 0x2e, 0x0b, 0x07, 0xf6, 0x95, 0xcc, 0x47, 0xda, 0xd5, 0x00, 0x16, 0x68, - 0x8f, 0x3c, 0xa7, 0x0d, 0xd1, 0xc1, 0xea, 0xcb, 0xd7, 0xdb, 0x85, 0x84, 0x7f, 0x1b, 0xa2, 0xaa, - 0x81, 0xd0, 0x9c, 0x07, 0xc7, 0x5f, 0xa0, 0xd5, 0x91, 0xc7, 0x45, 0x59, 0x52, 0x8b, 0xb5, 0xb5, - 0xbd, 0xc7, 0xb7, 0xb2, 0xce, 0x1a, 0x25, 0x80, 0xea, 0x47, 0x48, 0x6e, 0x38, 0x0e, 0x0d, 0x7d, - 0x91, 0xb1, 0x02, 0x8e, 0xf1, 0x42, 0xb3, 0xf5, 0xac, 0xae, 0x86, 0xf0, 0x61, 0xfe, 0x8f, 0x6f, - 0xaf, 0x54, 0x11, 0x32, 0xc1, 0xa1, 0x81, 0xdb, 0x86, 0xe8, 0xe6, 0x8a, 0x16, 0x42, 0x73, 0x6b, - 0xc4, 0x7f, 0x61, 0x91, 0xfa, 0x8e, 0x96, 0x4d, 0x2d, 0x77, 0x55, 0xe6, 0x32, 0x6d, 0x8e, 0x78, - 0x8b, 0xfe, 0x2f, 0x12, 0x5a, 0x3f, 0x02, 0xe2, 0x42, 0x60, 0x85, 0x03, 0x0e, 0x02, 0x7f, 0x89, - 0x56, 0x63, 0xc3, 0x27, 0xe3, 0x5b, 0xdb, 0x53, 0x96, 0x7c, 0xd3, 0xcb, 0x5f, 0xc3, 0xc1, 0xbd, - 0xb8, 0xcd, 0x8b, 0x7f, 0xb6, 0x25, 0x33, 0x41, 0xe0, 0x4f, 0x51, 0xc9, 0x87, 0x73, 0x61, 0x4f, - 0xe6, 0xd4, 0xec, 0x53, 0xc2, 0x4f, 0xb3, 0xe1, 0xe1, 0x38, 0x77, 0xc5, 0xfa, 0x88, 0xf0, 0x53, - 0xbc, 0x85, 0xee, 0x11, 0xc6, 0xd2, 0xaa, 0x62, 0x66, 0x6b, 0xc6, 0xe2, 0xd4, 0xee, 0x1f, 0x12, - 0xba, 0xff, 0x96, 0x4d, 0xf0, 0x67, 0x48, 0xe9, 0x74, 0x0d, 0xb3, 0xd1, 0x6b, 0x75, 0x8e, 0xed, - 0xde, 0x8f, 0x5d, 0xc3, 0xee, 0x1f, 0x5b, 0x5d, 0xe3, 0xb0, 0xf5, 0x5d, 0xcb, 0x68, 0xca, 0x05, - 0xa5, 0x34, 0x9d, 0xa9, 0x72, 0x1b, 0xa2, 0x0e, 0xeb, 0xfb, 0x9c, 0x81, 0xe3, 0x9d, 0x78, 0xe0, - 0xe2, 0x6f, 0xd1, 0xce, 0x35, 0x54, 0xa3, 0xd9, 0x6c, 0x25, 0x51, 0xc7, 0xb4, 0xfb, 0xdd, 0x66, - 0xa3, 0x67, 0xc8, 0x92, 0xf2, 0x70, 0x3a, 0x53, 0xdf, 0x6f, 0x43, 0xd4, 0x70, 0x5d, 0x2f, 0xbe, - 0xb1, 0x13, 0xf4, 0x99, 0x4b, 0x04, 0xe0, 0x5d, 0xb4, 0x79, 0x0d, 0x6f, 0x1a, 0xdf, 0x77, 0x9e, - 0x35, 0x9e, 0xc8, 0x2b, 0xca, 0xc6, 0x74, 0xa6, 0xa2, 0xf8, 0x49, 0xc0, 0x98, 0x4e, 0xc8, 0x48, - 0x59, 0xfd, 0xf9, 0xd7, 0x4a, 0x61, 0xf7, 0x7f, 0x09, 0x3d, 0x78, 0x1a, 0x42, 0x08, 0x26, 0xf0, - 0x70, 0x24, 0x12, 0xee, 0xdf, 0xa0, 0xc7, 0x4f, 0xfb, 0x46, 0x3f, 0x06, 0x5b, 0xfd, 0x27, 0xbd, - 0x9b, 0xe8, 0x2b, 0xd3, 0x99, 0xba, 0xb9, 0x80, 0x5b, 0x14, 0xf1, 0x39, 0xda, 0x5a, 0x86, 0x5b, - 0xfd, 0xc3, 0x43, 0xc3, 0xb2, 0x64, 0x49, 0xd9, 0x9c, 0xce, 0x54, 0xbc, 0x00, 0xb5, 0x42, 0xc7, - 0x89, 0x9f, 0xc7, 0x3e, 0x2a, 0x2f, 0xc3, 0x8c, 0x1f, 0x5a, 0x56, 0xcf, 0x92, 0x57, 0x94, 0x0f, - 0xa6, 0x33, 0xf5, 0xbd, 0x05, 0x94, 0x71, 0xee, 0x71, 0xc1, 0x6f, 0xbe, 0x2b, 0xd1, 0x6c, 0x34, - 0xe5, 0xe2, 0xd2, 0x5d, 0x89, 0x76, 0x70, 0x53, 0xed, 0x07, 0xed, 0x97, 0x17, 0x15, 0xe9, 0xd5, - 0x45, 0x45, 0xfa, 0xf7, 0xa2, 0x22, 0xbd, 0xb8, 0xac, 0x14, 0x5e, 0x5d, 0x56, 0x0a, 0x7f, 0x5f, - 0x56, 0x0a, 0x3f, 0xd5, 0x87, 0x9e, 0x38, 0x0d, 0x07, 0x9a, 0x43, 0xc7, 0x7a, 0xb6, 0xdd, 0x8e, - 0x41, 0x3c, 0xa7, 0xc1, 0x99, 0x9e, 0xaf, 0xf5, 0xf3, 0xf9, 0x62, 0x8f, 0xf7, 0x07, 0x1f, 0xdc, - 0x49, 0x3c, 0xb7, 0xff, 0x26, 0x00, 0x00, 0xff, 0xff, 0x2a, 0xf4, 0x2e, 0x60, 0xf8, 0x05, 0x00, - 0x00, + 0x50, 0xa8, 0xc0, 0x26, 0x2d, 0x08, 0x04, 0x02, 0x29, 0x6d, 0x8c, 0x1a, 0x65, 0x69, 0xb2, 0x76, + 0xbc, 0x02, 0x2e, 0x96, 0x63, 0xbf, 0xa6, 0x56, 0x13, 0xcf, 0xc8, 0x33, 0xce, 0xd6, 0xff, 0x01, + 0xca, 0x69, 0x2f, 0x1c, 0x73, 0x42, 0xfc, 0x07, 0x48, 0x9c, 0xb8, 0xaf, 0x38, 0xed, 0x91, 0xd3, + 0x82, 0xda, 0xff, 0x80, 0x1b, 0x37, 0xe4, 0x5f, 0xa9, 0xb7, 0xa9, 0x7a, 0xf3, 0x9b, 0xf7, 0xbe, + 0x37, 0xdf, 0xe7, 0xf7, 0xcd, 0x43, 0x32, 0x9c, 0x13, 0x87, 0x04, 0xa0, 0xba, 0x64, 0x74, 0x42, + 0x88, 0xab, 0x4e, 0x9b, 0xf9, 0xa7, 0x42, 0x03, 0xc2, 0x09, 0xc6, 0x59, 0x85, 0x92, 0x1f, 0x4f, + 0x9b, 0x52, 0x65, 0x44, 0x46, 0x24, 0x49, 0xab, 0xf1, 0x57, 0x5a, 0x29, 0x6d, 0x8d, 0x08, 0x19, + 0x8d, 0x41, 0x4d, 0xa2, 0x61, 0x78, 0xa2, 0xda, 0x7e, 0x94, 0xa5, 0xb6, 0xaf, 0xa7, 0xb8, 0x37, + 0x01, 0xc6, 0xed, 0x09, 0xcd, 0xb1, 0x0e, 0x61, 0x13, 0xc2, 0xac, 0xb4, 0x69, 0x1a, 0x64, 0xa9, + 0x47, 0x1c, 0x7c, 0x17, 0x82, 0x89, 0xe7, 0x73, 0xd5, 0x09, 0x22, 0xca, 0x89, 0x7a, 0x06, 0x51, + 0x9e, 0x7d, 0x3f, 0xad, 0x55, 0x19, 0xb7, 0xcf, 0x3c, 0x7f, 0xa4, 0x4e, 0x9b, 0x43, 0xe0, 0x76, + 0x33, 0x8f, 0xd3, 0xaa, 0xfa, 0xaf, 0x02, 0x12, 0xb5, 0x54, 0xc7, 0x33, 0x7b, 0xec, 0xb9, 0x36, + 0x27, 0x01, 0xae, 0xa2, 0xbb, 0xb6, 0xeb, 0x06, 0xc0, 0x58, 0x55, 0x90, 0x85, 0xc6, 0xba, 0x9e, + 0x87, 0xb8, 0x82, 0xde, 0xa2, 0xe4, 0x39, 0x04, 0xd5, 0x15, 0x59, 0x68, 0x94, 0xf5, 0x34, 0xc0, + 0x36, 0xba, 0x43, 0xc3, 0xe1, 0x19, 0x44, 0xd5, 0xb2, 0x2c, 0x34, 0xd6, 0xf6, 0x2a, 0x4a, 0xaa, + 0x4a, 0xc9, 0x55, 0x29, 0x2d, 0x3f, 0x3a, 0xd8, 0xff, 0xf7, 0xf5, 0xf6, 0xc3, 0xc8, 0x9e, 0x8c, + 0xbf, 0xac, 0x3b, 0xc4, 0x67, 0xe0, 0xb3, 0x90, 0x59, 0x29, 0xae, 0xfe, 0xe7, 0x6f, 0x1f, 0x57, + 0x32, 0x6d, 0xa9, 0x12, 0xa5, 0x1f, 0x0e, 0xbb, 0x10, 0xe9, 0x59, 0xe3, 0xfa, 0x1f, 0x02, 0x7a, + 0xbb, 0x47, 0x21, 0xb0, 0xb9, 0x47, 0x7c, 0x7c, 0x84, 0x36, 0x48, 0x1e, 0x58, 0x3c, 0xa2, 0x90, + 0xf0, 0xdc, 0xd8, 0xdb, 0x51, 0x96, 0x67, 0xa2, 0x2c, 0x60, 0x83, 0x88, 0x82, 0x7e, 0x9f, 0x14, + 0x43, 0xfc, 0x21, 0x12, 0xd3, 0x03, 0x12, 0x58, 0xb9, 0xe6, 0x95, 0x44, 0xf3, 0x83, 0xfc, 0xbc, + 0x95, 0x69, 0xff, 0x0a, 0xdd, 0xa5, 0xe1, 0xd0, 0xba, 0x92, 0xf9, 0x48, 0xb9, 0x1a, 0x40, 0x81, + 0xf6, 0xd8, 0x73, 0xba, 0x10, 0x1d, 0xac, 0xbe, 0x7c, 0xbd, 0x5d, 0x4a, 0xf8, 0x77, 0x21, 0xaa, + 0x6b, 0x08, 0x2d, 0x78, 0x30, 0xfc, 0x39, 0x5a, 0x1d, 0x7b, 0x8c, 0x57, 0x05, 0xb9, 0xdc, 0x58, + 0xdb, 0x7b, 0x7c, 0x2b, 0xeb, 0xac, 0x51, 0x02, 0xa8, 0x7f, 0x80, 0xc4, 0x96, 0xe3, 0x90, 0xd0, + 0xe7, 0x19, 0x2b, 0x60, 0x18, 0x17, 0x9a, 0xad, 0x67, 0x75, 0x0d, 0x84, 0x0f, 0xf3, 0x7f, 0x7c, + 0x7b, 0xe5, 0x47, 0x68, 0xd3, 0xf4, 0x5d, 0x18, 0xc3, 0x28, 0xb9, 0x4d, 0x07, 0x87, 0x04, 0x6e, + 0x17, 0xa2, 0x9b, 0xab, 0x3b, 0x08, 0x2d, 0x6c, 0x12, 0xff, 0x91, 0xa2, 0x8c, 0x1d, 0x25, 0x9b, + 0x60, 0xee, 0xb0, 0xcc, 0x71, 0xca, 0x02, 0xf1, 0x86, 0x94, 0x9f, 0x05, 0xb4, 0x7e, 0x04, 0xb6, + 0x0b, 0x81, 0x11, 0x0e, 0x19, 0x70, 0xfc, 0x05, 0x5a, 0x8d, 0xcd, 0x9f, 0x8c, 0x72, 0x6d, 0x4f, + 0x5a, 0xf2, 0xd0, 0x20, 0x7f, 0x19, 0x07, 0xf7, 0xe2, 0x36, 0x2f, 0xfe, 0xde, 0x16, 0xf4, 0x04, + 0x81, 0x3f, 0x41, 0x15, 0x1f, 0xce, 0xb9, 0x35, 0x5d, 0x50, 0xb3, 0x4e, 0x6d, 0x76, 0x9a, 0x0d, + 0x12, 0xc7, 0xb9, 0x2b, 0xd6, 0x47, 0x36, 0x3b, 0xc5, 0x5b, 0xe8, 0x9e, 0x4d, 0x69, 0x5a, 0x55, + 0xce, 0x2c, 0x4e, 0x69, 0x9c, 0xda, 0xfd, 0x5d, 0x40, 0xf7, 0xdf, 0xb0, 0x0c, 0xfe, 0x14, 0x49, + 0xbd, 0xbe, 0xa6, 0xb7, 0x06, 0x9d, 0xde, 0xb1, 0x35, 0xf8, 0xa1, 0xaf, 0x59, 0xe6, 0xb1, 0xd1, + 0xd7, 0x0e, 0x3b, 0xdf, 0x76, 0xb4, 0xb6, 0x58, 0x92, 0x2a, 0xb3, 0xb9, 0x2c, 0x76, 0x21, 0xea, + 0x51, 0xd3, 0x67, 0x14, 0x1c, 0xef, 0xc4, 0x03, 0x17, 0x7f, 0x83, 0x76, 0xae, 0xa1, 0x5a, 0xed, + 0x76, 0x27, 0x89, 0x7a, 0xba, 0x65, 0xf6, 0xdb, 0xad, 0x81, 0x26, 0x0a, 0xd2, 0xc3, 0xd9, 0x5c, + 0x7e, 0xb7, 0x0b, 0x51, 0xcb, 0x75, 0xbd, 0xf8, 0xc6, 0x5e, 0x60, 0x52, 0xd7, 0xe6, 0x80, 0x77, + 0xd1, 0xe6, 0x35, 0xbc, 0xae, 0x7d, 0xd7, 0x7b, 0xd6, 0x7a, 0x22, 0xae, 0x48, 0x1b, 0xb3, 0xb9, + 0x8c, 0xe2, 0xe7, 0x01, 0x13, 0x32, 0xb5, 0xc7, 0xd2, 0xea, 0x4f, 0xbf, 0xd4, 0x4a, 0xbb, 0xff, + 0x09, 0xe8, 0xc1, 0xd3, 0x10, 0x42, 0xd0, 0x81, 0x85, 0x63, 0x9e, 0x70, 0xff, 0x1a, 0x3d, 0x7e, + 0x6a, 0x6a, 0x66, 0x0c, 0x36, 0xcc, 0x27, 0x83, 0x9b, 0xe8, 0x4b, 0xb3, 0xb9, 0xbc, 0x59, 0xc0, + 0x15, 0x45, 0x7c, 0x86, 0xb6, 0x96, 0xe1, 0x86, 0x79, 0x78, 0xa8, 0x19, 0x86, 0x28, 0x48, 0x9b, + 0xb3, 0xb9, 0x8c, 0x0b, 0x50, 0x23, 0x74, 0x9c, 0xf8, 0xa9, 0xec, 0xa3, 0xea, 0x32, 0x4c, 0xfb, + 0xbe, 0x63, 0x0c, 0x0c, 0x71, 0x45, 0x7a, 0x6f, 0x36, 0x97, 0xdf, 0x29, 0xa0, 0xb4, 0x73, 0x8f, + 0x71, 0x76, 0xf3, 0x5d, 0x89, 0x66, 0xad, 0x2d, 0x96, 0x97, 0xee, 0x4a, 0xb4, 0x83, 0x9b, 0x6a, + 0x3f, 0xe8, 0xbe, 0xbc, 0xa8, 0x09, 0xaf, 0x2e, 0x6a, 0xc2, 0x3f, 0x17, 0x35, 0xe1, 0xc5, 0x65, + 0xad, 0xf4, 0xea, 0xb2, 0x56, 0xfa, 0xeb, 0xb2, 0x56, 0xfa, 0xb1, 0x39, 0xf2, 0xf8, 0x69, 0x38, + 0x54, 0x1c, 0x32, 0x51, 0xb3, 0x4d, 0x77, 0x0c, 0xfc, 0x39, 0x09, 0xce, 0xd4, 0x7c, 0xc5, 0x9f, + 0x2f, 0x96, 0x7c, 0xbc, 0x4b, 0xd8, 0xf0, 0x4e, 0xe2, 0xb9, 0xfd, 0xff, 0x03, 0x00, 0x00, 0xff, + 0xff, 0x41, 0xe1, 0x03, 0x2c, 0x04, 0x06, 0x00, 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { @@ -796,7 +795,7 @@ func (m *ConsensusAddresses) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *RecordKeys) Marshal() (dAtA []byte, err error) { +func (m *UndelegationRecordKeys) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -806,12 +805,12 @@ func (m *RecordKeys) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *RecordKeys) MarshalTo(dAtA []byte) (int, error) { +func (m *UndelegationRecordKeys) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *RecordKeys) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *UndelegationRecordKeys) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -1004,7 +1003,7 @@ func (m *ConsensusAddresses) Size() (n int) { return n } -func (m *RecordKeys) Size() (n int) { +func (m *UndelegationRecordKeys) Size() (n int) { if m == nil { return 0 } @@ -1582,7 +1581,7 @@ func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { } return nil } -func (m *RecordKeys) Unmarshal(dAtA []byte) error { +func (m *UndelegationRecordKeys) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1605,10 +1604,10 @@ func (m *RecordKeys) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: RecordKeys: wiretype end group for non-group") + return fmt.Errorf("proto: UndelegationRecordKeys: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: RecordKeys: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: UndelegationRecordKeys: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: From 061ec1365075f6ec5064d242c60826f96a1a8c8b Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 26 Feb 2024 19:55:05 +0000 Subject: [PATCH 18/32] doc(dogfood): update comments in EndBlock ...and refactor getters / setters to `pending.go`. --- x/dogfood/keeper/abci.go | 136 ++---------------------------------- x/dogfood/keeper/pending.go | 132 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 130 deletions(-) create mode 100644 x/dogfood/keeper/pending.go diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go index 4b6fcb36c..01750e969 100644 --- a/x/dogfood/keeper/abci.go +++ b/x/dogfood/keeper/abci.go @@ -7,19 +7,21 @@ import ( ) func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { - // start with undelegations + // start with clearing the hold on the undelegations. undelegations := k.GetPendingUndelegations(ctx) for _, undelegation := range undelegations.GetList() { k.delegationKeeper.DecrementUndelegationHoldCount(ctx, undelegation) } k.ClearPendingUndelegations(ctx) - // then opt outs (consensus addresses should be done after opt out) + // then, let the operator module know that the opt out has finished. optOuts := k.GetPendingOptOuts(ctx) for _, addr := range optOuts.GetList() { k.operatorKeeper.CompleteOperatorOptOutFromChainId(ctx, addr, ctx.ChainID()) } k.ClearPendingOptOuts(ctx) - // then consensus addresses + // for slashing, the operator module is required to store a mapping of chain id + cons addr + // to operator address. this information can now be pruned, since the opt out is considered + // complete. consensusAddrs := k.GetPendingConsensusAddrs(ctx) for _, consensusAddr := range consensusAddrs.GetList() { k.operatorKeeper.DeleteOperatorAddressForChainIdAndConsAddr( @@ -27,7 +29,7 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { ) } k.ClearPendingConsensusAddrs(ctx) - // finally, operations + // finally, perform the actual operations of vote power changes. operations := k.GetPendingOperations(ctx) res := make([]abci.ValidatorUpdate, 0, len(operations.GetList())) for _, operation := range operations.GetList() { @@ -54,129 +56,3 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { } return res } - -// SetPendingOperations sets the pending operations to be applied at the end of the block. -func (k Keeper) SetPendingOperations(ctx sdk.Context, operations types.Operations) { - store := ctx.KVStore(k.storeKey) - bz, err := operations.Marshal() - if err != nil { - panic(err) - } - store.Set(types.PendingOperationsKey(), bz) -} - -// GetPendingOperations returns the pending operations to be applied at the end of the block. -func (k Keeper) GetPendingOperations(ctx sdk.Context) types.Operations { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingOperationsKey()) - if bz == nil { - return types.Operations{} - } - var operations types.Operations - if err := operations.Unmarshal(bz); err != nil { - panic(err) - } - return operations -} - -// ClearPendingOperations clears the pending operations to be applied at the end of the block. -func (k Keeper) ClearPendingOperations(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingOperationsKey()) -} - -// SetPendingOptOuts sets the pending opt-outs to be applied at the end of the block. -func (k Keeper) SetPendingOptOuts(ctx sdk.Context, addrs types.AccountAddresses) { - store := ctx.KVStore(k.storeKey) - bz, err := addrs.Marshal() - if err != nil { - panic(err) - } - store.Set(types.PendingOptOutsKey(), bz) -} - -// GetPendingOptOuts returns the pending opt-outs to be applied at the end of the block. -func (k Keeper) GetPendingOptOuts(ctx sdk.Context) types.AccountAddresses { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingOptOutsKey()) - if bz == nil { - return types.AccountAddresses{} - } - var addrs types.AccountAddresses - if err := addrs.Unmarshal(bz); err != nil { - panic(err) - } - return addrs -} - -// ClearPendingOptOuts clears the pending opt-outs to be applied at the end of the block. -func (k Keeper) ClearPendingOptOuts(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingOptOutsKey()) -} - -// SetPendingConsensusAddrs sets the pending consensus addresses to be pruned at the end of the -// block. -func (k Keeper) SetPendingConsensusAddrs(ctx sdk.Context, addrs types.ConsensusAddresses) { - store := ctx.KVStore(k.storeKey) - bz, err := addrs.Marshal() - if err != nil { - panic(err) - } - store.Set(types.PendingConsensusAddrsKey(), bz) -} - -// GetPendingConsensusAddrs returns the pending consensus addresses to be pruned at the end of -// the block. -func (k Keeper) GetPendingConsensusAddrs(ctx sdk.Context) types.ConsensusAddresses { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingConsensusAddrsKey()) - if bz == nil { - return types.ConsensusAddresses{} - } - var addrs types.ConsensusAddresses - if err := addrs.Unmarshal(bz); err != nil { - panic(err) - } - return addrs -} - -// ClearPendingConsensusAddrs clears the pending consensus addresses to be pruned at the end of -// the block. -func (k Keeper) ClearPendingConsensusAddrs(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingConsensusAddrsKey()) -} - -// SetPendingUndelegations sets the pending undelegations to be released at the end of the -// block. -func (k Keeper) SetPendingUndelegations(ctx sdk.Context, undelegations types.UndelegationRecordKeys) { - store := ctx.KVStore(k.storeKey) - bz, err := undelegations.Marshal() - if err != nil { - panic(err) - } - store.Set(types.PendingUndelegationsKey(), bz) -} - -// GetPendingUndelegations returns the pending undelegations to be released at the end of the -// block. -func (k Keeper) GetPendingUndelegations(ctx sdk.Context) types.UndelegationRecordKeys { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingUndelegationsKey()) - if bz == nil { - return types.UndelegationRecordKeys{} - } - var undelegations types.UndelegationRecordKeys - if err := undelegations.Unmarshal(bz); err != nil { - panic(err) - } - return undelegations -} - -// ClearPendingUndelegations clears the pending undelegations to be released at the end of the -// block. -func (k Keeper) ClearPendingUndelegations(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingUndelegationsKey()) -} diff --git a/x/dogfood/keeper/pending.go b/x/dogfood/keeper/pending.go new file mode 100644 index 000000000..7d68779f8 --- /dev/null +++ b/x/dogfood/keeper/pending.go @@ -0,0 +1,132 @@ +package keeper + +import ( + "github.com/ExocoreNetwork/exocore/x/dogfood/types" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// SetPendingOperations sets the pending operations to be applied at the end of the block. +func (k Keeper) SetPendingOperations(ctx sdk.Context, operations types.Operations) { + store := ctx.KVStore(k.storeKey) + bz, err := operations.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingOperationsKey(), bz) +} + +// GetPendingOperations returns the pending operations to be applied at the end of the block. +func (k Keeper) GetPendingOperations(ctx sdk.Context) types.Operations { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingOperationsKey()) + if bz == nil { + return types.Operations{} + } + var operations types.Operations + if err := operations.Unmarshal(bz); err != nil { + panic(err) + } + return operations +} + +// ClearPendingOperations clears the pending operations to be applied at the end of the block. +func (k Keeper) ClearPendingOperations(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingOperationsKey()) +} + +// SetPendingOptOuts sets the pending opt-outs to be applied at the end of the block. +func (k Keeper) SetPendingOptOuts(ctx sdk.Context, addrs types.AccountAddresses) { + store := ctx.KVStore(k.storeKey) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingOptOutsKey(), bz) +} + +// GetPendingOptOuts returns the pending opt-outs to be applied at the end of the block. +func (k Keeper) GetPendingOptOuts(ctx sdk.Context) types.AccountAddresses { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingOptOutsKey()) + if bz == nil { + return types.AccountAddresses{} + } + var addrs types.AccountAddresses + if err := addrs.Unmarshal(bz); err != nil { + panic(err) + } + return addrs +} + +// ClearPendingOptOuts clears the pending opt-outs to be applied at the end of the block. +func (k Keeper) ClearPendingOptOuts(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingOptOutsKey()) +} + +// SetPendingConsensusAddrs sets the pending consensus addresses to be pruned at the end of the +// block. +func (k Keeper) SetPendingConsensusAddrs(ctx sdk.Context, addrs types.ConsensusAddresses) { + store := ctx.KVStore(k.storeKey) + bz, err := addrs.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingConsensusAddrsKey(), bz) +} + +// GetPendingConsensusAddrs returns the pending consensus addresses to be pruned at the end of +// the block. +func (k Keeper) GetPendingConsensusAddrs(ctx sdk.Context) types.ConsensusAddresses { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingConsensusAddrsKey()) + if bz == nil { + return types.ConsensusAddresses{} + } + var addrs types.ConsensusAddresses + if err := addrs.Unmarshal(bz); err != nil { + panic(err) + } + return addrs +} + +// ClearPendingConsensusAddrs clears the pending consensus addresses to be pruned at the end of +// the block. +func (k Keeper) ClearPendingConsensusAddrs(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingConsensusAddrsKey()) +} + +// SetPendingUndelegations sets the pending undelegations to be released at the end of the +// block. +func (k Keeper) SetPendingUndelegations(ctx sdk.Context, undelegations types.UndelegationRecordKeys) { + store := ctx.KVStore(k.storeKey) + bz, err := undelegations.Marshal() + if err != nil { + panic(err) + } + store.Set(types.PendingUndelegationsKey(), bz) +} + +// GetPendingUndelegations returns the pending undelegations to be released at the end of the +// block. +func (k Keeper) GetPendingUndelegations(ctx sdk.Context) types.UndelegationRecordKeys { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PendingUndelegationsKey()) + if bz == nil { + return types.UndelegationRecordKeys{} + } + var undelegations types.UndelegationRecordKeys + if err := undelegations.Unmarshal(bz); err != nil { + panic(err) + } + return undelegations +} + +// ClearPendingUndelegations clears the pending undelegations to be released at the end of the +// block. +func (k Keeper) ClearPendingUndelegations(ctx sdk.Context) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.PendingUndelegationsKey()) +} From ba3b5d89763e179c6976ad525a8c19bc812ac6d1 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:16:08 +0000 Subject: [PATCH 19/32] fix(dogfood): clear validator set only if unused --- x/dogfood/keeper/validators.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index 15c5d229b..d53a88d58 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -223,9 +223,9 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { break } } - // contract: TrackHistoricalInfo must be called after storing the validator set - // for the current block. - currentID, _ := k.GetValidatorSetID(ctx, ctx.BlockHeight()) + currentID, _ := k.GetValidatorSetID( + ctx, ctx.BlockHeight()-int64(numHistoricalEntries)+1, + ) for i := lastDeletedID; i < currentID; i++ { k.DeleteValidatorSet(ctx, i) } From 8e9dec2d034cbac50e4434b431dfcde3a5fe3c8d Mon Sep 17 00:00:00 2001 From: Max <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:32:40 +0530 Subject: [PATCH 20/32] feat(dogfood): implement sdk staking interface (#123) * feat(dogfood): implement sdk staking interface The interface required by IBC was already implemented in `validators.go`. This PR takes that a step further and implements the interfaces required to use the dogfood module as a drop-in replacement for the SDK's staking module. The interfaces implemented are those expected by the slashing, evidence and `genutil` modules. An explanation has been provided above each function to explain why and where it is called, and if its implementation is really necessary. There are still some TODOs left in this PR that depend on the overall slashing / operator design. This branch is merged into dogfood-part6, which forms the basis of #122. * fix(dogfood): store val set id + val set at genesis, the val set id starts with 1. each time the validator set changes, the val set id of the current block is retrieved. for the next block, the val set is is stored as this id + 1. * fix(dogfood): increment val set id correctly in the case of genesis, we should not use height + 1 as the key in the mapping; rather, it should be height. in all other cases, the mapping key is height + 1. the value is the val set id in all cases. --- x/dogfood/keeper/abci.go | 11 +- x/dogfood/keeper/genesis.go | 3 +- x/dogfood/keeper/impl_sdk.go | 171 ++++++++++++++++++++++++++++ x/dogfood/keeper/keeper.go | 3 + x/dogfood/keeper/validators.go | 35 +++++- x/dogfood/types/expected_keepers.go | 15 +++ x/dogfood/types/keys.go | 3 + 7 files changed, 233 insertions(+), 8 deletions(-) create mode 100644 x/dogfood/keeper/impl_sdk.go diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go index 01750e969..30dd3950b 100644 --- a/x/dogfood/keeper/abci.go +++ b/x/dogfood/keeper/abci.go @@ -31,6 +31,13 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { k.ClearPendingConsensusAddrs(ctx) // finally, perform the actual operations of vote power changes. operations := k.GetPendingOperations(ctx) + id, _ := k.GetValidatorSetID(ctx, ctx.BlockHeight()) + if len(operations.GetList()) == 0 { + // there is no validator set change, so we just increment the block height + // and retain the same val set id mapping. + k.SetValidatorSetID(ctx, ctx.BlockHeight()+1, id) + return []abci.ValidatorUpdate{} + } res := make([]abci.ValidatorUpdate, 0, len(operations.GetList())) for _, operation := range operations.GetList() { switch operation.OperationType { @@ -54,5 +61,7 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { panic("unspecified operation type") } } - return res + // call via wrapper function so that validator info is stored. + // the id is incremented by 1 for the next block. + return k.ApplyValidatorChanges(ctx, res, id+1, false) } diff --git a/x/dogfood/keeper/genesis.go b/x/dogfood/keeper/genesis.go index 16f51892b..e0544924d 100644 --- a/x/dogfood/keeper/genesis.go +++ b/x/dogfood/keeper/genesis.go @@ -20,9 +20,8 @@ func (k Keeper) InitGenesis( // the panic is suitable here because it is being done at genesis, when the node // is not running. it means that the genesis file is malformed. panic("epoch info not found") - } - return k.ApplyValidatorChanges(ctx, genState.ValSet) + return k.ApplyValidatorChanges(ctx, genState.ValSet, types.InitialValidatorSetID, true) } // ExportGenesis returns the module's exported genesis diff --git a/x/dogfood/keeper/impl_sdk.go b/x/dogfood/keeper/impl_sdk.go new file mode 100644 index 000000000..547f526e7 --- /dev/null +++ b/x/dogfood/keeper/impl_sdk.go @@ -0,0 +1,171 @@ +package keeper + +import ( + "cosmossdk.io/math" + abci "github.com/cometbft/cometbft/abci/types" + sdk "github.com/cosmos/cosmos-sdk/types" + evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" +) + +// interface guards +var _ slashingtypes.StakingKeeper = Keeper{} +var _ evidencetypes.StakingKeeper = Keeper{} +var _ genutiltypes.StakingKeeper = Keeper{} +var _ clienttypes.StakingKeeper = Keeper{} // implemented in `validators.go` + +// GetParams is an implementation of the staking interface expected by the SDK's evidence +// module. The module does not use it, but it is part of the interface. +func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params { + return stakingtypes.Params{} +} + +// IterateValidators is an implementation of the staking interface expected by the SDK's +// slashing module. The slashing module uses it for two purposes: once at genesis to +// store a mapping of pub key to cons address (which is done by our operator module), +// and then during the invariants check to ensure that the total delegated amount +// matches that of each validator. Ideally, this invariant should be implemented +// by the delegation and/or deposit module(s) instead. +func (k Keeper) IterateValidators(sdk.Context, + func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { + // no op +} + +// Validator is an implementation of the staking interface expected by the SDK's +// slashing module. The slashing module uses it to obtain a validator's information at +// its addition to the list of validators, and then to unjail a validator. The former +// is used to create the pub key to cons address mapping, which we do in the operator module. +// The latter should also be implemented in the operator module, or maybe the slashing module +// depending upon the finalized design. We don't need to implement this function here because +// we are not calling the AfterValidatorCreated hook in our module, so this will never be +// reached. +func (k Keeper) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI { + panic("unimplemented on this keeper") +} + +// ValidatorByConsAddr is an implementation of the staking interface expected by the SDK's +// slashing and evidence modules. +// The slashing module calls this function when it observes downtime. The only requirement on +// the returned value is that it isn't nil, and the jailed status is accurately set (to prevent +// re-jailing of the same operator). +// The evidence module calls this function when it handles equivocation evidence. The returned +// value must not be nil and must not have an UNBONDED validator status (the default is +// unspecified), or evidence will reject it. +func (k Keeper) ValidatorByConsAddr( + ctx sdk.Context, + addr sdk.ConsAddress, +) stakingtypes.ValidatorI { + found, accAddr := k.operatorKeeper.GetOperatorAddressForChainIdAndConsAddr( + ctx, ctx.ChainID(), addr, + ) + if !found { + // replicate the behavior of the SDK's staking module + return nil + } + return stakingtypes.Validator{ + Jailed: k.operatorKeeper.IsOperatorJailedForChainId(ctx, accAddr, ctx.ChainID()), + } +} + +// Slash is an implementation of the staking interface expected by the SDK's slashing module. +// It forwards the call to SlashWithInfractionReason with Infraction_INFRACTION_UNSPECIFIED. +// It is not called within the slashing module, but is part of the interface. +func (k Keeper) Slash( + ctx sdk.Context, addr sdk.ConsAddress, + infractionHeight, power int64, + slashFactor sdk.Dec, +) math.Int { + return k.SlashWithInfractionReason( + ctx, addr, infractionHeight, power, + slashFactor, stakingtypes.Infraction_INFRACTION_UNSPECIFIED, + ) +} + +// SlashWithInfractionReason is an implementation of the staking interface expected by the +// SDK's slashing module. It is called when the slashing module observes an infraction +// of either downtime or equivocation (which is via the evidence module). +func (k Keeper) SlashWithInfractionReason( + ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, + slashFactor sdk.Dec, infraction stakingtypes.Infraction, +) math.Int { + found, accAddress := k.operatorKeeper.GetOperatorAddressForChainIdAndConsAddr( + ctx, ctx.ChainID(), addr, + ) + if !found { + // TODO(mm): already slashed and removed from the set? + return math.NewInt(0) + } + // TODO(mm): add list of assets to be slashed (and not just all of them). + // based on yet to be finalized slashing design. + return k.slashingKeeper.SlashWithInfractionReason( + ctx, accAddress, infractionHeight, + power, slashFactor, infraction, + ) +} + +// Jail is an implementation of the staking interface expected by the SDK's slashing module. +// It delegates the call to the operator module. Alternatively, this may be handled +// by the slashing module depending upon the design decisions. +func (k Keeper) Jail(ctx sdk.Context, addr sdk.ConsAddress) { + k.operatorKeeper.Jail(ctx, addr, ctx.ChainID()) + // TODO(mm) + // once the operator module jails someone, a hook should be triggered + // and the validator removed from the set. same for unjailing. +} + +// Unjail is an implementation of the staking interface expected by the SDK's slashing module. +// The function is called by the slashing module only when it receives a request from the +// operator to do so. TODO(mm): We need to use the SDK's slashing module to allow for downtime +// slashing but somehow we need to prevent its Unjail function from being called by anyone. +func (k Keeper) Unjail(sdk.Context, sdk.ConsAddress) { + panic("unimplemented on this keeper") +} + +// Delegation is an implementation of the staking interface expected by the SDK's slashing +// module. The slashing module uses it to obtain the delegation information of a validator +// before unjailing it. If the slashing module's unjail function is never called, this +// function will never be called either. +func (k Keeper) Delegation( + sdk.Context, sdk.AccAddress, sdk.ValAddress, +) stakingtypes.DelegationI { + panic("unimplemented on this keeper") +} + +// MaxValidators is an implementation of the staking interface expected by the SDK's slashing +// module. It is not called within the slashing module, but is part of the interface. +// It returns the maximum number of validators allowed in the network. +func (k Keeper) MaxValidators(ctx sdk.Context) uint32 { + return k.GetMaxValidators(ctx) +} + +// GetAllValidators is an implementation of the staking interface expected by the SDK's +// slashing module. It is not called within the slashing module, but is part of the interface. +func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Validator) { + return []stakingtypes.Validator{} +} + +// IsValidatorJailed is an implementation of the staking interface expected by the SDK's +// slashing module. It is called by the slashing module to record validator signatures +// for downtime tracking. We delegate the call to the operator keeper. +func (k Keeper) IsValidatorJailed(ctx sdk.Context, addr sdk.ConsAddress) bool { + found, accAddr := k.operatorKeeper.GetOperatorAddressForChainIdAndConsAddr( + ctx, ctx.ChainID(), addr, + ) + if !found { + // replicate the behavior of the SDK's staking module + return false + } + return k.operatorKeeper.IsOperatorJailedForChainId(ctx, accAddr, ctx.ChainID()) +} + +// ApplyAndReturnValidatorSetUpdates is an implementation of the staking interface expected +// by the SDK's genutil module. It is used in the gentx command, which we do not need to +// support. So this function does nothing. +func (k Keeper) ApplyAndReturnValidatorSetUpdates( + sdk.Context, +) (updates []abci.ValidatorUpdate, err error) { + return +} diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index 103d60c97..e85f961d0 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -26,6 +26,7 @@ type ( operatorKeeper types.OperatorKeeper delegationKeeper types.DelegationKeeper restakingKeeper types.RestakingKeeper + slashingKeeper types.SlashingKeeper } ) @@ -38,6 +39,7 @@ func NewKeeper( operatorKeeper types.OperatorKeeper, delegationKeeper types.DelegationKeeper, restakingKeeper types.RestakingKeeper, + slashingKeeper types.SlashingKeeper, ) *Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -52,6 +54,7 @@ func NewKeeper( operatorKeeper: operatorKeeper, delegationKeeper: delegationKeeper, restakingKeeper: restakingKeeper, + slashingKeeper: slashingKeeper, } } diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index d53a88d58..c41b7ba22 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -31,10 +31,10 @@ func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration { // ApplyValidatorChanges returns the validator set as is. However, it also // stores the validators that are added or those that are removed, and updates // the power for the existing validators. It also allows any hooks registered -// on the keeper to be executed. +// on the keeper to be executed. Lastly, it stores the validator set against the +// provided validator set id. func (k Keeper) ApplyValidatorChanges( - ctx sdk.Context, - changes []abci.ValidatorUpdate, + ctx sdk.Context, changes []abci.ValidatorUpdate, valSetID uint64, genesis bool, ) []abci.ValidatorUpdate { ret := []abci.ValidatorUpdate{} for _, change := range changes { @@ -42,7 +42,7 @@ func (k Keeper) ApplyValidatorChanges( pubkey, err := cryptocodec.FromTmProtoPublicKey(change.GetPubKey()) if err != nil { // An error here would indicate that the validator updates - // received from other modules are invalid. + // received from other modules (or genesis) are invalid. panic(err) } addr := pubkey.Address() @@ -79,9 +79,34 @@ func (k Keeper) ApplyValidatorChanges( // to tendermint. continue } - ret = append(ret, change) } + + // store the validator set against the provided validator set id + lastVals := types.Validators{} + for _, v := range k.GetAllExocoreValidators(ctx) { + pubkey, err := v.ConsPubKey() + if err != nil { + panic(err) + } + val, err := stakingtypes.NewValidator(nil, pubkey, stakingtypes.Description{}) + if err != nil { + panic(err) + } + // Set validator to bonded status + val.Status = stakingtypes.Bonded + // Compute tokens from voting power + val.Tokens = sdk.TokensFromConsensusPower(v.Power, sdk.DefaultPowerReduction) + lastVals.List = append(lastVals.GetList(), val) + } + k.SetValidatorSet(ctx, valSetID, &lastVals) + if !genesis { + // the val set change is effective as of the next block, so height + 1. + k.SetValidatorSetID(ctx, ctx.BlockHeight()+1, valSetID) + } else { + // the val set change is effective immediately. + k.SetValidatorSetID(ctx, ctx.BlockHeight(), valSetID) + } return ret } diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index 9dfd255ea..06ca74df4 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -1,8 +1,10 @@ package types import ( + "cosmossdk.io/math" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" epochsTypes "github.com/evmos/evmos/v14/x/epochs/types" ) @@ -48,6 +50,11 @@ type OperatorKeeper interface { ) bool CompleteOperatorOptOutFromChainId(sdk.Context, sdk.AccAddress, string) DeleteOperatorAddressForChainIdAndConsAddr(sdk.Context, string, sdk.ConsAddress) + GetOperatorAddressForChainIdAndConsAddr( + sdk.Context, string, sdk.ConsAddress, + ) (bool, sdk.AccAddress) + IsOperatorJailedForChainId(sdk.Context, sdk.AccAddress, string) bool + Jail(sdk.Context, sdk.ConsAddress, string) } // DelegationKeeper represents the expected keeper interface for the delegation module. @@ -66,3 +73,11 @@ type EpochsHooks interface { type RestakingKeeper interface { GetOperatorAssetValue(sdk.Context, sdk.AccAddress) (int64, error) } + +// SlashingKeeper represents the expected keeper interface for the (exo-)slashing module. +type SlashingKeeper interface { + SlashWithInfractionReason( + sdk.Context, sdk.AccAddress, int64, + int64, sdk.Dec, stakingtypes.Infraction, + ) math.Int +} diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 15e3fda9f..6397e1796 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -12,6 +12,9 @@ const ( StoreKey = ModuleName ) +// InitialValidatorSetID is the initial validator set id. +const InitialValidatorSetID = uint64(1) + const ( // ExocoreValidatorBytePrefix is the prefix for the validator store. ExocoreValidatorBytePrefix byte = iota + 1 From 3a5d824b52ee4f58cd6899d4c8bf3c3dcccca365 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:25:30 +0000 Subject: [PATCH 21/32] chore(lint): apply to dogfood --- x/dogfood/client/cli/query.go | 3 +- x/dogfood/keeper/impl_epochs_hooks.go | 2 +- x/dogfood/keeper/impl_sdk.go | 19 ++++++----- x/dogfood/keeper/queue.go | 6 ++-- x/dogfood/keeper/validators.go | 49 +++++++++++++++------------ x/dogfood/module.go | 9 +++-- x/dogfood/types/codec.go | 2 +- 7 files changed, 51 insertions(+), 39 deletions(-) diff --git a/x/dogfood/client/cli/query.go b/x/dogfood/client/cli/query.go index a4dfc065d..a1f193d8d 100644 --- a/x/dogfood/client/cli/query.go +++ b/x/dogfood/client/cli/query.go @@ -8,6 +8,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + // "github.com/cosmos/cosmos-sdk/client/flags" // sdk "github.com/cosmos/cosmos-sdk/types" @@ -15,7 +16,7 @@ import ( ) // GetQueryCmd returns the cli query commands for this module -func GetQueryCmd(queryRoute string) *cobra.Command { +func GetQueryCmd(string) *cobra.Command { // Group dogfood queries under a subcommand cmd := &cobra.Command{ Use: types.ModuleName, diff --git a/x/dogfood/keeper/impl_epochs_hooks.go b/x/dogfood/keeper/impl_epochs_hooks.go index af7cc5267..c17314a89 100644 --- a/x/dogfood/keeper/impl_epochs_hooks.go +++ b/x/dogfood/keeper/impl_epochs_hooks.go @@ -54,7 +54,7 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( // BeforeEpochStart is called before an epoch starts. func (wrapper EpochsHooksWrapper) BeforeEpochStart( - ctx sdk.Context, identifier string, epoch int64, + sdk.Context, string, int64, ) { // nothing to do } diff --git a/x/dogfood/keeper/impl_sdk.go b/x/dogfood/keeper/impl_sdk.go index 547f526e7..a019bff2a 100644 --- a/x/dogfood/keeper/impl_sdk.go +++ b/x/dogfood/keeper/impl_sdk.go @@ -12,14 +12,16 @@ import ( ) // interface guards -var _ slashingtypes.StakingKeeper = Keeper{} -var _ evidencetypes.StakingKeeper = Keeper{} -var _ genutiltypes.StakingKeeper = Keeper{} -var _ clienttypes.StakingKeeper = Keeper{} // implemented in `validators.go` +var ( + _ slashingtypes.StakingKeeper = Keeper{} + _ evidencetypes.StakingKeeper = Keeper{} + _ genutiltypes.StakingKeeper = Keeper{} + _ clienttypes.StakingKeeper = Keeper{} // implemented in `validators.go` +) // GetParams is an implementation of the staking interface expected by the SDK's evidence // module. The module does not use it, but it is part of the interface. -func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params { +func (k Keeper) GetParams(sdk.Context) stakingtypes.Params { return stakingtypes.Params{} } @@ -30,7 +32,8 @@ func (k Keeper) GetParams(ctx sdk.Context) stakingtypes.Params { // matches that of each validator. Ideally, this invariant should be implemented // by the delegation and/or deposit module(s) instead. func (k Keeper) IterateValidators(sdk.Context, - func(index int64, validator stakingtypes.ValidatorI) (stop bool)) { + func(index int64, validator stakingtypes.ValidatorI) (stop bool), +) { // no op } @@ -42,7 +45,7 @@ func (k Keeper) IterateValidators(sdk.Context, // depending upon the finalized design. We don't need to implement this function here because // we are not calling the AfterValidatorCreated hook in our module, so this will never be // reached. -func (k Keeper) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI { +func (k Keeper) Validator(sdk.Context, sdk.ValAddress) stakingtypes.ValidatorI { panic("unimplemented on this keeper") } @@ -143,7 +146,7 @@ func (k Keeper) MaxValidators(ctx sdk.Context) uint32 { // GetAllValidators is an implementation of the staking interface expected by the SDK's // slashing module. It is not called within the slashing module, but is part of the interface. -func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []stakingtypes.Validator) { +func (k Keeper) GetAllValidators(sdk.Context) (validators []stakingtypes.Validator) { return []stakingtypes.Validator{} } diff --git a/x/dogfood/keeper/queue.go b/x/dogfood/keeper/queue.go index 591962d5f..07cedfb32 100644 --- a/x/dogfood/keeper/queue.go +++ b/x/dogfood/keeper/queue.go @@ -25,10 +25,10 @@ func (k Keeper) QueueOperation( if operation.PubKey.Equal(key) { if operation.OperationType == operationType { return types.QueueResultExists - } else { - indexToDelete = i - break } + // reverse operation exists, remove it + indexToDelete = i + break } } ret := types.QueueResultSuccess diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index c41b7ba22..bdfc529d6 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -48,7 +48,8 @@ func (k Keeper) ApplyValidatorChanges( addr := pubkey.Address() val, found := k.GetValidator(ctx, addr) - if found { + switch found { + case true: // update or delete an existing validator if change.Power < 1 { k.DeleteValidator(ctx, addr) @@ -56,28 +57,32 @@ func (k Keeper) ApplyValidatorChanges( val.Power = change.Power k.SetValidator(ctx, val) } - } else if change.Power > 0 { - // create a new validator - the address is just derived from the public key and has - // no correlation with the operator address on Exocore - ocVal, err := types.NewExocoreValidator(addr, change.Power, pubkey) - if err != nil { - // An error here would indicate that the validator updates - // received are invalid. - panic(err) - } - - k.SetValidator(ctx, ocVal) - err = k.Hooks().AfterValidatorBonded(ctx, sdk.ConsAddress(addr), nil) - if err != nil { - // AfterValidatorBonded is hooked by the Slashing module and should not return - // an error. If any other module were to hook it, they should also not. - panic(err) + case false: + if change.Power > 0 { + // create a new validator - the address is just derived from the public key and + // has + // no correlation with the operator address on Exocore + ocVal, err := types.NewExocoreValidator(addr, change.Power, pubkey) + if err != nil { + // An error here would indicate that the validator updates + // received are invalid. + panic(err) + } + + k.SetValidator(ctx, ocVal) + err = k.Hooks().AfterValidatorBonded(ctx, sdk.ConsAddress(addr), nil) + if err != nil { + // AfterValidatorBonded is hooked by the Slashing module and should not + // return + // an error. If any other module were to hook it, they should also not. + panic(err) + } + } else { + // edge case: we received an update for 0 power + // but the validator is already deleted. Do not forward + // to tendermint. + continue } - } else { - // edge case: we received an update for 0 power - // but the validator is already deleted. Do not forward - // to tendermint. - continue } ret = append(ret, change) } diff --git a/x/dogfood/module.go b/x/dogfood/module.go index 50d02a5d0..44483fd37 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -56,7 +56,7 @@ func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { types.RegisterInterfaces(reg) } -// DefaultGenesis returns a default GenesisState for the module, marshalled to json.RawMessage. +// DefaultGenesis returns a default GenesisState for the module, marshaled to json.RawMessage. // The default GenesisState need to be defined by the module developer and is primarily used for // testing func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { @@ -66,7 +66,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { // ValidateGenesis used to validate the GenesisState, given in its json.RawMessage form func (AppModuleBasic) ValidateGenesis( cdc codec.JSONCodec, - config client.TxEncodingConfig, + _ client.TxEncodingConfig, bz json.RawMessage, ) error { var genState types.GenesisState @@ -81,7 +81,10 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes( clientCtx client.Context, mux *runtime.ServeMux, ) { - types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)) + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + // this panic is safe to do because it means an error in setting up the module. + panic(err) + } } // GetTxCmd returns the root Tx command for the module. The subcommands of this root command are diff --git a/x/dogfood/types/codec.go b/x/dogfood/types/codec.go index b70e2a444..3fb01c133 100644 --- a/x/dogfood/types/codec.go +++ b/x/dogfood/types/codec.go @@ -6,7 +6,7 @@ import ( "github.com/cosmos/cosmos-sdk/types/msgservice" ) -func RegisterCodec(cdc *codec.LegacyAmino) { +func RegisterCodec(*codec.LegacyAmino) { } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { From ded8f3f2245d71d30253fd039bf2ef3f67733017 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:37:26 +0000 Subject: [PATCH 22/32] doc(dogfood): update minor comment --- x/dogfood/keeper/impl_sdk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/dogfood/keeper/impl_sdk.go b/x/dogfood/keeper/impl_sdk.go index a019bff2a..936e7c2cb 100644 --- a/x/dogfood/keeper/impl_sdk.go +++ b/x/dogfood/keeper/impl_sdk.go @@ -65,7 +65,7 @@ func (k Keeper) ValidatorByConsAddr( ctx, ctx.ChainID(), addr, ) if !found { - // replicate the behavior of the SDK's staking module + // replicate the behavior of the SDK's staking module; do not panic. return nil } return stakingtypes.Validator{ From 84a8037b615bd5dfea885c61b3867e72fa390a09 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:45:52 +0000 Subject: [PATCH 23/32] chore(build): attempt to fix consensuswarn --- .github/workflows/consensuswarn.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/consensuswarn.yml b/.github/workflows/consensuswarn.yml index ab2ba53bf..7662e31d5 100644 --- a/.github/workflows/consensuswarn.yml +++ b/.github/workflows/consensuswarn.yml @@ -18,4 +18,4 @@ jobs: - uses: orijtech/consensuswarn@main with: # example.com/pkg/path.Type.Method - roots: 'github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.DeliverTx,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.BeginBlocker,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.EndBlocker' + roots: 'github.com/ExocoreNetwork/exocore/app.ExocoreApp.DeliverTx,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BeginBlocker,github.com/ExocoreNetwork/exocore/app.ExocoreApp.EndBlocker' From 0debcab680c433a28aec6d606447493eb5524534 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:48:17 +0000 Subject: [PATCH 24/32] Revert "chore(build): attempt to fix consensuswarn This reverts commit 84a8037b615bd5dfea885c61b3867e72fa390a09. --- .github/workflows/consensuswarn.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/consensuswarn.yml b/.github/workflows/consensuswarn.yml index 7662e31d5..ab2ba53bf 100644 --- a/.github/workflows/consensuswarn.yml +++ b/.github/workflows/consensuswarn.yml @@ -18,4 +18,4 @@ jobs: - uses: orijtech/consensuswarn@main with: # example.com/pkg/path.Type.Method - roots: 'github.com/ExocoreNetwork/exocore/app.ExocoreApp.DeliverTx,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BeginBlocker,github.com/ExocoreNetwork/exocore/app.ExocoreApp.EndBlocker' + roots: 'github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.DeliverTx,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.BeginBlocker,github.com/ExocoreNetwork/exocore/app.ExocoreApp.BaseApp.EndBlocker' From 8258c4617221d4aedd4b30bddb3838f09cf71cf0 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:54:36 +0000 Subject: [PATCH 25/32] chore(build): respond to gosec comments --- x/dogfood/keeper/abci.go | 10 ++- x/dogfood/keeper/opt_out.go | 20 +++-- x/dogfood/keeper/pending.go | 28 +++---- x/dogfood/keeper/unbonding.go | 8 +- x/dogfood/keeper/validators.go | 142 ++++++++++++++++++--------------- x/dogfood/types/keys.go | 63 ++++++++++++--- x/dogfood/types/params.go | 5 +- 7 files changed, 164 insertions(+), 112 deletions(-) diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go index 30dd3950b..a9641c68d 100644 --- a/x/dogfood/keeper/abci.go +++ b/x/dogfood/keeper/abci.go @@ -31,11 +31,11 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { k.ClearPendingConsensusAddrs(ctx) // finally, perform the actual operations of vote power changes. operations := k.GetPendingOperations(ctx) - id, _ := k.GetValidatorSetID(ctx, ctx.BlockHeight()) + id, _ := k.getValidatorSetID(ctx, ctx.BlockHeight()) if len(operations.GetList()) == 0 { // there is no validator set change, so we just increment the block height // and retain the same val set id mapping. - k.SetValidatorSetID(ctx, ctx.BlockHeight()+1, id) + k.setValidatorSetID(ctx, ctx.BlockHeight()+1, id) return []abci.ValidatorUpdate{} } res := make([]abci.ValidatorUpdate, 0, len(operations.GetList())) @@ -46,7 +46,8 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { ctx, operation.OperatorAddress, ) if err != nil { - panic(err) + // this should never happen, but if it does, we just skip the operation. + continue } res = append(res, abci.ValidatorUpdate{ PubKey: operation.PubKey, @@ -58,7 +59,8 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { Power: 0, }) case types.KeyOpUnspecified: - panic("unspecified operation type") + // this should never happen, but if it does, we just skip the operation. + continue } } // call via wrapper function so that validator info is stored. diff --git a/x/dogfood/keeper/opt_out.go b/x/dogfood/keeper/opt_out.go index 939d747e3..837fc925f 100644 --- a/x/dogfood/keeper/opt_out.go +++ b/x/dogfood/keeper/opt_out.go @@ -21,7 +21,8 @@ func (k Keeper) GetOptOutsToFinish( ctx sdk.Context, epoch int64, ) [][]byte { store := ctx.KVStore(k.storeKey) - key := types.OptOutsToFinishKey(epoch) + // the epochs module validates at genesis that epoch is non-negative. + key, _ := types.OptOutsToFinishKey(epoch) bz := store.Get(key) if bz == nil { return [][]byte{} @@ -39,7 +40,7 @@ func (k Keeper) setOptOutsToFinish( ctx sdk.Context, epoch int64, addrs types.AccountAddresses, ) { store := ctx.KVStore(k.storeKey) - key := types.OptOutsToFinishKey(epoch) + key, _ := types.OptOutsToFinishKey(epoch) bz, err := addrs.Marshal() if err != nil { panic(err) @@ -61,7 +62,7 @@ func (k Keeper) RemoveOptOutToFinish(ctx sdk.Context, epoch int64, addr sdk.AccA // finished at the end of the provided epoch. func (k Keeper) ClearOptOutsToFinish(ctx sdk.Context, epoch int64) { store := ctx.KVStore(k.storeKey) - key := types.OptOutsToFinishKey(epoch) + key, _ := types.OptOutsToFinishKey(epoch) store.Delete(key) } @@ -71,7 +72,8 @@ func (k Keeper) SetOperatorOptOutFinishEpoch( ) { store := ctx.KVStore(k.storeKey) key := types.OperatorOptOutFinishEpochKey(operatorAddr) - bz := sdk.Uint64ToBigEndian(uint64(epoch)) + uepoch, _ := types.SafeInt64ToUint64(epoch) + bz := sdk.Uint64ToBigEndian(uepoch) store.Set(key, bz) } @@ -86,7 +88,9 @@ func (k Keeper) GetOperatorOptOutFinishEpoch( if bz == nil { return -1 } - return int64(sdk.BigEndianToUint64(bz)) + // max int64 is 9 quintillion, and max uint64 is double of that. + // it is too far in the future to be a concern. + return int64(sdk.BigEndianToUint64(bz)) // #nosec G701 // see above. } // DeleteOperatorOptOutFinishEpoch deletes the epoch at which an operator's opt out will be @@ -115,7 +119,7 @@ func (k Keeper) GetConsensusAddrsToPrune( ctx sdk.Context, epoch int64, ) [][]byte { store := ctx.KVStore(k.storeKey) - key := types.ConsensusAddrsToPruneKey(epoch) + key, _ := types.ConsensusAddrsToPruneKey(epoch) bz := store.Get(key) if bz == nil { return [][]byte{} @@ -143,7 +147,7 @@ func (k Keeper) DeleteConsensusAddrToPrune( // epoch. func (k Keeper) ClearConsensusAddrsToPrune(ctx sdk.Context, epoch int64) { store := ctx.KVStore(k.storeKey) - key := types.ConsensusAddrsToPruneKey(epoch) + key, _ := types.ConsensusAddrsToPruneKey(epoch) store.Delete(key) } @@ -153,7 +157,7 @@ func (k Keeper) setConsensusAddrsToPrune( ctx sdk.Context, epoch int64, addrs types.ConsensusAddresses, ) { store := ctx.KVStore(k.storeKey) - key := types.ConsensusAddrsToPruneKey(epoch) + key, _ := types.ConsensusAddrsToPruneKey(epoch) bz, err := addrs.Marshal() if err != nil { panic(err) diff --git a/x/dogfood/keeper/pending.go b/x/dogfood/keeper/pending.go index 7d68779f8..9bf05ae17 100644 --- a/x/dogfood/keeper/pending.go +++ b/x/dogfood/keeper/pending.go @@ -24,7 +24,7 @@ func (k Keeper) GetPendingOperations(ctx sdk.Context) types.Operations { } var operations types.Operations if err := operations.Unmarshal(bz); err != nil { - panic(err) + return types.Operations{} } return operations } @@ -38,10 +38,7 @@ func (k Keeper) ClearPendingOperations(ctx sdk.Context) { // SetPendingOptOuts sets the pending opt-outs to be applied at the end of the block. func (k Keeper) SetPendingOptOuts(ctx sdk.Context, addrs types.AccountAddresses) { store := ctx.KVStore(k.storeKey) - bz, err := addrs.Marshal() - if err != nil { - panic(err) - } + bz := k.cdc.MustMarshal(&addrs) store.Set(types.PendingOptOutsKey(), bz) } @@ -54,7 +51,7 @@ func (k Keeper) GetPendingOptOuts(ctx sdk.Context) types.AccountAddresses { } var addrs types.AccountAddresses if err := addrs.Unmarshal(bz); err != nil { - panic(err) + return types.AccountAddresses{} } return addrs } @@ -69,10 +66,7 @@ func (k Keeper) ClearPendingOptOuts(ctx sdk.Context) { // block. func (k Keeper) SetPendingConsensusAddrs(ctx sdk.Context, addrs types.ConsensusAddresses) { store := ctx.KVStore(k.storeKey) - bz, err := addrs.Marshal() - if err != nil { - panic(err) - } + bz := k.cdc.MustMarshal(&addrs) store.Set(types.PendingConsensusAddrsKey(), bz) } @@ -86,7 +80,7 @@ func (k Keeper) GetPendingConsensusAddrs(ctx sdk.Context) types.ConsensusAddress } var addrs types.ConsensusAddresses if err := addrs.Unmarshal(bz); err != nil { - panic(err) + return types.ConsensusAddresses{} } return addrs } @@ -100,12 +94,12 @@ func (k Keeper) ClearPendingConsensusAddrs(ctx sdk.Context) { // SetPendingUndelegations sets the pending undelegations to be released at the end of the // block. -func (k Keeper) SetPendingUndelegations(ctx sdk.Context, undelegations types.UndelegationRecordKeys) { +func (k Keeper) SetPendingUndelegations( + ctx sdk.Context, + undelegations types.UndelegationRecordKeys, +) { store := ctx.KVStore(k.storeKey) - bz, err := undelegations.Marshal() - if err != nil { - panic(err) - } + bz := k.cdc.MustMarshal(&undelegations) store.Set(types.PendingUndelegationsKey(), bz) } @@ -119,7 +113,7 @@ func (k Keeper) GetPendingUndelegations(ctx sdk.Context) types.UndelegationRecor } var undelegations types.UndelegationRecordKeys if err := undelegations.Unmarshal(bz); err != nil { - panic(err) + return types.UndelegationRecordKeys{} } return undelegations } diff --git a/x/dogfood/keeper/unbonding.go b/x/dogfood/keeper/unbonding.go index 9e588e63a..4070c87dc 100644 --- a/x/dogfood/keeper/unbonding.go +++ b/x/dogfood/keeper/unbonding.go @@ -54,7 +54,7 @@ func (k Keeper) GetUnbondingCompletionEpoch( // goes into effect at the beginning of epoch 6. the information // should be held for 7 epochs, so it should be deleted at the // beginning of epoch 13 or the end of epoch 12. - return epochInfo.CurrentEpoch + int64(unbondingEpochs) + return epochInfo.CurrentEpoch + int64(unbondingEpochs) // #nosec G701 } // AppendUndelegationsToMature stores that the undelegation with recordKey should be @@ -75,7 +75,7 @@ func (k Keeper) GetUndelegationsToMature( ctx sdk.Context, epoch int64, ) [][]byte { store := ctx.KVStore(k.storeKey) - key := types.UnbondingReleaseMaturityKey(epoch) + key, _ := types.UnbondingReleaseMaturityKey(epoch) bz := store.Get(key) if bz == nil { return [][]byte{} @@ -94,7 +94,7 @@ func (k Keeper) ClearUndelegationsToMature( ctx sdk.Context, epoch int64, ) { store := ctx.KVStore(k.storeKey) - key := types.UnbondingReleaseMaturityKey(epoch) + key, _ := types.UnbondingReleaseMaturityKey(epoch) store.Delete(key) } @@ -104,7 +104,7 @@ func (k Keeper) setUndelegationsToMature( ctx sdk.Context, epoch int64, undelegationRecords types.UndelegationRecordKeys, ) { store := ctx.KVStore(k.storeKey) - key := types.UnbondingReleaseMaturityKey(epoch) + key, _ := types.UnbondingReleaseMaturityKey(epoch) val, err := undelegationRecords.Marshal() if err != nil { panic(err) diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index bdfc529d6..cb61ca7de 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -41,9 +41,10 @@ func (k Keeper) ApplyValidatorChanges( // convert TM pubkey to SDK pubkey pubkey, err := cryptocodec.FromTmProtoPublicKey(change.GetPubKey()) if err != nil { - // An error here would indicate that the validator updates - // received from other modules (or genesis) are invalid. - panic(err) + // An error here would indicate that this change is invalid. + // In no situation it should happen, however, if it does, + // we do not panic. Simply skip the change. + continue } addr := pubkey.Address() val, found := k.GetValidator(ctx, addr) @@ -60,22 +61,19 @@ func (k Keeper) ApplyValidatorChanges( case false: if change.Power > 0 { // create a new validator - the address is just derived from the public key and - // has - // no correlation with the operator address on Exocore + // has no correlation with the operator address on Exocore ocVal, err := types.NewExocoreValidator(addr, change.Power, pubkey) if err != nil { - // An error here would indicate that the validator updates - // received are invalid. - panic(err) + continue } - - k.SetValidator(ctx, ocVal) - err = k.Hooks().AfterValidatorBonded(ctx, sdk.ConsAddress(addr), nil) + cc, writeFunc := ctx.CacheContext() + k.SetValidator(cc, ocVal) + err = k.Hooks().AfterValidatorBonded(cc, sdk.ConsAddress(addr), nil) if err != nil { - // AfterValidatorBonded is hooked by the Slashing module and should not - // return - // an error. If any other module were to hook it, they should also not. - panic(err) + // If an error is returned, the validator is not added to the `ret` slice. + continue + } else { + writeFunc() } } else { // edge case: we received an update for 0 power @@ -90,27 +88,23 @@ func (k Keeper) ApplyValidatorChanges( // store the validator set against the provided validator set id lastVals := types.Validators{} for _, v := range k.GetAllExocoreValidators(ctx) { - pubkey, err := v.ConsPubKey() - if err != nil { - panic(err) - } - val, err := stakingtypes.NewValidator(nil, pubkey, stakingtypes.Description{}) - if err != nil { - panic(err) - } + // we stored the validators above, so this will never fail. + pubkey, _ := v.ConsPubKey() + // This calls NewAnyWithValue internally, which we have already done. + val, _ := stakingtypes.NewValidator(nil, pubkey, stakingtypes.Description{}) // Set validator to bonded status val.Status = stakingtypes.Bonded // Compute tokens from voting power val.Tokens = sdk.TokensFromConsensusPower(v.Power, sdk.DefaultPowerReduction) lastVals.List = append(lastVals.GetList(), val) } - k.SetValidatorSet(ctx, valSetID, &lastVals) + k.setValidatorSet(ctx, valSetID, &lastVals) if !genesis { // the val set change is effective as of the next block, so height + 1. - k.SetValidatorSetID(ctx, ctx.BlockHeight()+1, valSetID) + k.setValidatorSetID(ctx, ctx.BlockHeight()+1, valSetID) } else { // the val set change is effective immediately. - k.SetValidatorSetID(ctx, ctx.BlockHeight(), valSetID) + k.setValidatorSetID(ctx, ctx.BlockHeight(), valSetID) } return ret } @@ -167,17 +161,17 @@ func (k Keeper) GetAllExocoreValidators( func (k Keeper) GetHistoricalInfo( ctx sdk.Context, height int64, ) (stakingtypes.HistoricalInfo, bool) { - headerSubset, found := k.GetBlockHeader(ctx, height) + headerSubset, found := k.getBlockHeader(ctx, height) if !found { // only panic in the case of an unmarshal error return stakingtypes.HistoricalInfo{}, false } - valSetID, found := k.GetValidatorSetID(ctx, height) + valSetID, found := k.getValidatorSetID(ctx, height) if !found { // only panic in the case of an unmarshal error return stakingtypes.HistoricalInfo{}, false } - valSet, found := k.GetValidatorSet(ctx, valSetID) + valSet, found := k.getValidatorSet(ctx, valSetID) if !found { // only panic in the case of an unmarshal error return stakingtypes.HistoricalInfo{}, false @@ -192,9 +186,10 @@ func (k Keeper) GetHistoricalInfo( ), true } -// SetValidatorSet sets the validator set at a given id. This is -// (intentionally) not exported in the genesis state. -func (k Keeper) SetValidatorSet( +// setValidatorSet sets the validator set at a given id. This is +// (intentionally) not exported in the genesis state. It can therefore +// be a private function. +func (k Keeper) setValidatorSet( ctx sdk.Context, id uint64, vs *types.Validators, ) { store := ctx.KVStore(k.storeKey) @@ -203,8 +198,8 @@ func (k Keeper) SetValidatorSet( store.Set(key, value) } -// GetValidatorSet gets the validator set at a given id. -func (k Keeper) GetValidatorSet( +// getValidatorSet gets the validator set at a given id. +func (k Keeper) getValidatorSet( ctx sdk.Context, id uint64, ) (*types.Validators, bool) { store := ctx.KVStore(k.storeKey) @@ -218,8 +213,8 @@ func (k Keeper) GetValidatorSet( return &hi, true } -// DeleteValidatorSet deletes the validator set at a given id. -func (k Keeper) DeleteValidatorSet(ctx sdk.Context, id uint64) { +// deleteValidatorSet deletes the validator set at a given id. +func (k Keeper) deleteValidatorSet(ctx sdk.Context, id uint64) { store := ctx.KVStore(k.storeKey) key := types.ValidatorSetKey(id) store.Delete(key) @@ -231,7 +226,8 @@ func (k Keeper) DeleteValidatorSet(ctx sdk.Context, id uint64) { // event. Otherwise, it is constant. The header, however, will change at every block. Since // the Cosmos SDK does not allow for the retrieval of a past block header, we store the header // ourselves in this function. The validator set is stored when it changes at the end of an -// epoch or at a slashing event in the corresponding functions. +// epoch or at a slashing event in the corresponding functions. It is called within the EndBlock +// of the module, so it is kept public. func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { // Get the number of historical entries to persist, as the number of block heights. numHistoricalEntries := k.GetHistoricalEntries(ctx) @@ -241,23 +237,23 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { // they must be only deleted if no other block is using them. lastDeletedID := uint64(0) // contract: starts from 1. for i := ctx.BlockHeight() - int64(numHistoricalEntries); i >= 0; i-- { - _, found := k.GetBlockHeader(ctx, i) + _, found := k.getBlockHeader(ctx, i) if found { // because they are deleted together, and saved one after the other, // since the block header exists, so must the validator set id. - lastDeletedID, _ = k.GetValidatorSetID(ctx, i+1) + lastDeletedID, _ = k.getValidatorSetID(ctx, i+1) // clear both the header and the mapping - k.DeleteBlockHeader(ctx, i) - k.DeleteValidatorSetID(ctx, i) + k.deleteBlockHeader(ctx, i) + k.deleteValidatorSetID(ctx, i) } else { break } } - currentID, _ := k.GetValidatorSetID( - ctx, ctx.BlockHeight()-int64(numHistoricalEntries)+1, + currentID, _ := k.getValidatorSetID(ctx, + ctx.BlockHeight()-int64(numHistoricalEntries)+1, // #nosec G701 // uint32 < int64 always ) for i := lastDeletedID; i < currentID; i++ { - k.DeleteValidatorSet(ctx, i) + k.deleteValidatorSet(ctx, i) } // if there is no need to persist historicalInfo, return. @@ -266,7 +262,7 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { } // store the header - k.StoreBlockHeader(ctx) + k.storeBlockHeader(ctx) // we have stored: // before TrackHistoricalInfo: ValidatorSetID for height, and the validator set. @@ -297,13 +293,17 @@ func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.Va return valUpdates } -// GetValidatorSetID returns the identifier of the validator set at a given height. +// getValidatorSetID returns the identifier of the validator set at a given height. // It is used to "share" the validator set entries across multiple heights within an epoch. // Typically, the validator set should change only at the end of an epoch. However, in the -// case of a slashing occurrence, the validator set may change within an epoch. -func (k Keeper) GetValidatorSetID(ctx sdk.Context, height int64) (uint64, bool) { +// case of a slashing occurrence, the validator set may change within an epoch. This info +// is not exported in the genesis, so it is private. +func (k Keeper) getValidatorSetID(ctx sdk.Context, height int64) (uint64, bool) { store := ctx.KVStore(k.storeKey) - key := types.ValidatorSetIDKey(height) + key, ok := types.ValidatorSetIDKey(height) + if !ok { + return 0, false + } value := store.Get(key) if value == nil { return 0, false @@ -311,44 +311,54 @@ func (k Keeper) GetValidatorSetID(ctx sdk.Context, height int64) (uint64, bool) return sdk.BigEndianToUint64(value), true } -// SetValidatorSetID sets the identifier of the validator set at a given height. -func (k Keeper) SetValidatorSetID(ctx sdk.Context, height int64, id uint64) { +// setValidatorSetID sets the identifier of the validator set at a given height. +func (k Keeper) setValidatorSetID(ctx sdk.Context, height int64, id uint64) { store := ctx.KVStore(k.storeKey) - key := types.ValidatorSetIDKey(height) + // SetValidatorSetID is called with ctx.BlockHeight which Cosmos + // guarantees to be positive. + key, _ := types.ValidatorSetIDKey(height) value := sdk.Uint64ToBigEndian(id) store.Set(key, value) } -// DeleteValidatorSetID deletes the identifier of the validator set at a given height. -func (k Keeper) DeleteValidatorSetID(ctx sdk.Context, height int64) { +// deleteValidatorSetID deletes the identifier of the validator set at a given height. +func (k Keeper) deleteValidatorSetID(ctx sdk.Context, height int64) { store := ctx.KVStore(k.storeKey) - key := types.ValidatorSetIDKey(height) + // i don't care if we delete a key that is meaningless + key, _ := types.ValidatorSetIDKey(height) store.Delete(key) } -// GetBlockHeader returns the block header at a given height. -func (k Keeper) GetBlockHeader(ctx sdk.Context, height int64) (types.HeaderSubset, bool) { +// getBlockHeader returns the block header at a given height. It is called during IBC's +// GetHistoricalInfo call. Since it is an external call, we will validate that height +// should be non-negative. This info is not exported in the genesis, so it is private. +func (k Keeper) getBlockHeader(ctx sdk.Context, height int64) (types.HeaderSubset, bool) { store := ctx.KVStore(k.storeKey) - key := types.HeaderKey(height) - var header types.HeaderSubset + key, ok := types.HeaderKey(height) + if !ok { + return types.HeaderSubset{}, false + } value := store.Get(key) if value == nil { - return header, false + return types.HeaderSubset{}, false } + var header types.HeaderSubset k.cdc.MustUnmarshal(value, &header) return header, true } -// SetBlockHeader sets the block header at a given height. -func (k Keeper) DeleteBlockHeader(ctx sdk.Context, height int64) { +// deleteBlockHeader deletes the block header at a given height. +func (k Keeper) deleteBlockHeader(ctx sdk.Context, height int64) { store := ctx.KVStore(k.storeKey) - key := types.HeaderKey(height) + // i don't care if we delete a key that is meaningless + key, _ := types.HeaderKey(height) store.Delete(key) } -// StoreBlockHeader stores the block header subset as of the current height. -func (k Keeper) StoreBlockHeader(ctx sdk.Context) { - key := types.HeaderKey(ctx.BlockHeight()) +// storeBlockHeader stores the block header subset as of the current height. +func (k Keeper) storeBlockHeader(ctx sdk.Context) { + // ctx.BlockHeight() is positive so we don't need to validate + key, _ := types.HeaderKey(ctx.BlockHeight()) sdkHeader := ctx.BlockHeader() header := types.HeaderSubset{ Time: sdkHeader.Time, diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 6397e1796..1303fb4d0 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -75,15 +75,27 @@ func ValidatorSetKey(id uint64) []byte { } // ValidatorSetIDKey returns the key for the validator set id store. -func ValidatorSetIDKey(height int64) []byte { - bz := sdk.Uint64ToBigEndian(uint64(height)) - return append([]byte{ValidatorSetIDBytePrefix}, bz...) +func ValidatorSetIDKey(height int64) ([]byte, bool) { + uheight, ok := SafeInt64ToUint64(height) + if !ok { + return nil, false + } + return append( + []byte{ValidatorSetIDBytePrefix}, + sdk.Uint64ToBigEndian(uheight)..., + ), true } // HeaderKey returns the key for the header store. -func HeaderKey(height int64) []byte { - bz := sdk.Uint64ToBigEndian(uint64(height)) - return append([]byte{HeaderBytePrefix}, bz...) +func HeaderKey(height int64) ([]byte, bool) { + uheight, ok := SafeInt64ToUint64(height) + if !ok { + return nil, false + } + return append( + []byte{HeaderBytePrefix}, + sdk.Uint64ToBigEndian(uheight)..., + ), true } // QueuedOperationsKey returns the key for the queued operations store. @@ -93,8 +105,15 @@ func QueuedOperationsKey() []byte { // OptOutsToFinishKey returns the key for the operator opt out maturity store (epoch -> list of // addresses). -func OptOutsToFinishKey(epoch int64) []byte { - return append([]byte{OptOutsToFinishBytePrefix}, sdk.Uint64ToBigEndian(uint64(epoch))...) +func OptOutsToFinishKey(epoch int64) ([]byte, bool) { + uepoch, ok := SafeInt64ToUint64(epoch) + if !ok { + return nil, false + } + return append( + []byte{OptOutsToFinishBytePrefix}, + sdk.Uint64ToBigEndian(uepoch)..., + ), true } // OperatorOptOutFinishEpochKey is the key for the operator opt out maturity store @@ -105,18 +124,28 @@ func OperatorOptOutFinishEpochKey(address sdk.AccAddress) []byte { // ConsensusAddrsToPruneKey is the key to lookup the list of operator consensus addresses that // can be pruned from the operator module at the provided epoch. -func ConsensusAddrsToPruneKey(epoch int64) []byte { +func ConsensusAddrsToPruneKey(epoch int64) ([]byte, bool) { + uepoch, ok := SafeInt64ToUint64(epoch) + if !ok { + return nil, false + } return append( []byte{ConsensusAddrsToPruneBytePrefix}, - sdk.Uint64ToBigEndian(uint64(epoch))...) + sdk.Uint64ToBigEndian(uepoch)..., + ), true } // UnbondingReleaseMaturityKey is the key to lookup the list of undelegations that will mature // at the provided epoch. -func UnbondingReleaseMaturityKey(epoch int64) []byte { +func UnbondingReleaseMaturityKey(epoch int64) ([]byte, bool) { + uepoch, ok := SafeInt64ToUint64(epoch) + if !ok { + return nil, false + } return append( []byte{UnbondingReleaseMaturityBytePrefix}, - sdk.Uint64ToBigEndian(uint64(epoch))...) + sdk.Uint64ToBigEndian(uepoch)..., + ), true } // PendingOperationsKey returns the key for the pending operations store. @@ -139,3 +168,13 @@ func PendingConsensusAddrsKey() []byte { func PendingUndelegationsKey() []byte { return []byte{PendingUndelegationsByte} } + +// SafeInt64ToUint64 is a wrapper function to convert an int64 +// to a uint64. It returns (0, false) if the conversion is not possible. +// This is safe as long as the int64 is non-negative. +func SafeInt64ToUint64(id int64) (uint64, bool) { + if id < 0 { + return 0, false + } + return uint64(id), true // #nosec G701 // already checked. +} diff --git a/x/dogfood/types/params.go b/x/dogfood/types/params.go index 97fb4f583..f1b272b56 100644 --- a/x/dogfood/types/params.go +++ b/x/dogfood/types/params.go @@ -123,6 +123,9 @@ func ValidatePositiveUint32(i interface{}) error { // String implements the Stringer interface. Ths interface is required as part of the // proto.Message interface, which is used in the query server. func (p Params) String() string { - out, _ := yaml.Marshal(p) + out, err := yaml.Marshal(p) + if err != nil { + return "" + } return string(out) } From 57f60a429a9e94ce445b83d580bb556e3096adce Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:56:42 +0000 Subject: [PATCH 26/32] chore(build): remove unused proto import --- proto/exocore/dogfood/v1/query.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/proto/exocore/dogfood/v1/query.proto b/proto/exocore/dogfood/v1/query.proto index 9f1a73ae7..51d9424a4 100644 --- a/proto/exocore/dogfood/v1/query.proto +++ b/proto/exocore/dogfood/v1/query.proto @@ -4,7 +4,6 @@ package exocore.dogfood.v1; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; -import "cosmos/base/query/v1beta1/pagination.proto"; import "exocore/dogfood/v1/params.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; From 7bba29fe8be3cd6b01b0d9afdc7c8d761e9d760c Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:58:09 +0000 Subject: [PATCH 27/32] chore(dogfood): respond to golangci-lint --- x/dogfood/client/cli/query.go | 2 +- x/dogfood/keeper/validators.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x/dogfood/client/cli/query.go b/x/dogfood/client/cli/query.go index a1f193d8d..eac3ceae4 100644 --- a/x/dogfood/client/cli/query.go +++ b/x/dogfood/client/cli/query.go @@ -39,7 +39,7 @@ func CmdQueryParams() *cobra.Command { Use: "params", Short: "shows the parameters of the module", Args: cobra.NoArgs, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, _ []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index cb61ca7de..8c4b1147a 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -72,9 +72,8 @@ func (k Keeper) ApplyValidatorChanges( if err != nil { // If an error is returned, the validator is not added to the `ret` slice. continue - } else { - writeFunc() } + writeFunc() } else { // edge case: we received an update for 0 power // but the validator is already deleted. Do not forward From 55a228cf5a8862e95cddaafa658b41135cdf422a Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:00:17 +0000 Subject: [PATCH 28/32] chore(dogfood): lint the proto files --- proto/exocore/dogfood/v1/dogfood.proto | 95 ++++++++++++++------------ proto/exocore/dogfood/v1/query.proto | 2 +- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index 21c5b350b..8f5ad37f5 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -6,22 +6,22 @@ import "gogoproto/gogo.proto"; import "google/protobuf/any.proto"; import "google/protobuf/timestamp.proto"; +import "cosmos/staking/v1beta1/staking.proto"; import "cosmos_proto/cosmos.proto"; import "tendermint/crypto/keys.proto"; -import "cosmos/staking/v1beta1/staking.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; // ExocoreValidator is a validator that is part of the Exocore network. It is // used to validate and sign blocks and transactions. message ExocoreValidator { - // The address, as derived from the consensus key. It has no relation - // with the operator's account address. - bytes address = 1; - // Last known power - int64 power = 2; - // pubkey is the consensus public key of the validator, as a Protobuf Any. - google.protobuf.Any pubkey = 3 [ + // The address, as derived from the consensus key. It has no relation + // with the operator's account address. + bytes address = 1; + // Last known power + int64 power = 2; + // pubkey is the consensus public key of the validator, as a Protobuf Any. + google.protobuf.Any pubkey = 3 [ (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\"" ]; @@ -30,79 +30,84 @@ message ExocoreValidator { // OperationType is used to indicate the type of operation that is being // cached by the module to create the updated validator set. enum OperationType { - option (gogoproto.goproto_enum_prefix) = false; - // KeyOpUnspecified is used to indicate that the operation type is not specified. - // This should never be used. - OPERATION_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "KeyOpUnspecified" ]; - // KeyAddition is used to indicate that the operation is a key addition. - OPERATION_TYPE_ADDITION_OR_UPDATE = 1 [ (gogoproto.enumvalue_customname) = "KeyAdditionOrUpdate" ]; - // KeyRemoval is used to indicate that the operation is a key removal. Typically - // this is done due to key replacement mechanism and not directly. - OPERATION_TYPE_REMOVAL = 2 [ (gogoproto.enumvalue_customname) = "KeyRemoval" ]; + option (gogoproto.goproto_enum_prefix) = false; + // KeyOpUnspecified is used to indicate that the operation type is not specified. + // This should never be used. + OPERATION_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "KeyOpUnspecified" ]; + // KeyAddition is used to indicate that the operation is a key addition. + OPERATION_TYPE_ADDITION_OR_UPDATE = 1 [ (gogoproto.enumvalue_customname) = "KeyAdditionOrUpdate" ]; + // KeyRemoval is used to indicate that the operation is a key removal. Typically + // this is done due to key replacement mechanism and not directly. + OPERATION_TYPE_REMOVAL = 2 [ (gogoproto.enumvalue_customname) = "KeyRemoval" ]; } // QueueResultType is used to indicate the result of the queue operation. enum QueueResultType { - option (gogoproto.goproto_enum_prefix) = false; - // QueueResultUnspecified is used to indicate that the queue result type is not specified. - QUEUE_RESULT_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "QueueResultUnspecified" ]; - // QueueResultSuccess is used to indicate that the queue operation was successful. - QUEUE_RESULT_TYPE_SUCCESS = 1 [ (gogoproto.enumvalue_customname) = "QueueResultSuccess" ]; - // QueueResultExists is used to indicate that the queue operation failed because the - // operation already exists in the queue. - QUEUE_RESULT_TYPE_EXISTS = 2 [ (gogoproto.enumvalue_customname) = "QueueResultExists" ]; - // QueueResultRemoved is used to indicate that the queue operation resulted in an existing - // operation being removed from the queue. - QUEUE_RESULT_TYPE_REMOVED = 3 [ (gogoproto.enumvalue_customname) = "QueueResultRemoved" ]; + option (gogoproto.goproto_enum_prefix) = false; + // QueueResultUnspecified is used to indicate that the queue result type is not specified. + QUEUE_RESULT_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "QueueResultUnspecified" ]; + // QueueResultSuccess is used to indicate that the queue operation was successful. + QUEUE_RESULT_TYPE_SUCCESS = 1 [ (gogoproto.enumvalue_customname) = "QueueResultSuccess" ]; + // QueueResultExists is used to indicate that the queue operation failed because the + // operation already exists in the queue. + QUEUE_RESULT_TYPE_EXISTS = 2 [ (gogoproto.enumvalue_customname) = "QueueResultExists" ]; + // QueueResultRemoved is used to indicate that the queue operation resulted in an existing + // operation being removed from the queue. + QUEUE_RESULT_TYPE_REMOVED = 3 [ (gogoproto.enumvalue_customname) = "QueueResultRemoved" ]; } // Operation is used to indicate the operation that is being cached by the module // to create the updated validator set. message Operation { - // OperationType is the type of the operation (addition / removal). - OperationType operation_type = 1; - // OperatorAddress is the sdk.AccAddress of the operator. - bytes operator_address = 2; - // PubKey is the public key for which the operation is being applied. - tendermint.crypto.PublicKey pub_key = 3 [(gogoproto.nullable) = false]; + // OperationType is the type of the operation (addition / removal). + OperationType operation_type = 1; + // OperatorAddress is the sdk.AccAddress of the operator. + bytes operator_address = 2; + // PubKey is the public key for which the operation is being applied. + tendermint.crypto.PublicKey pub_key = 3 [(gogoproto.nullable) = false]; } // Operations is a collection of Operation. message Operations { - repeated Operation list = 1 [(gogoproto.nullable) = false]; + // list is the list of operations. + repeated Operation list = 1 [(gogoproto.nullable) = false]; } // AccountAddresses represents a list of account addresses. It is used to store the list of // operator addresses whose operations are maturing at an epoch. message AccountAddresses { - repeated bytes list = 1; + // list is the list of account addresses. + repeated bytes list = 1; } // ConsensusAddresses represents a list of account addresses. It is used to store the list of // addresses (which correspond to operator public keys) to delete at the end of an epoch. message ConsensusAddresses { - repeated bytes list = 1; + // list is the list of consensus addresses. + repeated bytes list = 1; } // UndelegationRecordKeys is a collection of undelegation record keys. This is used to store a // list of undelegation records to mature in the delegation module at the end of the epoch. message UndelegationRecordKeys { - repeated bytes list = 1; + // list is the list of undelegation record keys. + repeated bytes list = 1; } // Validators is a list of validators stored according to the staking module. message Validators { - repeated cosmos.staking.v1beta1.Validator list = 1 [(gogoproto.nullable) = false]; + // list is the list of validators. + repeated cosmos.staking.v1beta1.Validator list = 1 [(gogoproto.nullable) = false]; } // HeaderSubset is a subset of the block header that is relevant to the IBC codebase. It is // stored for each height and then converted to the `tm.Header` object after queried. It is // pruned when the information is no longer needed according to the `HistoricalEntries` param. message HeaderSubset { - // timestamp of the block - google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; - // validators for the next block - bytes next_validators_hash = 2; - // state after txs from the previous block - bytes app_hash = 3; + // timestamp of the block + google.protobuf.Timestamp time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + // validators for the next block + bytes next_validators_hash = 2; + // state after txs from the previous block + bytes app_hash = 3; } \ No newline at end of file diff --git a/proto/exocore/dogfood/v1/query.proto b/proto/exocore/dogfood/v1/query.proto index 51d9424a4..111b0c8e8 100644 --- a/proto/exocore/dogfood/v1/query.proto +++ b/proto/exocore/dogfood/v1/query.proto @@ -2,9 +2,9 @@ syntax = "proto3"; package exocore.dogfood.v1; +import "exocore/dogfood/v1/params.proto"; import "gogoproto/gogo.proto"; import "google/api/annotations.proto"; -import "exocore/dogfood/v1/params.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; From ca658d8b6dd15a0540cc23b10c57f3fdfb490f0b Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:01:15 +0000 Subject: [PATCH 29/32] build(dogfood): regenerate proto code --- x/dogfood/types/dogfood.pb.go | 109 ++++++++++++++++++---------------- x/dogfood/types/query.pb.go | 41 ++++++------- 2 files changed, 76 insertions(+), 74 deletions(-) diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index fc3868a19..876f5c4c1 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -237,6 +237,7 @@ func (m *Operation) GetPubKey() crypto.PublicKey { // Operations is a collection of Operation. type Operations struct { + // list is the list of operations. List []Operation `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` } @@ -283,6 +284,7 @@ func (m *Operations) GetList() []Operation { // AccountAddresses represents a list of account addresses. It is used to store the list of // operator addresses whose operations are maturing at an epoch. type AccountAddresses struct { + // list is the list of account addresses. List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` } @@ -329,6 +331,7 @@ func (m *AccountAddresses) GetList() [][]byte { // ConsensusAddresses represents a list of account addresses. It is used to store the list of // addresses (which correspond to operator public keys) to delete at the end of an epoch. type ConsensusAddresses struct { + // list is the list of consensus addresses. List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` } @@ -375,6 +378,7 @@ func (m *ConsensusAddresses) GetList() [][]byte { // UndelegationRecordKeys is a collection of undelegation record keys. This is used to store a // list of undelegation records to mature in the delegation module at the end of the epoch. type UndelegationRecordKeys struct { + // list is the list of undelegation record keys. List [][]byte `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"` } @@ -420,6 +424,7 @@ func (m *UndelegationRecordKeys) GetList() [][]byte { // Validators is a list of validators stored according to the staking module. type Validators struct { + // list is the list of validators. List []types1.Validator `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` } @@ -546,60 +551,60 @@ func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescrip var fileDescriptor_071b9989c501c3f2 = []byte{ // 857 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0xcf, 0x6f, 0xe3, 0x44, + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x41, 0x6f, 0xe3, 0x44, 0x14, 0x8e, 0x9b, 0xb2, 0xbb, 0x4c, 0xbb, 0x5d, 0x33, 0x84, 0x6e, 0x6a, 0xed, 0xa6, 0x6e, 0x84, 0x50, 0xa8, 0xc0, 0x26, 0x2d, 0x08, 0x04, 0x02, 0x29, 0x6d, 0x8c, 0x1a, 0x65, 0x69, 0xb2, 0x76, - 0xbc, 0x02, 0x2e, 0x96, 0x63, 0xbf, 0xa6, 0x56, 0x13, 0xcf, 0xc8, 0x33, 0xce, 0xd6, 0xff, 0x01, - 0xca, 0x69, 0x2f, 0x1c, 0x73, 0x42, 0xfc, 0x07, 0x48, 0x9c, 0xb8, 0xaf, 0x38, 0xed, 0x91, 0xd3, - 0x82, 0xda, 0xff, 0x80, 0x1b, 0x37, 0xe4, 0x5f, 0xa9, 0xb7, 0xa9, 0x7a, 0xf3, 0x9b, 0xf7, 0xbe, - 0x37, 0xdf, 0xe7, 0xf7, 0xcd, 0x43, 0x32, 0x9c, 0x13, 0x87, 0x04, 0xa0, 0xba, 0x64, 0x74, 0x42, - 0x88, 0xab, 0x4e, 0x9b, 0xf9, 0xa7, 0x42, 0x03, 0xc2, 0x09, 0xc6, 0x59, 0x85, 0x92, 0x1f, 0x4f, - 0x9b, 0x52, 0x65, 0x44, 0x46, 0x24, 0x49, 0xab, 0xf1, 0x57, 0x5a, 0x29, 0x6d, 0x8d, 0x08, 0x19, - 0x8d, 0x41, 0x4d, 0xa2, 0x61, 0x78, 0xa2, 0xda, 0x7e, 0x94, 0xa5, 0xb6, 0xaf, 0xa7, 0xb8, 0x37, - 0x01, 0xc6, 0xed, 0x09, 0xcd, 0xb1, 0x0e, 0x61, 0x13, 0xc2, 0xac, 0xb4, 0x69, 0x1a, 0x64, 0xa9, - 0x47, 0x1c, 0x7c, 0x17, 0x82, 0x89, 0xe7, 0x73, 0xd5, 0x09, 0x22, 0xca, 0x89, 0x7a, 0x06, 0x51, - 0x9e, 0x7d, 0x3f, 0xad, 0x55, 0x19, 0xb7, 0xcf, 0x3c, 0x7f, 0xa4, 0x4e, 0x9b, 0x43, 0xe0, 0x76, - 0x33, 0x8f, 0xd3, 0xaa, 0xfa, 0xaf, 0x02, 0x12, 0xb5, 0x54, 0xc7, 0x33, 0x7b, 0xec, 0xb9, 0x36, - 0x27, 0x01, 0xae, 0xa2, 0xbb, 0xb6, 0xeb, 0x06, 0xc0, 0x58, 0x55, 0x90, 0x85, 0xc6, 0xba, 0x9e, - 0x87, 0xb8, 0x82, 0xde, 0xa2, 0xe4, 0x39, 0x04, 0xd5, 0x15, 0x59, 0x68, 0x94, 0xf5, 0x34, 0xc0, - 0x36, 0xba, 0x43, 0xc3, 0xe1, 0x19, 0x44, 0xd5, 0xb2, 0x2c, 0x34, 0xd6, 0xf6, 0x2a, 0x4a, 0xaa, - 0x4a, 0xc9, 0x55, 0x29, 0x2d, 0x3f, 0x3a, 0xd8, 0xff, 0xf7, 0xf5, 0xf6, 0xc3, 0xc8, 0x9e, 0x8c, - 0xbf, 0xac, 0x3b, 0xc4, 0x67, 0xe0, 0xb3, 0x90, 0x59, 0x29, 0xae, 0xfe, 0xe7, 0x6f, 0x1f, 0x57, - 0x32, 0x6d, 0xa9, 0x12, 0xa5, 0x1f, 0x0e, 0xbb, 0x10, 0xe9, 0x59, 0xe3, 0xfa, 0x1f, 0x02, 0x7a, - 0xbb, 0x47, 0x21, 0xb0, 0xb9, 0x47, 0x7c, 0x7c, 0x84, 0x36, 0x48, 0x1e, 0x58, 0x3c, 0xa2, 0x90, - 0xf0, 0xdc, 0xd8, 0xdb, 0x51, 0x96, 0x67, 0xa2, 0x2c, 0x60, 0x83, 0x88, 0x82, 0x7e, 0x9f, 0x14, - 0x43, 0xfc, 0x21, 0x12, 0xd3, 0x03, 0x12, 0x58, 0xb9, 0xe6, 0x95, 0x44, 0xf3, 0x83, 0xfc, 0xbc, - 0x95, 0x69, 0xff, 0x0a, 0xdd, 0xa5, 0xe1, 0xd0, 0xba, 0x92, 0xf9, 0x48, 0xb9, 0x1a, 0x40, 0x81, - 0xf6, 0xd8, 0x73, 0xba, 0x10, 0x1d, 0xac, 0xbe, 0x7c, 0xbd, 0x5d, 0x4a, 0xf8, 0x77, 0x21, 0xaa, - 0x6b, 0x08, 0x2d, 0x78, 0x30, 0xfc, 0x39, 0x5a, 0x1d, 0x7b, 0x8c, 0x57, 0x05, 0xb9, 0xdc, 0x58, - 0xdb, 0x7b, 0x7c, 0x2b, 0xeb, 0xac, 0x51, 0x02, 0xa8, 0x7f, 0x80, 0xc4, 0x96, 0xe3, 0x90, 0xd0, - 0xe7, 0x19, 0x2b, 0x60, 0x18, 0x17, 0x9a, 0xad, 0x67, 0x75, 0x0d, 0x84, 0x0f, 0xf3, 0x7f, 0x7c, - 0x7b, 0xe5, 0x47, 0x68, 0xd3, 0xf4, 0x5d, 0x18, 0xc3, 0x28, 0xb9, 0x4d, 0x07, 0x87, 0x04, 0x6e, - 0x17, 0xa2, 0x9b, 0xab, 0x3b, 0x08, 0x2d, 0x6c, 0x12, 0xff, 0x91, 0xa2, 0x8c, 0x1d, 0x25, 0x9b, - 0x60, 0xee, 0xb0, 0xcc, 0x71, 0xca, 0x02, 0xf1, 0x86, 0x94, 0x9f, 0x05, 0xb4, 0x7e, 0x04, 0xb6, - 0x0b, 0x81, 0x11, 0x0e, 0x19, 0x70, 0xfc, 0x05, 0x5a, 0x8d, 0xcd, 0x9f, 0x8c, 0x72, 0x6d, 0x4f, - 0x5a, 0xf2, 0xd0, 0x20, 0x7f, 0x19, 0x07, 0xf7, 0xe2, 0x36, 0x2f, 0xfe, 0xde, 0x16, 0xf4, 0x04, - 0x81, 0x3f, 0x41, 0x15, 0x1f, 0xce, 0xb9, 0x35, 0x5d, 0x50, 0xb3, 0x4e, 0x6d, 0x76, 0x9a, 0x0d, - 0x12, 0xc7, 0xb9, 0x2b, 0xd6, 0x47, 0x36, 0x3b, 0xc5, 0x5b, 0xe8, 0x9e, 0x4d, 0x69, 0x5a, 0x55, - 0xce, 0x2c, 0x4e, 0x69, 0x9c, 0xda, 0xfd, 0x5d, 0x40, 0xf7, 0xdf, 0xb0, 0x0c, 0xfe, 0x14, 0x49, - 0xbd, 0xbe, 0xa6, 0xb7, 0x06, 0x9d, 0xde, 0xb1, 0x35, 0xf8, 0xa1, 0xaf, 0x59, 0xe6, 0xb1, 0xd1, - 0xd7, 0x0e, 0x3b, 0xdf, 0x76, 0xb4, 0xb6, 0x58, 0x92, 0x2a, 0xb3, 0xb9, 0x2c, 0x76, 0x21, 0xea, - 0x51, 0xd3, 0x67, 0x14, 0x1c, 0xef, 0xc4, 0x03, 0x17, 0x7f, 0x83, 0x76, 0xae, 0xa1, 0x5a, 0xed, - 0x76, 0x27, 0x89, 0x7a, 0xba, 0x65, 0xf6, 0xdb, 0xad, 0x81, 0x26, 0x0a, 0xd2, 0xc3, 0xd9, 0x5c, - 0x7e, 0xb7, 0x0b, 0x51, 0xcb, 0x75, 0xbd, 0xf8, 0xc6, 0x5e, 0x60, 0x52, 0xd7, 0xe6, 0x80, 0x77, - 0xd1, 0xe6, 0x35, 0xbc, 0xae, 0x7d, 0xd7, 0x7b, 0xd6, 0x7a, 0x22, 0xae, 0x48, 0x1b, 0xb3, 0xb9, - 0x8c, 0xe2, 0xe7, 0x01, 0x13, 0x32, 0xb5, 0xc7, 0xd2, 0xea, 0x4f, 0xbf, 0xd4, 0x4a, 0xbb, 0xff, - 0x09, 0xe8, 0xc1, 0xd3, 0x10, 0x42, 0xd0, 0x81, 0x85, 0x63, 0x9e, 0x70, 0xff, 0x1a, 0x3d, 0x7e, - 0x6a, 0x6a, 0x66, 0x0c, 0x36, 0xcc, 0x27, 0x83, 0x9b, 0xe8, 0x4b, 0xb3, 0xb9, 0xbc, 0x59, 0xc0, - 0x15, 0x45, 0x7c, 0x86, 0xb6, 0x96, 0xe1, 0x86, 0x79, 0x78, 0xa8, 0x19, 0x86, 0x28, 0x48, 0x9b, - 0xb3, 0xb9, 0x8c, 0x0b, 0x50, 0x23, 0x74, 0x9c, 0xf8, 0xa9, 0xec, 0xa3, 0xea, 0x32, 0x4c, 0xfb, - 0xbe, 0x63, 0x0c, 0x0c, 0x71, 0x45, 0x7a, 0x6f, 0x36, 0x97, 0xdf, 0x29, 0xa0, 0xb4, 0x73, 0x8f, - 0x71, 0x76, 0xf3, 0x5d, 0x89, 0x66, 0xad, 0x2d, 0x96, 0x97, 0xee, 0x4a, 0xb4, 0x83, 0x9b, 0x6a, - 0x3f, 0xe8, 0xbe, 0xbc, 0xa8, 0x09, 0xaf, 0x2e, 0x6a, 0xc2, 0x3f, 0x17, 0x35, 0xe1, 0xc5, 0x65, - 0xad, 0xf4, 0xea, 0xb2, 0x56, 0xfa, 0xeb, 0xb2, 0x56, 0xfa, 0xb1, 0x39, 0xf2, 0xf8, 0x69, 0x38, - 0x54, 0x1c, 0x32, 0x51, 0xb3, 0x4d, 0x77, 0x0c, 0xfc, 0x39, 0x09, 0xce, 0xd4, 0x7c, 0xc5, 0x9f, - 0x2f, 0x96, 0x7c, 0xbc, 0x4b, 0xd8, 0xf0, 0x4e, 0xe2, 0xb9, 0xfd, 0xff, 0x03, 0x00, 0x00, 0xff, - 0xff, 0x41, 0xe1, 0x03, 0x2c, 0x04, 0x06, 0x00, 0x00, + 0xbc, 0x02, 0x2e, 0x96, 0x63, 0xbf, 0xa6, 0x56, 0x13, 0x8f, 0xe5, 0x19, 0x67, 0xeb, 0x7f, 0x80, + 0x72, 0xda, 0x0b, 0xc7, 0x9c, 0x10, 0xff, 0x00, 0x89, 0x13, 0xf7, 0x15, 0xa7, 0x3d, 0x72, 0x5a, + 0x50, 0xfb, 0x0f, 0xb8, 0x71, 0x43, 0xb6, 0xc7, 0xa9, 0xb7, 0xa9, 0x7a, 0x9b, 0x37, 0xef, 0x7d, + 0xf3, 0xbe, 0x6f, 0xe6, 0x9b, 0x87, 0x64, 0x38, 0x27, 0x0e, 0x09, 0x41, 0x75, 0xc9, 0xe8, 0x84, + 0x10, 0x57, 0x9d, 0x36, 0xf3, 0xa5, 0x12, 0x84, 0x84, 0x11, 0x8c, 0x79, 0x85, 0x92, 0x6f, 0x4f, + 0x9b, 0x52, 0x65, 0x44, 0x46, 0x24, 0x4d, 0xab, 0xc9, 0x2a, 0xab, 0x94, 0xb6, 0x46, 0x84, 0x8c, + 0xc6, 0xa0, 0xa6, 0xd1, 0x30, 0x3a, 0x51, 0x6d, 0x3f, 0xe6, 0xa9, 0xed, 0xeb, 0x29, 0xe6, 0x4d, + 0x80, 0x32, 0x7b, 0x12, 0xf0, 0x82, 0xf7, 0x1d, 0x42, 0x27, 0x84, 0xaa, 0x94, 0xd9, 0x67, 0x9e, + 0x3f, 0x52, 0xa7, 0xcd, 0x21, 0x30, 0xbb, 0x99, 0xc7, 0x79, 0x87, 0xac, 0xca, 0xca, 0x5a, 0x67, + 0x01, 0x4f, 0x3d, 0x62, 0xe0, 0xbb, 0x10, 0x4e, 0x3c, 0x9f, 0xa9, 0x4e, 0x18, 0x07, 0x8c, 0xa8, + 0x67, 0x10, 0xf3, 0x6c, 0xfd, 0x57, 0x01, 0x89, 0x5a, 0xa6, 0xe3, 0x99, 0x3d, 0xf6, 0x5c, 0x9b, + 0x91, 0x10, 0x57, 0xd1, 0x5d, 0xdb, 0x75, 0x43, 0xa0, 0xb4, 0x2a, 0xc8, 0x42, 0x63, 0x5d, 0xcf, + 0x43, 0x5c, 0x41, 0x6f, 0x05, 0xe4, 0x39, 0x84, 0xd5, 0x15, 0x59, 0x68, 0x94, 0xf5, 0x2c, 0xc0, + 0x36, 0xba, 0x13, 0x44, 0xc3, 0x33, 0x88, 0xab, 0x65, 0x59, 0x68, 0xac, 0xed, 0x55, 0x94, 0x4c, + 0x95, 0x92, 0xab, 0x52, 0x5a, 0x7e, 0x7c, 0xb0, 0xff, 0xef, 0xeb, 0xed, 0x87, 0xb1, 0x3d, 0x19, + 0x7f, 0x59, 0x77, 0x88, 0x4f, 0xc1, 0xa7, 0x11, 0xb5, 0x32, 0x5c, 0xfd, 0xcf, 0xdf, 0x3e, 0xae, + 0x70, 0xd6, 0x19, 0x47, 0xa5, 0x1f, 0x0d, 0xbb, 0x10, 0xeb, 0xfc, 0xe0, 0xfa, 0x1f, 0x02, 0x7a, + 0xbb, 0x17, 0x40, 0x68, 0x33, 0x8f, 0xf8, 0xf8, 0x08, 0x6d, 0x90, 0x3c, 0xb0, 0x58, 0x1c, 0x40, + 0xca, 0x73, 0x63, 0x6f, 0x47, 0x59, 0x7e, 0x13, 0x65, 0x01, 0x1b, 0xc4, 0x01, 0xe8, 0xf7, 0x49, + 0x31, 0xc4, 0x1f, 0x22, 0x31, 0xdb, 0x20, 0xa1, 0x95, 0x6b, 0x5e, 0x49, 0x35, 0x3f, 0xc8, 0xf7, + 0x5b, 0x5c, 0xfb, 0x57, 0xe8, 0x6e, 0x10, 0x0d, 0xad, 0x2b, 0x99, 0x8f, 0x94, 0xab, 0xab, 0x2d, + 0xd0, 0x1e, 0x7b, 0x4e, 0x17, 0xe2, 0x83, 0xd5, 0x97, 0xaf, 0xb7, 0x4b, 0x29, 0xff, 0x2e, 0xc4, + 0x75, 0x0d, 0xa1, 0x05, 0x0f, 0x8a, 0x3f, 0x47, 0xab, 0x63, 0x8f, 0xb2, 0xaa, 0x20, 0x97, 0x1b, + 0x6b, 0x7b, 0x8f, 0x6f, 0x65, 0xcd, 0x0f, 0x4a, 0x01, 0xf5, 0x0f, 0x90, 0xd8, 0x72, 0x1c, 0x12, + 0xf9, 0x8c, 0xb3, 0x02, 0x8a, 0x71, 0xe1, 0xb0, 0x75, 0x5e, 0xd7, 0x40, 0xf8, 0x30, 0xbf, 0xe3, + 0xdb, 0x2b, 0x3f, 0x42, 0x9b, 0xa6, 0xef, 0xc2, 0x18, 0x46, 0x69, 0x37, 0x1d, 0x1c, 0x12, 0xba, + 0x5d, 0x88, 0x6f, 0xae, 0xee, 0x20, 0xb4, 0xb0, 0x49, 0x72, 0x23, 0x45, 0x19, 0x3b, 0x0a, 0x7f, + 0xc1, 0xdc, 0x9a, 0xdc, 0xaa, 0xca, 0x02, 0xf1, 0x86, 0x94, 0x9f, 0x05, 0xb4, 0x7e, 0x04, 0xb6, + 0x0b, 0xa1, 0x11, 0x0d, 0x29, 0x30, 0xfc, 0x05, 0x5a, 0x4d, 0xcc, 0x9f, 0x3e, 0xe5, 0xda, 0x9e, + 0xb4, 0xe4, 0xa1, 0x41, 0xfe, 0x33, 0x0e, 0xee, 0x25, 0xc7, 0xbc, 0xf8, 0x7b, 0x5b, 0xd0, 0x53, + 0x04, 0xfe, 0x04, 0x55, 0x7c, 0x38, 0x67, 0xd6, 0x74, 0x41, 0xcd, 0x3a, 0xb5, 0xe9, 0x29, 0x7f, + 0x48, 0x9c, 0xe4, 0xae, 0x58, 0x1f, 0xd9, 0xf4, 0x14, 0x6f, 0xa1, 0x7b, 0x76, 0x10, 0x64, 0x55, + 0x65, 0x6e, 0xf1, 0x20, 0x48, 0x52, 0xbb, 0xbf, 0x0b, 0xe8, 0xfe, 0x1b, 0x96, 0xc1, 0x9f, 0x22, + 0xa9, 0xd7, 0xd7, 0xf4, 0xd6, 0xa0, 0xd3, 0x3b, 0xb6, 0x06, 0x3f, 0xf4, 0x35, 0xcb, 0x3c, 0x36, + 0xfa, 0xda, 0x61, 0xe7, 0xdb, 0x8e, 0xd6, 0x16, 0x4b, 0x52, 0x65, 0x36, 0x97, 0xc5, 0x2e, 0xc4, + 0xbd, 0xc0, 0xf4, 0x69, 0x00, 0x8e, 0x77, 0xe2, 0x81, 0x8b, 0xbf, 0x41, 0x3b, 0xd7, 0x50, 0xad, + 0x76, 0xbb, 0x93, 0x46, 0x3d, 0xdd, 0x32, 0xfb, 0xed, 0xd6, 0x40, 0x13, 0x05, 0xe9, 0xe1, 0x6c, + 0x2e, 0xbf, 0xdb, 0x85, 0xb8, 0xe5, 0xba, 0x5e, 0xd2, 0xb1, 0x17, 0x9a, 0x81, 0x6b, 0x33, 0xc0, + 0xbb, 0x68, 0xf3, 0x1a, 0x5e, 0xd7, 0xbe, 0xeb, 0x3d, 0x6b, 0x3d, 0x11, 0x57, 0xa4, 0x8d, 0xd9, + 0x5c, 0x46, 0xc9, 0xf7, 0x80, 0x09, 0x99, 0xda, 0x63, 0x69, 0xf5, 0xa7, 0x5f, 0x6a, 0xa5, 0xdd, + 0xff, 0x04, 0xf4, 0xe0, 0x69, 0x04, 0x11, 0xe8, 0x40, 0xa3, 0x31, 0x4b, 0xb9, 0x7f, 0x8d, 0x1e, + 0x3f, 0x35, 0x35, 0x33, 0x01, 0x1b, 0xe6, 0x93, 0xc1, 0x4d, 0xf4, 0xa5, 0xd9, 0x5c, 0xde, 0x2c, + 0xe0, 0x8a, 0x22, 0x3e, 0x43, 0x5b, 0xcb, 0x70, 0xc3, 0x3c, 0x3c, 0xd4, 0x0c, 0x43, 0x14, 0xa4, + 0xcd, 0xd9, 0x5c, 0xc6, 0x05, 0xa8, 0x11, 0x39, 0x4e, 0xf2, 0x55, 0xf6, 0x51, 0x75, 0x19, 0xa6, + 0x7d, 0xdf, 0x31, 0x06, 0x86, 0xb8, 0x22, 0xbd, 0x37, 0x9b, 0xcb, 0xef, 0x14, 0x50, 0xda, 0xb9, + 0x47, 0x19, 0xbd, 0xb9, 0x57, 0xaa, 0x59, 0x6b, 0x8b, 0xe5, 0xa5, 0x5e, 0xa9, 0x76, 0x70, 0x33, + 0xed, 0x07, 0xdd, 0x97, 0x17, 0x35, 0xe1, 0xd5, 0x45, 0x4d, 0xf8, 0xe7, 0xa2, 0x26, 0xbc, 0xb8, + 0xac, 0x95, 0x5e, 0x5d, 0xd6, 0x4a, 0x7f, 0x5d, 0xd6, 0x4a, 0x3f, 0x36, 0x47, 0x1e, 0x3b, 0x8d, + 0x86, 0x8a, 0x43, 0x26, 0x2a, 0x9f, 0x74, 0xc7, 0xc0, 0x9e, 0x93, 0xf0, 0x4c, 0xcd, 0x47, 0xfc, + 0xf9, 0x62, 0xc8, 0x27, 0xb3, 0x84, 0x0e, 0xef, 0xa4, 0x9e, 0xdb, 0xff, 0x3f, 0x00, 0x00, 0xff, + 0xff, 0x99, 0xab, 0xaa, 0x75, 0x04, 0x06, 0x00, 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { diff --git a/x/dogfood/types/query.pb.go b/x/dogfood/types/query.pb.go index ec851da1b..c1d854133 100644 --- a/x/dogfood/types/query.pb.go +++ b/x/dogfood/types/query.pb.go @@ -6,7 +6,6 @@ package types import ( context "context" fmt "fmt" - _ "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/cosmos/gogoproto/gogoproto" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" @@ -121,27 +120,25 @@ func init() { func init() { proto.RegisterFile("exocore/dogfood/v1/query.proto", fileDescriptor_e23d51a3dceb1c68) } var fileDescriptor_e23d51a3dceb1c68 = []byte{ - // 309 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x90, 0x3f, 0x4b, 0x03, 0x31, - 0x18, 0xc6, 0x2f, 0xa2, 0x1d, 0xe2, 0x16, 0x0b, 0xea, 0x21, 0xa9, 0x74, 0x50, 0x71, 0x48, 0xb8, - 0xba, 0x38, 0x17, 0x9c, 0x04, 0xff, 0x74, 0x74, 0xcb, 0xb5, 0x31, 0x1e, 0xda, 0x7b, 0xd3, 0x4b, - 0xee, 0x6c, 0x1d, 0xf5, 0x0b, 0x08, 0x7e, 0xa9, 0x8e, 0x05, 0x17, 0x27, 0x91, 0x3b, 0x3f, 0x88, - 0xf4, 0x12, 0x0a, 0xda, 0x82, 0x5b, 0x78, 0x9f, 0xdf, 0xf3, 0xe4, 0x79, 0x5f, 0x4c, 0xe5, 0x18, - 0xfa, 0x90, 0x49, 0x3e, 0x00, 0x75, 0x0b, 0x30, 0xe0, 0x45, 0xc4, 0x47, 0xb9, 0xcc, 0x26, 0x4c, - 0x67, 0x60, 0x81, 0x10, 0xaf, 0x33, 0xaf, 0xb3, 0x22, 0x0a, 0x9b, 0x0a, 0x14, 0xd4, 0x32, 0x9f, - 0xbf, 0x1c, 0x19, 0xee, 0x29, 0x00, 0xf5, 0x20, 0xb9, 0xd0, 0x09, 0x17, 0x69, 0x0a, 0x56, 0xd8, - 0x04, 0x52, 0xe3, 0xd5, 0xe3, 0x3e, 0x98, 0x21, 0x18, 0x1e, 0x0b, 0x23, 0xdd, 0x07, 0xbc, 0x88, - 0x62, 0x69, 0x45, 0xc4, 0xb5, 0x50, 0x49, 0x5a, 0xc3, 0x9e, 0x6d, 0xad, 0xe8, 0xa4, 0x45, 0x26, - 0x86, 0x3e, 0xac, 0xdd, 0xc4, 0xe4, 0x7a, 0x1e, 0x71, 0x55, 0x0f, 0x7b, 0x72, 0x94, 0x4b, 0x63, - 0xdb, 0x97, 0x78, 0xeb, 0xd7, 0xd4, 0x68, 0x48, 0x8d, 0x24, 0xa7, 0xb8, 0xe1, 0xcc, 0x3b, 0x68, - 0x1f, 0x1d, 0x6d, 0x76, 0x42, 0xb6, 0xbc, 0x12, 0x73, 0x9e, 0xee, 0xfa, 0xf4, 0xb3, 0x15, 0xf4, - 0x3c, 0xdf, 0x79, 0x41, 0x78, 0xa3, 0x4e, 0x24, 0x4f, 0xb8, 0xe1, 0x08, 0x72, 0xb0, 0xca, 0xbd, - 0x5c, 0x26, 0x3c, 0xfc, 0x97, 0x73, 0xf5, 0xda, 0xad, 0xe7, 0xf7, 0xef, 0xb7, 0xb5, 0x5d, 0xb2, - 0xcd, 0xff, 0x6e, 0xed, 0x5a, 0x74, 0xcf, 0xa7, 0x25, 0x45, 0xb3, 0x92, 0xa2, 0xaf, 0x92, 0xa2, - 0xd7, 0x8a, 0x06, 0xb3, 0x8a, 0x06, 0x1f, 0x15, 0x0d, 0x6e, 0x22, 0x95, 0xd8, 0xbb, 0x3c, 0x66, - 0x7d, 0x18, 0xf2, 0x33, 0x67, 0xbe, 0x90, 0xf6, 0x11, 0xb2, 0xfb, 0x45, 0xd6, 0x78, 0x91, 0x66, - 0x27, 0x5a, 0x9a, 0xb8, 0x51, 0x1f, 0xf0, 0xe4, 0x27, 0x00, 0x00, 0xff, 0xff, 0x19, 0xa2, 0xb5, - 0x7c, 0xf7, 0x01, 0x00, 0x00, + // 282 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4b, 0xad, 0xc8, 0x4f, + 0xce, 0x2f, 0x4a, 0xd5, 0x4f, 0xc9, 0x4f, 0x4f, 0xcb, 0xcf, 0x4f, 0xd1, 0x2f, 0x33, 0xd4, 0x2f, + 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x82, 0xca, 0xeb, 0x41, + 0xe5, 0xf5, 0xca, 0x0c, 0xa5, 0xe4, 0xb1, 0xe8, 0x29, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0x86, 0x68, + 0x92, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0x33, 0xf5, 0x41, 0x2c, 0xa8, 0xa8, 0x4c, 0x7a, 0x7e, + 0x7e, 0x7a, 0x4e, 0xaa, 0x7e, 0x62, 0x41, 0xa6, 0x7e, 0x62, 0x5e, 0x5e, 0x7e, 0x49, 0x62, 0x49, + 0x66, 0x7e, 0x1e, 0x54, 0x8f, 0x92, 0x08, 0x97, 0x50, 0x20, 0xc8, 0xde, 0x00, 0xb0, 0x41, 0x41, + 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x4a, 0xfe, 0x5c, 0xc2, 0x28, 0xa2, 0xc5, 0x05, 0xf9, 0x79, + 0xc5, 0xa9, 0x42, 0x16, 0x5c, 0x6c, 0x10, 0x0b, 0x25, 0x18, 0x15, 0x18, 0x35, 0xb8, 0x8d, 0xa4, + 0xf4, 0x30, 0x9d, 0xa9, 0x07, 0xd1, 0xe3, 0xc4, 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x54, 0xbd, + 0x51, 0x33, 0x23, 0x17, 0x2b, 0xd8, 0x44, 0xa1, 0x2a, 0x2e, 0x36, 0x88, 0x0a, 0x21, 0x35, 0x6c, + 0xba, 0x31, 0x1d, 0x23, 0xa5, 0x4e, 0x50, 0x1d, 0xc4, 0x79, 0x4a, 0xf2, 0x4d, 0x97, 0x9f, 0x4c, + 0x66, 0x92, 0x14, 0x12, 0xd7, 0x47, 0x0f, 0x29, 0x88, 0x2b, 0x9c, 0xbc, 0x4f, 0x3c, 0x92, 0x63, + 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, + 0x63, 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0xca, 0x30, 0x3d, 0xb3, 0x24, 0xa3, 0x34, 0x49, 0x2f, 0x39, + 0x3f, 0x57, 0xdf, 0x15, 0xa2, 0xd9, 0x2f, 0xb5, 0xa4, 0x3c, 0xbf, 0x28, 0x1b, 0x6e, 0x56, 0x05, + 0xdc, 0xb4, 0x92, 0xca, 0x82, 0xd4, 0xe2, 0x24, 0x36, 0x70, 0x00, 0x1a, 0x03, 0x02, 0x00, 0x00, + 0xff, 0xff, 0xef, 0xf0, 0x5f, 0x7f, 0xcb, 0x01, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. From 931a8e1380814e2faf0b08abe861573cb2fb1525 Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:10:06 +0000 Subject: [PATCH 30/32] chore(dogfood): ignore redundant gosec errors --- x/dogfood/keeper/validators.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index 8c4b1147a..294545c97 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -88,9 +88,11 @@ func (k Keeper) ApplyValidatorChanges( lastVals := types.Validators{} for _, v := range k.GetAllExocoreValidators(ctx) { // we stored the validators above, so this will never fail. - pubkey, _ := v.ConsPubKey() + pubkey, _ := v.ConsPubKey() // #nosec G703 // This calls NewAnyWithValue internally, which we have already done. - val, _ := stakingtypes.NewValidator(nil, pubkey, stakingtypes.Description{}) + val, _ := stakingtypes.NewValidator( // #nosec G703 + nil, pubkey, stakingtypes.Description{}, + ) // Set validator to bonded status val.Status = stakingtypes.Bonded // Compute tokens from voting power @@ -229,13 +231,16 @@ func (k Keeper) deleteValidatorSet(ctx sdk.Context, id uint64) { // of the module, so it is kept public. func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { // Get the number of historical entries to persist, as the number of block heights. - numHistoricalEntries := k.GetHistoricalEntries(ctx) + // #nosec G701 // uint32 fits into int64 always. + numHistoricalEntries := int64( + k.GetHistoricalEntries(ctx), + ) // we are deleting headers, say, from, 0 to 999 at block 1999 // for these headers, we must find the corresponding validator set ids to delete. // they must be only deleted if no other block is using them. lastDeletedID := uint64(0) // contract: starts from 1. - for i := ctx.BlockHeight() - int64(numHistoricalEntries); i >= 0; i-- { + for i := ctx.BlockHeight() - numHistoricalEntries; i >= 0; i-- { _, found := k.getBlockHeader(ctx, i) if found { // because they are deleted together, and saved one after the other, @@ -249,7 +254,7 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { } } currentID, _ := k.getValidatorSetID(ctx, - ctx.BlockHeight()-int64(numHistoricalEntries)+1, // #nosec G701 // uint32 < int64 always + ctx.BlockHeight()-numHistoricalEntries+1, ) for i := lastDeletedID; i < currentID; i++ { k.deleteValidatorSet(ctx, i) From 59fce84a2148e8e330028ea368f2f0ac1359696a Mon Sep 17 00:00:00 2001 From: MaxMustermann2 <82761650+MaxMustermann2@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:14:38 +0000 Subject: [PATCH 31/32] chore(dogfood): ignore redundant gosec warning The `// #nosec G703` line needs to be placed above the multi-line statement that it is ignoring, not in the middle of the statement which contains the part to ignore. --- x/dogfood/keeper/validators.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index 294545c97..13336a37f 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -89,8 +89,8 @@ func (k Keeper) ApplyValidatorChanges( for _, v := range k.GetAllExocoreValidators(ctx) { // we stored the validators above, so this will never fail. pubkey, _ := v.ConsPubKey() // #nosec G703 - // This calls NewAnyWithValue internally, which we have already done. - val, _ := stakingtypes.NewValidator( // #nosec G703 + // #nosec G703 // This calls NewAnyWithValue internally, which we have already done. + val, _ := stakingtypes.NewValidator( nil, pubkey, stakingtypes.Description{}, ) // Set validator to bonded status From f3df5ef2b43c3081d446af7ebe02c2bd0f826c70 Mon Sep 17 00:00:00 2001 From: Max <82761650+MaxMustermann2@users.noreply.github.com> Date: Tue, 5 Mar 2024 15:59:15 +0530 Subject: [PATCH 32/32] feat(dogfood): asset ids, oracle usage (#11) * feat(dogfood): add asset_ids param * feat(dogfood): move to average pricing * fix(dogfood): relint, add epoch id for avg * chore(dogfood): golangci-lint * chore(dogfood): lint gosec again * fix(dogfood): use correct string for pubkey * fix(dogfood): ++ the undelegation hold count The line was accidentally deleted. --- proto/exocore/dogfood/v1/dogfood.proto | 54 +- proto/exocore/dogfood/v1/params.proto | 5 + x/dogfood/keeper/abci.go | 124 ++- x/dogfood/keeper/genesis.go | 22 +- x/dogfood/keeper/impl_delegation_hooks.go | 104 +-- x/dogfood/keeper/impl_epochs_hooks.go | 12 +- x/dogfood/keeper/impl_operator_hooks.go | 119 +-- x/dogfood/keeper/keeper.go | 41 +- x/dogfood/keeper/params.go | 14 +- x/dogfood/keeper/pending.go | 30 - x/dogfood/keeper/queue.go | 45 -- x/dogfood/keeper/unbonding.go | 11 +- x/dogfood/keeper/validators.go | 73 +- x/dogfood/module.go | 4 +- x/dogfood/types/dogfood.pb.go | 899 ++++++++-------------- x/dogfood/types/expected_keepers.go | 10 + x/dogfood/types/keys.go | 17 + x/dogfood/types/params.go | 65 +- x/dogfood/types/params.pb.go | 99 ++- 19 files changed, 728 insertions(+), 1020 deletions(-) delete mode 100644 x/dogfood/keeper/queue.go diff --git a/proto/exocore/dogfood/v1/dogfood.proto b/proto/exocore/dogfood/v1/dogfood.proto index 8f5ad37f5..28f16e9e5 100644 --- a/proto/exocore/dogfood/v1/dogfood.proto +++ b/proto/exocore/dogfood/v1/dogfood.proto @@ -8,7 +8,6 @@ import "google/protobuf/timestamp.proto"; import "cosmos/staking/v1beta1/staking.proto"; import "cosmos_proto/cosmos.proto"; -import "tendermint/crypto/keys.proto"; option go_package = "github.com/ExocoreNetwork/exocore/x/dogfood/types"; @@ -27,52 +26,6 @@ message ExocoreValidator { ]; } -// OperationType is used to indicate the type of operation that is being -// cached by the module to create the updated validator set. -enum OperationType { - option (gogoproto.goproto_enum_prefix) = false; - // KeyOpUnspecified is used to indicate that the operation type is not specified. - // This should never be used. - OPERATION_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "KeyOpUnspecified" ]; - // KeyAddition is used to indicate that the operation is a key addition. - OPERATION_TYPE_ADDITION_OR_UPDATE = 1 [ (gogoproto.enumvalue_customname) = "KeyAdditionOrUpdate" ]; - // KeyRemoval is used to indicate that the operation is a key removal. Typically - // this is done due to key replacement mechanism and not directly. - OPERATION_TYPE_REMOVAL = 2 [ (gogoproto.enumvalue_customname) = "KeyRemoval" ]; -} - -// QueueResultType is used to indicate the result of the queue operation. -enum QueueResultType { - option (gogoproto.goproto_enum_prefix) = false; - // QueueResultUnspecified is used to indicate that the queue result type is not specified. - QUEUE_RESULT_TYPE_UNSPECIFIED = 0 [ (gogoproto.enumvalue_customname) = "QueueResultUnspecified" ]; - // QueueResultSuccess is used to indicate that the queue operation was successful. - QUEUE_RESULT_TYPE_SUCCESS = 1 [ (gogoproto.enumvalue_customname) = "QueueResultSuccess" ]; - // QueueResultExists is used to indicate that the queue operation failed because the - // operation already exists in the queue. - QUEUE_RESULT_TYPE_EXISTS = 2 [ (gogoproto.enumvalue_customname) = "QueueResultExists" ]; - // QueueResultRemoved is used to indicate that the queue operation resulted in an existing - // operation being removed from the queue. - QUEUE_RESULT_TYPE_REMOVED = 3 [ (gogoproto.enumvalue_customname) = "QueueResultRemoved" ]; -} - -// Operation is used to indicate the operation that is being cached by the module -// to create the updated validator set. -message Operation { - // OperationType is the type of the operation (addition / removal). - OperationType operation_type = 1; - // OperatorAddress is the sdk.AccAddress of the operator. - bytes operator_address = 2; - // PubKey is the public key for which the operation is being applied. - tendermint.crypto.PublicKey pub_key = 3 [(gogoproto.nullable) = false]; -} - -// Operations is a collection of Operation. -message Operations { - // list is the list of operations. - repeated Operation list = 1 [(gogoproto.nullable) = false]; -} - // AccountAddresses represents a list of account addresses. It is used to store the list of // operator addresses whose operations are maturing at an epoch. message AccountAddresses { @@ -110,4 +63,11 @@ message HeaderSubset { bytes next_validators_hash = 2; // state after txs from the previous block bytes app_hash = 3; +} + +// KeyPowerMapping is a mapping of the consensus public key (as a string) +// to the power of the key. +message KeyPowerMapping { + // list is the actual mapping of the consensus public key to the power. + map list = 1; } \ No newline at end of file diff --git a/proto/exocore/dogfood/v1/params.proto b/proto/exocore/dogfood/v1/params.proto index 4d3f94a8d..790908699 100644 --- a/proto/exocore/dogfood/v1/params.proto +++ b/proto/exocore/dogfood/v1/params.proto @@ -20,4 +20,9 @@ message Params { uint32 max_validators = 3; // HistoricalEntries is the number of historical entries to persist. uint32 historical_entries = 4; + // AssetIDs is the ids of the assets which will be accepted by the module. + // It must be within the list of assets supported by the restaking module. + // The typical format of these IDs is + // lower(assetAddress) + _ + hex(clientChainLzID) + repeated string asset_ids = 5 [(gogoproto.customname) = "AssetIDs"]; } diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go index a9641c68d..040aabdf5 100644 --- a/x/dogfood/keeper/abci.go +++ b/x/dogfood/keeper/abci.go @@ -1,12 +1,21 @@ package keeper import ( - "github.com/ExocoreNetwork/exocore/x/dogfood/types" + "sort" + abci "github.com/cometbft/cometbft/abci/types" + tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ) func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { + id, _ := k.getValidatorSetID(ctx, ctx.BlockHeight()) + if !k.IsEpochEnd(ctx) { + // save the same id for the next block height. + k.setValidatorSetID(ctx, ctx.BlockHeight()+1, id) + return []abci.ValidatorUpdate{} + } + defer k.ClearEpochEnd(ctx) // start with clearing the hold on the undelegations. undelegations := k.GetPendingUndelegations(ctx) for _, undelegation := range undelegations.GetList() { @@ -30,40 +39,95 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { } k.ClearPendingConsensusAddrs(ctx) // finally, perform the actual operations of vote power changes. - operations := k.GetPendingOperations(ctx) - id, _ := k.getValidatorSetID(ctx, ctx.BlockHeight()) - if len(operations.GetList()) == 0 { - // there is no validator set change, so we just increment the block height - // and retain the same val set id mapping. - k.setValidatorSetID(ctx, ctx.BlockHeight()+1, id) + // 1. find all operator keys for the chain. + // 2. find last stored operator keys + their powers. + // 3. find newest vote power for the operator keys, and sort them. + // 4. loop through #1 and see if anything has changed. + // if it hasn't, do nothing for that operator key. + // if it has, queue an update. + prev := k.getKeyPowerMapping(ctx).List + res := make([]abci.ValidatorUpdate, 0, len(prev)) + operators, keys := k.operatorKeeper.GetActiveOperatorsForChainId(ctx, ctx.ChainID()) + powers, err := k.restakingKeeper.GetAvgDelegatedValue( + ctx, operators, k.GetAssetIDs(ctx), k.GetEpochIdentifier(ctx), + ) + if err != nil { return []abci.ValidatorUpdate{} } - res := make([]abci.ValidatorUpdate, 0, len(operations.GetList())) - for _, operation := range operations.GetList() { - switch operation.OperationType { - case types.KeyAdditionOrUpdate: - power, err := k.restakingKeeper.GetOperatorAssetValue( - ctx, operation.OperatorAddress, - ) - if err != nil { - // this should never happen, but if it does, we just skip the operation. - continue - } - res = append(res, abci.ValidatorUpdate{ - PubKey: operation.PubKey, - Power: power, - }) - case types.KeyRemoval: - res = append(res, abci.ValidatorUpdate{ - PubKey: operation.PubKey, - Power: 0, - }) - case types.KeyOpUnspecified: - // this should never happen, but if it does, we just skip the operation. + operators, keys, powers = sortByPower(operators, keys, powers) + maxVals := k.GetMaxValidators(ctx) + for i := range operators { + // #nosec G701 // ok if 64-bit. + if i >= int(maxVals) { + // we have reached the maximum number of validators. + break + } + power := powers[i] + if power < 1 { + // we have reached the bottom of the rung. + break + } + // find the previous power. + key := keys[i] + keyString := string(k.cdc.MustMarshal(&key)) + prevPower, found := prev[keyString] + if found && prevPower == power { + delete(prev, keyString) continue } + // either the key was not in the previous set, + // or the power has changed. + res = append(res, abci.ValidatorUpdate{ + PubKey: key, + // note that this is the final power and not the change in power. + Power: power, + }) + } + // the remaining keys in prev have lost their power. + // gosec does not like `for key := range prev` while others do not like + // `for key, _ := range prev` + // #nosec G705 + for key := range prev { + bz := []byte(key) // undo string operation + var keyObj tmprotocrypto.PublicKey + k.cdc.MustUnmarshal(bz, &keyObj) // undo marshal operation + res = append(res, abci.ValidatorUpdate{ + PubKey: keyObj, + Power: 0, + }) } // call via wrapper function so that validator info is stored. // the id is incremented by 1 for the next block. - return k.ApplyValidatorChanges(ctx, res, id+1, false) + return k.ApplyValidatorChanges(ctx, res, id+1) +} + +// sortByPower sorts operators, their pubkeys, and their powers by the powers. +// the sorting is descending, so the highest power is first. +func sortByPower( + operatorAddrs []sdk.AccAddress, + pubKeys []tmprotocrypto.PublicKey, + powers []int64, +) ([]sdk.AccAddress, []tmprotocrypto.PublicKey, []int64) { + // Create a slice of indices + indices := make([]int, len(powers)) + for i := range indices { + indices[i] = i + } + + // Sort the indices slice based on the powers slice + sort.SliceStable(indices, func(i, j int) bool { + return powers[indices[i]] > powers[indices[j]] + }) + + // Reorder all slices using the sorted indices + sortedOperatorAddrs := make([]sdk.AccAddress, len(operatorAddrs)) + sortedPubKeys := make([]tmprotocrypto.PublicKey, len(pubKeys)) + sortedPowers := make([]int64, len(powers)) + for i, idx := range indices { + sortedOperatorAddrs[i] = operatorAddrs[idx] + sortedPubKeys[i] = pubKeys[idx] + sortedPowers[i] = powers[idx] + } + + return sortedOperatorAddrs, sortedPubKeys, sortedPowers } diff --git a/x/dogfood/keeper/genesis.go b/x/dogfood/keeper/genesis.go index e0544924d..76e3758a9 100644 --- a/x/dogfood/keeper/genesis.go +++ b/x/dogfood/keeper/genesis.go @@ -1,6 +1,8 @@ package keeper import ( + "fmt" + "github.com/ExocoreNetwork/exocore/x/dogfood/types" abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -21,13 +23,29 @@ func (k Keeper) InitGenesis( // is not running. it means that the genesis file is malformed. panic("epoch info not found") } - return k.ApplyValidatorChanges(ctx, genState.ValSet, types.InitialValidatorSetID, true) + // apply the same logic to the staking assets. + for _, assetID := range genState.Params.AssetIDs { + if !k.restakingKeeper.IsStakingAsset(ctx, assetID) { + panic(fmt.Errorf("staking asset %s not found", assetID)) + } + } + // genState must not be malformed. + // #nosec G701 // ok if 64-bit. + if len(genState.ValSet) > int(k.GetMaxValidators(ctx)) { + panic(fmt.Errorf( + "cannot have more than %d validators in the genesis state", + k.GetMaxValidators(ctx), + )) + } + return k.ApplyValidatorChanges( + ctx, genState.ValSet, types.InitialValidatorSetID, + ) } // ExportGenesis returns the module's exported genesis func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { genesis := types.DefaultGenesis() genesis.Params = k.GetDogfoodParams(ctx) - + // TODO(mm) return genesis } diff --git a/x/dogfood/keeper/impl_delegation_hooks.go b/x/dogfood/keeper/impl_delegation_hooks.go index e32442853..adbdc021e 100644 --- a/x/dogfood/keeper/impl_delegation_hooks.go +++ b/x/dogfood/keeper/impl_delegation_hooks.go @@ -22,100 +22,34 @@ func (k *Keeper) DelegationHooks() DelegationHooksWrapper { // AfterDelegation is called after a delegation is made. func (wrapper DelegationHooksWrapper) AfterDelegation( - ctx sdk.Context, operator sdk.AccAddress, + sdk.Context, sdk.AccAddress, ) { - found, pubKey, err := wrapper.keeper.operatorKeeper.GetOperatorConsKeyForChainId( - ctx, operator, ctx.ChainID(), - ) - if err != nil { - // the operator keeper can offer two errors: not an operator and not a chain. - // both of these should not happen here because the dogfooding genesis will - // register the chain, and the operator must be known to the delegation module - // when it calls this hook. - panic(err) - } - if found { - if !wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( - ctx, operator, ctx.ChainID(), - ) { - // only queue the operation if operator is still opted into the chain. - res := wrapper.keeper.QueueOperation( - ctx, operator, pubKey, types.KeyAdditionOrUpdate, - ) - switch res { - case types.QueueResultExists: - // nothing to do because the operation is in the queue already. - case types.QueueResultRemoved: - // a KeyRemoval was in the queue which has now been cleared from the queue. - // the KeyRemoval can only be in the queue if the operator is opting out from - // the chain, or has replaced their key. if it is the former, it means that - // there is some inconsistency. if it is the latter, it means that the operator - // module just reported the old key in `GetOperatorConsKeyForChainId`, which - // should not happen. - panic("unexpected removal of operation from queue") - case types.QueueResultSuccess: - // best case, nothing to do. - case types.QueueResultUnspecified: - panic("unspecified queue result") - } - } - } + // we do nothing here, since the vote power for all operators is calculated + // in the end separately. even if we knew the amount of the delegation, the + // average exchange rate for the epoch is unknown. } // AfterUndelegationStarted is called after an undelegation is started. func (wrapper DelegationHooksWrapper) AfterUndelegationStarted( ctx sdk.Context, operator sdk.AccAddress, recordKey []byte, ) { - found, pubKey, err := wrapper.keeper.operatorKeeper.GetOperatorConsKeyForChainId( + var unbondingCompletionEpoch int64 + if wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( ctx, operator, ctx.ChainID(), - ) - if err != nil { - panic(err) - } - if found { - // note that this is still key addition or update because undelegation does not remove - // the operator from the list. it only decreases their vote power. - if !wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( - ctx, operator, ctx.ChainID(), - ) { - // only queue the operation if operator is still opted into the chain. - res := wrapper.keeper.QueueOperation( - ctx, operator, pubKey, types.KeyAdditionOrUpdate, - ) - switch res { - case types.QueueResultExists: - // nothing to do - case types.QueueResultRemoved: - // KeyRemoval + KeyAdditionOrUpdate => Removed - // KeyRemoval can happen - // 1. if the operator is opting out from the chain,which is inconsistent. - // 2. if the operator is replacing their old key, which should not be returned - // by `GetOperatorConsKeyForChainId`. - panic("unexpected removal of operation from queue") - case types.QueueResultSuccess: - // best case, nothing to do. - case types.QueueResultUnspecified: - panic("unspecified queue result") - } - } - // now handle the unbonding timeline. - wrapper.keeper.delegationKeeper.IncrementUndelegationHoldCount(ctx, recordKey) - // mark for unbonding release. - // note that we aren't supporting redelegation yet, so this undelegated amount will be - // held until the end of the unbonding period or the operator opt out period, whichever - // is first. - var unbondingCompletionEpoch int64 - if wrapper.keeper.operatorKeeper.IsOperatorOptingOutFromChainId( - ctx, operator, ctx.ChainID(), - ) { - unbondingCompletionEpoch = wrapper.keeper.GetOperatorOptOutFinishEpoch( - ctx, operator, - ) - } else { - unbondingCompletionEpoch = wrapper.keeper.GetUnbondingCompletionEpoch(ctx) - } - wrapper.keeper.AppendUndelegationToMature(ctx, unbondingCompletionEpoch, recordKey) + ) { + // if the operator is opting out, we need to use the finish epoch of the opt out. + unbondingCompletionEpoch = wrapper.keeper.GetOperatorOptOutFinishEpoch(ctx, operator) + // even if the operator opts back in, the undelegated vote power does not reappear + // in the picture. slashable events between undelegation and opt in cannot occur + // because the operator is not in the validator set. + } else { + // otherwise, we use the default unbonding completion epoch. + unbondingCompletionEpoch = wrapper.keeper.GetUnbondingCompletionEpoch(ctx) + // if the operator opts out after this, the undelegation will mature before the opt out. + // so this is not a concern. } + wrapper.keeper.AppendUndelegationToMature(ctx, unbondingCompletionEpoch, recordKey) + wrapper.keeper.delegationKeeper.IncrementUndelegationHoldCount(ctx, recordKey) } // AfterUndelegationCompleted is called after an undelegation is completed. diff --git a/x/dogfood/keeper/impl_epochs_hooks.go b/x/dogfood/keeper/impl_epochs_hooks.go index c17314a89..c3bed17db 100644 --- a/x/dogfood/keeper/impl_epochs_hooks.go +++ b/x/dogfood/keeper/impl_epochs_hooks.go @@ -22,7 +22,7 @@ func (k *Keeper) EpochsHooks() EpochsHooksWrapper { return EpochsHooksWrapper{k} } -// AfterEpochEnd is called after an epoch ends. +// AfterEpochEnd is called after an epoch ends. It is called during the BeginBlock function. func (wrapper EpochsHooksWrapper) AfterEpochEnd( ctx sdk.Context, identifier string, epoch int64, ) { @@ -32,17 +32,19 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( // note that this hook is called during BeginBlock, and the "pending" operations will be // applied within this block. however, for clarity, it is highlighted that unbonding // takes N epochs + 1 block to complete. - operations := wrapper.keeper.GetQueuedOperations(ctx) - wrapper.keeper.SetPendingOperations(ctx, types.Operations{List: operations}) - wrapper.keeper.ClearQueuedOperations(ctx) + wrapper.keeper.MarkEpochEnd(ctx) + // find the opt outs that mature when this epoch ends, and move them to pending. optOuts := wrapper.keeper.GetOptOutsToFinish(ctx, epoch) wrapper.keeper.SetPendingOptOuts(ctx, types.AccountAddresses{List: optOuts}) wrapper.keeper.ClearOptOutsToFinish(ctx, epoch) + // next, find the consensus addresses that are to be pruned, and move them to pending. consAddresses := wrapper.keeper.GetConsensusAddrsToPrune(ctx, epoch) wrapper.keeper.SetPendingConsensusAddrs( ctx, types.ConsensusAddresses{List: consAddresses}, ) wrapper.keeper.ClearConsensusAddrsToPrune(ctx, epoch) + // finally, find the undelegations that mature when this epoch ends, and move them to + // pending. undelegations := wrapper.keeper.GetUndelegationsToMature(ctx, epoch) wrapper.keeper.SetPendingUndelegations( ctx, types.UndelegationRecordKeys{ @@ -56,5 +58,5 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( func (wrapper EpochsHooksWrapper) BeforeEpochStart( sdk.Context, string, int64, ) { - // nothing to do + // no-op } diff --git a/x/dogfood/keeper/impl_operator_hooks.go b/x/dogfood/keeper/impl_operator_hooks.go index 3599d6565..5e0d027bb 100644 --- a/x/dogfood/keeper/impl_operator_hooks.go +++ b/x/dogfood/keeper/impl_operator_hooks.go @@ -21,127 +21,36 @@ func (k *Keeper) OperatorHooks() OperatorHooksWrapper { return OperatorHooksWrapper{k} } -// Hooks assumptions: Assuming I is opt-in, O is opt-out and R is key replacement, these are all -// possible within the same epoch, for a fresh operator. -// I O -// I R -// I R O -// This is not possible for a fresh operator to do: -// I O R -// R I O -// R I -// For an operator that is already opted in, the list looks like follows: -// R O -// O I (reversing the decision to opt out) -// O I R -// R O I -// The impossible list looks like: -// O R -// O R I -// Replacing the key with the same key is not possible, so it is not covered. -// The assumption is that these are enforced (allowed/denied) by the operator module. - -// Cases for a fresh operator: -// I + O => KeyAdditionOrUpdate + KeyRemoval => Success + Removed => covered. -// I + R => KeyAdditionOrUpdate (old) + KeyAdditionOrUpdate (new) + KeyRemoval (old) => -// Success + Success + Removed + => not considered unbonding of the old key since it -// was not yet effective => covered. -// I + R + O => KeyAdditionOrUpdate (old) + KeyAdditionOrUpdate (new) + KeyRemoval (old) + -// KeyRemoval (new) => -// Success (old) + Success (new) + Removed (old) + Removed (new) => covered - -// Cases for an operator that has already opted in: -// R + O => KeyAdditionOrUpdate (new) + KeyRemoval (old) + KeyRemoval (new) => -// Success (new) + Success (old) + Removed (new) => -// unbonding data made (old) => covered. -// O + I -// O + I case 1 => KeyRemoval (old) + KeyAdditionOrUpdate (new) => Success (old) + Success (new) -// => unbonding data made (old) => covered. -// O + I case 2 => KeyRemoval (old) + KeyAdditionOrUpdate (old) => Success (old) + Removed (old) -// => unbonding data made (old) and then cleared => covered. -// O + I + R -// O + I + R case 1 => KeyRemoval (old) + KeyAdditionOrUpdate (old) + KeyRemoval (old) + -// KeyAdditionOrUpdate (new) => Success (old) + Removed (old) + Success (old) + -// Success (new) => unbonding data old made + cleared + made => covered. -// O + I + R case 2 => -// AfterOperatorOptOut(old) => Success => unbonding data made for old -// AfterOperatorOptIn(new) => Success => no data changed -// AfterOperatorKeyReplacement(new, new2) => -// new2 operation KeyAdditionOrUpdate => Success => no data changed -// new operation KeyRemoval => Removed => no data changed -// => covered -// R + O + I => KeyAdditionOrUpdate (new) + KeyRemoval (old) + KeyRemoval (new) + -// KeyAdditionOrUpdate (X) -// Success + Success (=> unbonding data for old) + Removed (=> no data) + -// case 1 => X == new => Success => no change => covered -// case 2 => X == old => Removed => unbonding data for old removed => covered. -// case 3 => X == abc => Success => no change and unbonding data for old is not removed => -// covered. - // AfterOperatorOptIn is the implementation of the operator hooks. func (h OperatorHooksWrapper) AfterOperatorOptIn( - ctx sdk.Context, addr sdk.AccAddress, - chainID string, pubKey tmprotocrypto.PublicKey, + ctx sdk.Context, addr sdk.AccAddress, chainID string, key tmprotocrypto.PublicKey, ) { - if strings.Compare(ctx.ChainID(), chainID) == 0 { - // res == Removed, it means operator has opted back in - // res == Success, there is no additional information to store - // res == Exists, there is nothing to do - if res := h.keeper.QueueOperation( - ctx, addr, pubKey, types.KeyAdditionOrUpdate, - ); res == types.QueueResultRemoved { - // the old operation was key removal, which is now removed from the queue. - // so all of the changes that were associated with it need to be undone. - h.keeper.ClearUnbondingInformation(ctx, addr, pubKey) - } + // an operator opting in does not meaningfully affect this module, since + // this information will be fetched at the end of the epoch + // and the operator's vote power will be calculated then. + // however, we will still clear the unbonding information, if it exists. + if strings.Compare(chainID, ctx.ChainID()) == 0 { + h.keeper.ClearUnbondingInformation(ctx, addr, key) } } // AfterOperatorKeyReplacement is the implementation of the operator hooks. func (h OperatorHooksWrapper) AfterOperatorKeyReplacement( - ctx sdk.Context, addr sdk.AccAddress, - newKey tmprotocrypto.PublicKey, oldKey tmprotocrypto.PublicKey, - chainID string, + ctx sdk.Context, operator sdk.AccAddress, oldKey tmprotocrypto.PublicKey, + newKey tmprotocrypto.PublicKey, chainID string, ) { if strings.Compare(chainID, ctx.ChainID()) == 0 { - // remove the old key - // res == Removed, it means operator had added this key and is now removing it. - // no additional information to clear. - // res == Success, the old key should be pruned from the operator module. - // res == Exists, there is nothing to do. - if res := h.keeper.QueueOperation( - ctx, addr, oldKey, types.KeyRemoval, - ); res == types.QueueResultSuccess { - // the old key can be marked for pruning - h.keeper.SetUnbondingInformation(ctx, addr, oldKey, false) - } - // add the new key - // res == Removed, it means operator has added their original key again - // res == Success, there is no additional information to store - // res == Exists, there is no nothing to do - if res := h.keeper.QueueOperation( - ctx, addr, newKey, types.KeyAdditionOrUpdate, - ); res == types.QueueResultRemoved { - // see AfterOperatorOptIn for explanation - h.keeper.ClearUnbondingInformation(ctx, addr, newKey) - } + // a key replacement means that the old key needs to be pruned upon maturity. + h.keeper.SetUnbondingInformation(ctx, operator, oldKey, false) + h.keeper.ClearUnbondingInformation(ctx, operator, newKey) } } // AfterOperatorOptOutInitiated is the implementation of the operator hooks. func (h OperatorHooksWrapper) AfterOperatorOptOutInitiated( - ctx sdk.Context, addr sdk.AccAddress, - chainID string, pubKey tmprotocrypto.PublicKey, + ctx sdk.Context, operator sdk.AccAddress, chainID string, key tmprotocrypto.PublicKey, ) { if strings.Compare(chainID, ctx.ChainID()) == 0 { - // res == Removed means operator had opted in and is now opting out. nothing to do if - // it is within the same epoch. - // res == Success, set up pruning deadline and opt out completion deadline - // res == Exists, there is nothing to do (should never happen) - if res := h.keeper.QueueOperation( - ctx, addr, pubKey, types.KeyRemoval, - ); res == types.QueueResultSuccess { - h.keeper.SetUnbondingInformation(ctx, addr, pubKey, true) - } + h.keeper.SetUnbondingInformation(ctx, operator, key, true) } } diff --git a/x/dogfood/keeper/keeper.go b/x/dogfood/keeper/keeper.go index e85f961d0..a0ba33e63 100644 --- a/x/dogfood/keeper/keeper.go +++ b/x/dogfood/keeper/keeper.go @@ -81,37 +81,26 @@ func (k Keeper) Hooks() types.DogfoodHooks { return k.dogfoodHooks } -// GetQueuedKeyOperations returns the list of operations that are queued for execution at the -// end of the current epoch. -func (k Keeper) GetQueuedOperations( - ctx sdk.Context, -) []types.Operation { +// MarkEpochEnd marks the end of the epoch. It is called within the BeginBlocker to inform +// the module to apply the validator updates at the end of this block. +func (k Keeper) MarkEpochEnd(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - bz := store.Get(types.QueuedOperationsKey()) - if bz == nil { - return []types.Operation{} - } - var operations types.Operations - if err := operations.Unmarshal(bz); err != nil { - // TODO(mm): any failure to unmarshal is treated as no operations or panic? - return []types.Operation{} - } - return operations.GetList() + key := types.EpochEndKey() + store.Set(key, []byte{1}) } -// ClearQueuedOperations clears the operations to be executed at the end of the epoch. -func (k Keeper) ClearQueuedOperations(ctx sdk.Context) { +// IsEpochEnd returns true if the epoch ended in the beginning of this block, or the end of the +// previous block. +func (k Keeper) IsEpochEnd(ctx sdk.Context) bool { store := ctx.KVStore(k.storeKey) - store.Delete(types.QueuedOperationsKey()) + key := types.EpochEndKey() + return store.Has(key) } -// setQueuedOperations is a private, internal function used to update the current queue of -// operations to be executed at the end of the epoch with the supplied value. -func (k Keeper) setQueuedOperations(ctx sdk.Context, operations types.Operations) { +// ClearEpochEnd clears the epoch end marker. It is called after the epoch end operations are +// applied. +func (k Keeper) ClearEpochEnd(ctx sdk.Context) { store := ctx.KVStore(k.storeKey) - bz, err := operations.Marshal() - if err != nil { - panic(err) - } - store.Set(types.QueuedOperationsKey(), bz) + key := types.EpochEndKey() + store.Delete(key) } diff --git a/x/dogfood/keeper/params.go b/x/dogfood/keeper/params.go index f2bb7af60..782f57921 100644 --- a/x/dogfood/keeper/params.go +++ b/x/dogfood/keeper/params.go @@ -3,6 +3,7 @@ package keeper import ( "github.com/ExocoreNetwork/exocore/x/dogfood/types" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // GetEpochsUntilUnbonded returns the number of epochs after which an unbonding that is made @@ -25,7 +26,7 @@ func (k Keeper) GetEpochIdentifier(ctx sdk.Context) string { // the chain. It is a parameter of the dogfood module. func (k Keeper) GetMaxValidators(ctx sdk.Context) uint32 { var maxValidators uint32 - k.paramstore.Get(ctx, types.KeyMaxValidators, &maxValidators) + k.paramstore.Get(ctx, stakingtypes.KeyMaxValidators, &maxValidators) return maxValidators } @@ -33,10 +34,18 @@ func (k Keeper) GetMaxValidators(ctx sdk.Context) uint32 { // entries are used by the IBC module. The return value is a parameter of the dogfood module. func (k Keeper) GetHistoricalEntries(ctx sdk.Context) uint32 { var historicalEntries uint32 - k.paramstore.Get(ctx, types.KeyHistoricalEntries, &historicalEntries) + k.paramstore.Get(ctx, stakingtypes.KeyHistoricalEntries, &historicalEntries) return historicalEntries } +// GetAssetIDs returns the asset IDs that are accepted by the dogfood module. It is a parameter +// of the dogfood module. +func (k Keeper) GetAssetIDs(ctx sdk.Context) []string { + var assetIDs []string + k.paramstore.Get(ctx, types.KeyAssetIDs, &assetIDs) + return assetIDs +} + // SetParams sets the params for the dogfood module. func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { k.paramstore.SetParamSet(ctx, ¶ms) @@ -52,5 +61,6 @@ func (k Keeper) GetDogfoodParams(ctx sdk.Context) (params types.Params) { k.GetEpochIdentifier(ctx), k.GetMaxValidators(ctx), k.GetHistoricalEntries(ctx), + k.GetAssetIDs(ctx), ) } diff --git a/x/dogfood/keeper/pending.go b/x/dogfood/keeper/pending.go index 9bf05ae17..e3cf92288 100644 --- a/x/dogfood/keeper/pending.go +++ b/x/dogfood/keeper/pending.go @@ -5,36 +5,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// SetPendingOperations sets the pending operations to be applied at the end of the block. -func (k Keeper) SetPendingOperations(ctx sdk.Context, operations types.Operations) { - store := ctx.KVStore(k.storeKey) - bz, err := operations.Marshal() - if err != nil { - panic(err) - } - store.Set(types.PendingOperationsKey(), bz) -} - -// GetPendingOperations returns the pending operations to be applied at the end of the block. -func (k Keeper) GetPendingOperations(ctx sdk.Context) types.Operations { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.PendingOperationsKey()) - if bz == nil { - return types.Operations{} - } - var operations types.Operations - if err := operations.Unmarshal(bz); err != nil { - return types.Operations{} - } - return operations -} - -// ClearPendingOperations clears the pending operations to be applied at the end of the block. -func (k Keeper) ClearPendingOperations(ctx sdk.Context) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.PendingOperationsKey()) -} - // SetPendingOptOuts sets the pending opt-outs to be applied at the end of the block. func (k Keeper) SetPendingOptOuts(ctx sdk.Context, addrs types.AccountAddresses) { store := ctx.KVStore(k.storeKey) diff --git a/x/dogfood/keeper/queue.go b/x/dogfood/keeper/queue.go deleted file mode 100644 index 07cedfb32..000000000 --- a/x/dogfood/keeper/queue.go +++ /dev/null @@ -1,45 +0,0 @@ -package keeper - -import ( - "github.com/ExocoreNetwork/exocore/x/dogfood/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -// QueueOperation adds an operation to the consensus public key queue. If a similar operation -// already exists, the queue is not modified and QueueResultExists is returned. If a reverse -// operation already exists (removal + addition, or addition + removal), the old operation is -// dropped from the queue and QueueResultRemoved is returned. In the case that the operation is -// added to the queue, QueueResultSuccess is returned. -func (k Keeper) QueueOperation( - ctx sdk.Context, addr sdk.AccAddress, - key tmprotocrypto.PublicKey, operationType types.OperationType, -) types.QueueResultType { - if operationType == types.KeyOpUnspecified { - // should never happen - panic("invalid operation type") - } - currentQueue := k.GetQueuedOperations(ctx) - indexToDelete := len(currentQueue) - for i, operation := range currentQueue { - if operation.PubKey.Equal(key) { - if operation.OperationType == operationType { - return types.QueueResultExists - } - // reverse operation exists, remove it - indexToDelete = i - break - } - } - ret := types.QueueResultSuccess - if indexToDelete > len(currentQueue) { - currentQueue = append(currentQueue[:indexToDelete], currentQueue[indexToDelete+1:]...) - ret = types.QueueResultRemoved - } else { - operation := types.Operation{OperationType: operationType, OperatorAddress: addr, PubKey: key} - currentQueue = append(currentQueue, operation) - } - operations := types.Operations{List: currentQueue} - k.setQueuedOperations(ctx, operations) - return ret -} diff --git a/x/dogfood/keeper/unbonding.go b/x/dogfood/keeper/unbonding.go index 4070c87dc..4092acc8c 100644 --- a/x/dogfood/keeper/unbonding.go +++ b/x/dogfood/keeper/unbonding.go @@ -17,7 +17,7 @@ func (k Keeper) ClearUnbondingInformation( k.RemoveOptOutToFinish(ctx, optOutEpoch, addr) consAddress, err := types.TMCryptoPublicKeyToConsAddr(pubKey) if err != nil { - panic(err) + return } k.DeleteConsensusAddrToPrune(ctx, optOutEpoch, consAddress) } @@ -27,13 +27,13 @@ func (k Keeper) SetUnbondingInformation( ctx sdk.Context, addr sdk.AccAddress, pubKey tmprotocrypto.PublicKey, isOptingOut bool, ) { unbondingCompletionEpoch := k.GetUnbondingCompletionEpoch(ctx) - k.AppendOptOutToFinish(ctx, unbondingCompletionEpoch, addr) if isOptingOut { + k.AppendOptOutToFinish(ctx, unbondingCompletionEpoch, addr) k.SetOperatorOptOutFinishEpoch(ctx, addr, unbondingCompletionEpoch) } consAddress, err := types.TMCryptoPublicKeyToConsAddr(pubKey) if err != nil { - panic(err) + return } k.AppendConsensusAddrToPrune(ctx, unbondingCompletionEpoch, consAddress) } @@ -44,12 +44,9 @@ func (k Keeper) GetUnbondingCompletionEpoch( ctx sdk.Context, ) int64 { unbondingEpochs := k.GetEpochsUntilUnbonded(ctx) - epochInfo, found := k.epochsKeeper.GetEpochInfo( + epochInfo, _ := k.epochsKeeper.GetEpochInfo( ctx, k.GetEpochIdentifier(ctx), ) - if !found { - panic("current epoch not found") - } // if i execute the transaction at epoch 5, the vote power change // goes into effect at the beginning of epoch 6. the information // should be held for 7 epochs, so it should be deleted at the diff --git a/x/dogfood/keeper/validators.go b/x/dogfood/keeper/validators.go index 13336a37f..df67cb234 100644 --- a/x/dogfood/keeper/validators.go +++ b/x/dogfood/keeper/validators.go @@ -30,11 +30,11 @@ func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration { // ApplyValidatorChanges returns the validator set as is. However, it also // stores the validators that are added or those that are removed, and updates -// the power for the existing validators. It also allows any hooks registered +// the stored power for the existing validators. It also allows any hooks registered // on the keeper to be executed. Lastly, it stores the validator set against the // provided validator set id. func (k Keeper) ApplyValidatorChanges( - ctx sdk.Context, changes []abci.ValidatorUpdate, valSetID uint64, genesis bool, + ctx sdk.Context, changes []abci.ValidatorUpdate, valSetID uint64, ) []abci.ValidatorUpdate { ret := []abci.ValidatorUpdate{} for _, change := range changes { @@ -42,16 +42,20 @@ func (k Keeper) ApplyValidatorChanges( pubkey, err := cryptocodec.FromTmProtoPublicKey(change.GetPubKey()) if err != nil { // An error here would indicate that this change is invalid. - // In no situation it should happen, however, if it does, + // The change is received either from the genesis file, or from + // other parts of the module. + // In no situation it should happen; however, if it does, // we do not panic. Simply skip the change. continue } + // the address is just derived from the public key and + // has no correlation with the operator address on Exocore. addr := pubkey.Address() val, found := k.GetValidator(ctx, addr) - switch found { case true: - // update or delete an existing validator + // update or delete an existing validator. + // assumption: power can not be negative. if change.Power < 1 { k.DeleteValidator(ctx, addr) } else { @@ -60,12 +64,12 @@ func (k Keeper) ApplyValidatorChanges( } case false: if change.Power > 0 { - // create a new validator - the address is just derived from the public key and - // has no correlation with the operator address on Exocore + // create a new validator. ocVal, err := types.NewExocoreValidator(addr, change.Power, pubkey) if err != nil { continue } + // guard for errors within the AfterValidatorBonded hook. cc, writeFunc := ctx.CacheContext() k.SetValidator(cc, ocVal) err = k.Hooks().AfterValidatorBonded(cc, sdk.ConsAddress(addr), nil) @@ -84,7 +88,7 @@ func (k Keeper) ApplyValidatorChanges( ret = append(ret, change) } - // store the validator set against the provided validator set id + // store the updated validator set against the provided validator set id lastVals := types.Validators{} for _, v := range k.GetAllExocoreValidators(ctx) { // we stored the validators above, so this will never fail. @@ -97,16 +101,15 @@ func (k Keeper) ApplyValidatorChanges( val.Status = stakingtypes.Bonded // Compute tokens from voting power val.Tokens = sdk.TokensFromConsensusPower(v.Power, sdk.DefaultPowerReduction) - lastVals.List = append(lastVals.GetList(), val) + lastVals.List = append(lastVals.List, val) } k.setValidatorSet(ctx, valSetID, &lastVals) - if !genesis { - // the val set change is effective as of the next block, so height + 1. - k.setValidatorSetID(ctx, ctx.BlockHeight()+1, valSetID) - } else { - // the val set change is effective immediately. - k.setValidatorSetID(ctx, ctx.BlockHeight(), valSetID) - } + // this validator set is effective as of the next block, so use height + 1. + // this statement is true for genesis as well, since ctx.BlockHeight() is + // reported as 0 during InitGenesis. + k.setValidatorSetID(ctx, ctx.BlockHeight()+1, valSetID) + // store this to compare against, in the next round. + k.saveKeyPowerMapping(ctx, ret) return ret } @@ -227,8 +230,8 @@ func (k Keeper) deleteValidatorSet(ctx sdk.Context, id uint64) { // event. Otherwise, it is constant. The header, however, will change at every block. Since // the Cosmos SDK does not allow for the retrieval of a past block header, we store the header // ourselves in this function. The validator set is stored when it changes at the end of an -// epoch or at a slashing event in the corresponding functions. It is called within the EndBlock -// of the module, so it is kept public. +// epoch or at a slashing event in the corresponding functions. The function is called within +// the EndBlock of the module, so it is kept public. func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { // Get the number of historical entries to persist, as the number of block heights. // #nosec G701 // uint32 fits into int64 always. @@ -253,9 +256,16 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { break } } + // even if numHistoricalEntries is 0, this will work because it is called after the + // validatorSetID for height + 1 is stored. + // on the opposite side of things, if numHistoricalEntries is too large, currentID + // will be 0, and the loop will not run. currentID, _ := k.getValidatorSetID(ctx, ctx.BlockHeight()-numHistoricalEntries+1, ) + // lastDeletedID will be the lowest deleted id since we are working backwards + // from the latest height to the oldest height. this, and upto but not including + // currentID, are the ids to delete. for i := lastDeletedID; i < currentID; i++ { k.deleteValidatorSet(ctx, i) } @@ -269,7 +279,7 @@ func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) { k.storeBlockHeader(ctx) // we have stored: - // before TrackHistoricalInfo: ValidatorSetID for height, and the validator set. + // outside of TrackHistoricalInfo: ValidatorSetID for height, and the validator set. // within TrackHistoricalInfo: the header. // this is enough information to answer the GetHistoricalInfo query. } @@ -373,3 +383,28 @@ func (k Keeper) storeBlockHeader(ctx sdk.Context) { value := k.cdc.MustMarshal(&header) store.Set(key, value) } + +// saveKeyPowerMapping stores a mapping from the key string to the power. +func (k Keeper) saveKeyPowerMapping(ctx sdk.Context, updates []abci.ValidatorUpdate) { + store := ctx.KVStore(k.storeKey) + m := make(map[string]int64, len(updates)) + for _, update := range updates { + // do not use the stringer interface here so that it can be deserialized. + key := update.PubKey // prevent implicit memory aliasing. + m[string(k.cdc.MustMarshal(&key))] = update.Power + } + bz := k.cdc.MustMarshal(&types.KeyPowerMapping{List: m}) + store.Set(types.KeyPowerMappingKey(), bz) +} + +// getKeyPowerMapping gets the most recently stored mapping from the key string to the power. +func (k Keeper) getKeyPowerMapping(ctx sdk.Context) types.KeyPowerMapping { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.KeyPowerMappingKey()) + if bz == nil { + return types.KeyPowerMapping{} + } + var updates types.KeyPowerMapping + k.cdc.MustUnmarshal(bz, &updates) + return updates +} diff --git a/x/dogfood/module.go b/x/dogfood/module.go index 44483fd37..1f0b36e58 100644 --- a/x/dogfood/module.go +++ b/x/dogfood/module.go @@ -163,5 +163,7 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} // EndBlock contains the logic that is automatically triggered at the end of each block func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - return am.keeper.EndBlock(ctx) + ret := am.keeper.EndBlock(ctx) + am.keeper.TrackHistoricalInfo(ctx) + return ret } diff --git a/x/dogfood/types/dogfood.pb.go b/x/dogfood/types/dogfood.pb.go index 876f5c4c1..56424d7ad 100644 --- a/x/dogfood/types/dogfood.pb.go +++ b/x/dogfood/types/dogfood.pb.go @@ -5,7 +5,6 @@ package types import ( fmt "fmt" - crypto "github.com/cometbft/cometbft/proto/tendermint/crypto" _ "github.com/cosmos/cosmos-proto" types "github.com/cosmos/cosmos-sdk/codec/types" types1 "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -31,79 +30,6 @@ var _ = time.Kitchen // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package -// OperationType is used to indicate the type of operation that is being -// cached by the module to create the updated validator set. -type OperationType int32 - -const ( - // KeyOpUnspecified is used to indicate that the operation type is not specified. - // This should never be used. - KeyOpUnspecified OperationType = 0 - // KeyAddition is used to indicate that the operation is a key addition. - KeyAdditionOrUpdate OperationType = 1 - // KeyRemoval is used to indicate that the operation is a key removal. Typically - // this is done due to key replacement mechanism and not directly. - KeyRemoval OperationType = 2 -) - -var OperationType_name = map[int32]string{ - 0: "OPERATION_TYPE_UNSPECIFIED", - 1: "OPERATION_TYPE_ADDITION_OR_UPDATE", - 2: "OPERATION_TYPE_REMOVAL", -} - -var OperationType_value = map[string]int32{ - "OPERATION_TYPE_UNSPECIFIED": 0, - "OPERATION_TYPE_ADDITION_OR_UPDATE": 1, - "OPERATION_TYPE_REMOVAL": 2, -} - -func (x OperationType) String() string { - return proto.EnumName(OperationType_name, int32(x)) -} - -func (OperationType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{0} -} - -// QueueResultType is used to indicate the result of the queue operation. -type QueueResultType int32 - -const ( - // QueueResultUnspecified is used to indicate that the queue result type is not specified. - QueueResultUnspecified QueueResultType = 0 - // QueueResultSuccess is used to indicate that the queue operation was successful. - QueueResultSuccess QueueResultType = 1 - // QueueResultExists is used to indicate that the queue operation failed because the - // operation already exists in the queue. - QueueResultExists QueueResultType = 2 - // QueueResultRemoved is used to indicate that the queue operation resulted in an existing - // operation being removed from the queue. - QueueResultRemoved QueueResultType = 3 -) - -var QueueResultType_name = map[int32]string{ - 0: "QUEUE_RESULT_TYPE_UNSPECIFIED", - 1: "QUEUE_RESULT_TYPE_SUCCESS", - 2: "QUEUE_RESULT_TYPE_EXISTS", - 3: "QUEUE_RESULT_TYPE_REMOVED", -} - -var QueueResultType_value = map[string]int32{ - "QUEUE_RESULT_TYPE_UNSPECIFIED": 0, - "QUEUE_RESULT_TYPE_SUCCESS": 1, - "QUEUE_RESULT_TYPE_EXISTS": 2, - "QUEUE_RESULT_TYPE_REMOVED": 3, -} - -func (x QueueResultType) String() string { - return proto.EnumName(QueueResultType_name, int32(x)) -} - -func (QueueResultType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{1} -} - // ExocoreValidator is a validator that is part of the Exocore network. It is // used to validate and sign blocks and transactions. type ExocoreValidator struct { @@ -170,117 +96,6 @@ func (m *ExocoreValidator) GetPubkey() *types.Any { return nil } -// Operation is used to indicate the operation that is being cached by the module -// to create the updated validator set. -type Operation struct { - // OperationType is the type of the operation (addition / removal). - OperationType OperationType `protobuf:"varint,1,opt,name=operation_type,json=operationType,proto3,enum=exocore.dogfood.v1.OperationType" json:"operation_type,omitempty"` - // OperatorAddress is the sdk.AccAddress of the operator. - OperatorAddress []byte `protobuf:"bytes,2,opt,name=operator_address,json=operatorAddress,proto3" json:"operator_address,omitempty"` - // PubKey is the public key for which the operation is being applied. - PubKey crypto.PublicKey `protobuf:"bytes,3,opt,name=pub_key,json=pubKey,proto3" json:"pub_key"` -} - -func (m *Operation) Reset() { *m = Operation{} } -func (m *Operation) String() string { return proto.CompactTextString(m) } -func (*Operation) ProtoMessage() {} -func (*Operation) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{1} -} -func (m *Operation) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Operation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Operation.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 *Operation) XXX_Merge(src proto.Message) { - xxx_messageInfo_Operation.Merge(m, src) -} -func (m *Operation) XXX_Size() int { - return m.Size() -} -func (m *Operation) XXX_DiscardUnknown() { - xxx_messageInfo_Operation.DiscardUnknown(m) -} - -var xxx_messageInfo_Operation proto.InternalMessageInfo - -func (m *Operation) GetOperationType() OperationType { - if m != nil { - return m.OperationType - } - return KeyOpUnspecified -} - -func (m *Operation) GetOperatorAddress() []byte { - if m != nil { - return m.OperatorAddress - } - return nil -} - -func (m *Operation) GetPubKey() crypto.PublicKey { - if m != nil { - return m.PubKey - } - return crypto.PublicKey{} -} - -// Operations is a collection of Operation. -type Operations struct { - // list is the list of operations. - List []Operation `protobuf:"bytes,1,rep,name=list,proto3" json:"list"` -} - -func (m *Operations) Reset() { *m = Operations{} } -func (m *Operations) String() string { return proto.CompactTextString(m) } -func (*Operations) ProtoMessage() {} -func (*Operations) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{2} -} -func (m *Operations) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *Operations) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_Operations.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 *Operations) XXX_Merge(src proto.Message) { - xxx_messageInfo_Operations.Merge(m, src) -} -func (m *Operations) XXX_Size() int { - return m.Size() -} -func (m *Operations) XXX_DiscardUnknown() { - xxx_messageInfo_Operations.DiscardUnknown(m) -} - -var xxx_messageInfo_Operations proto.InternalMessageInfo - -func (m *Operations) GetList() []Operation { - if m != nil { - return m.List - } - return nil -} - // AccountAddresses represents a list of account addresses. It is used to store the list of // operator addresses whose operations are maturing at an epoch. type AccountAddresses struct { @@ -292,7 +107,7 @@ func (m *AccountAddresses) Reset() { *m = AccountAddresses{} } func (m *AccountAddresses) String() string { return proto.CompactTextString(m) } func (*AccountAddresses) ProtoMessage() {} func (*AccountAddresses) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{3} + return fileDescriptor_071b9989c501c3f2, []int{1} } func (m *AccountAddresses) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -339,7 +154,7 @@ func (m *ConsensusAddresses) Reset() { *m = ConsensusAddresses{} } func (m *ConsensusAddresses) String() string { return proto.CompactTextString(m) } func (*ConsensusAddresses) ProtoMessage() {} func (*ConsensusAddresses) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{4} + return fileDescriptor_071b9989c501c3f2, []int{2} } func (m *ConsensusAddresses) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -386,7 +201,7 @@ func (m *UndelegationRecordKeys) Reset() { *m = UndelegationRecordKeys{} func (m *UndelegationRecordKeys) String() string { return proto.CompactTextString(m) } func (*UndelegationRecordKeys) ProtoMessage() {} func (*UndelegationRecordKeys) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{5} + return fileDescriptor_071b9989c501c3f2, []int{3} } func (m *UndelegationRecordKeys) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -432,7 +247,7 @@ func (m *Validators) Reset() { *m = Validators{} } func (m *Validators) String() string { return proto.CompactTextString(m) } func (*Validators) ProtoMessage() {} func (*Validators) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{6} + return fileDescriptor_071b9989c501c3f2, []int{4} } func (m *Validators) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -484,7 +299,7 @@ func (m *HeaderSubset) Reset() { *m = HeaderSubset{} } func (m *HeaderSubset) String() string { return proto.CompactTextString(m) } func (*HeaderSubset) ProtoMessage() {} func (*HeaderSubset) Descriptor() ([]byte, []int) { - return fileDescriptor_071b9989c501c3f2, []int{7} + return fileDescriptor_071b9989c501c3f2, []int{5} } func (m *HeaderSubset) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -534,77 +349,104 @@ func (m *HeaderSubset) GetAppHash() []byte { return nil } +// KeyPowerMapping is a mapping of the consensus public key (as a string) +// to the power of the key. +type KeyPowerMapping struct { + // list is the actual mapping of the consensus public key to the power. + List map[string]int64 `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"` +} + +func (m *KeyPowerMapping) Reset() { *m = KeyPowerMapping{} } +func (m *KeyPowerMapping) String() string { return proto.CompactTextString(m) } +func (*KeyPowerMapping) ProtoMessage() {} +func (*KeyPowerMapping) Descriptor() ([]byte, []int) { + return fileDescriptor_071b9989c501c3f2, []int{6} +} +func (m *KeyPowerMapping) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *KeyPowerMapping) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_KeyPowerMapping.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 *KeyPowerMapping) XXX_Merge(src proto.Message) { + xxx_messageInfo_KeyPowerMapping.Merge(m, src) +} +func (m *KeyPowerMapping) XXX_Size() int { + return m.Size() +} +func (m *KeyPowerMapping) XXX_DiscardUnknown() { + xxx_messageInfo_KeyPowerMapping.DiscardUnknown(m) +} + +var xxx_messageInfo_KeyPowerMapping proto.InternalMessageInfo + +func (m *KeyPowerMapping) GetList() map[string]int64 { + if m != nil { + return m.List + } + return nil +} + func init() { - proto.RegisterEnum("exocore.dogfood.v1.OperationType", OperationType_name, OperationType_value) - proto.RegisterEnum("exocore.dogfood.v1.QueueResultType", QueueResultType_name, QueueResultType_value) proto.RegisterType((*ExocoreValidator)(nil), "exocore.dogfood.v1.ExocoreValidator") - proto.RegisterType((*Operation)(nil), "exocore.dogfood.v1.Operation") - proto.RegisterType((*Operations)(nil), "exocore.dogfood.v1.Operations") proto.RegisterType((*AccountAddresses)(nil), "exocore.dogfood.v1.AccountAddresses") proto.RegisterType((*ConsensusAddresses)(nil), "exocore.dogfood.v1.ConsensusAddresses") proto.RegisterType((*UndelegationRecordKeys)(nil), "exocore.dogfood.v1.UndelegationRecordKeys") proto.RegisterType((*Validators)(nil), "exocore.dogfood.v1.Validators") proto.RegisterType((*HeaderSubset)(nil), "exocore.dogfood.v1.HeaderSubset") + proto.RegisterType((*KeyPowerMapping)(nil), "exocore.dogfood.v1.KeyPowerMapping") + proto.RegisterMapType((map[string]int64)(nil), "exocore.dogfood.v1.KeyPowerMapping.ListEntry") } func init() { proto.RegisterFile("exocore/dogfood/v1/dogfood.proto", fileDescriptor_071b9989c501c3f2) } var fileDescriptor_071b9989c501c3f2 = []byte{ - // 857 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x54, 0x41, 0x6f, 0xe3, 0x44, - 0x14, 0x8e, 0x9b, 0xb2, 0xbb, 0x4c, 0xbb, 0x5d, 0x33, 0x84, 0x6e, 0x6a, 0xed, 0xa6, 0x6e, 0x84, - 0x50, 0xa8, 0xc0, 0x26, 0x2d, 0x08, 0x04, 0x02, 0x29, 0x6d, 0x8c, 0x1a, 0x65, 0x69, 0xb2, 0x76, - 0xbc, 0x02, 0x2e, 0x96, 0x63, 0xbf, 0xa6, 0x56, 0x13, 0x8f, 0xe5, 0x19, 0x67, 0xeb, 0x7f, 0x80, - 0x72, 0xda, 0x0b, 0xc7, 0x9c, 0x10, 0xff, 0x00, 0x89, 0x13, 0xf7, 0x15, 0xa7, 0x3d, 0x72, 0x5a, - 0x50, 0xfb, 0x0f, 0xb8, 0x71, 0x43, 0xb6, 0xc7, 0xa9, 0xb7, 0xa9, 0x7a, 0x9b, 0x37, 0xef, 0x7d, - 0xf3, 0xbe, 0x6f, 0xe6, 0x9b, 0x87, 0x64, 0x38, 0x27, 0x0e, 0x09, 0x41, 0x75, 0xc9, 0xe8, 0x84, - 0x10, 0x57, 0x9d, 0x36, 0xf3, 0xa5, 0x12, 0x84, 0x84, 0x11, 0x8c, 0x79, 0x85, 0x92, 0x6f, 0x4f, - 0x9b, 0x52, 0x65, 0x44, 0x46, 0x24, 0x4d, 0xab, 0xc9, 0x2a, 0xab, 0x94, 0xb6, 0x46, 0x84, 0x8c, - 0xc6, 0xa0, 0xa6, 0xd1, 0x30, 0x3a, 0x51, 0x6d, 0x3f, 0xe6, 0xa9, 0xed, 0xeb, 0x29, 0xe6, 0x4d, - 0x80, 0x32, 0x7b, 0x12, 0xf0, 0x82, 0xf7, 0x1d, 0x42, 0x27, 0x84, 0xaa, 0x94, 0xd9, 0x67, 0x9e, - 0x3f, 0x52, 0xa7, 0xcd, 0x21, 0x30, 0xbb, 0x99, 0xc7, 0x79, 0x87, 0xac, 0xca, 0xca, 0x5a, 0x67, - 0x01, 0x4f, 0x3d, 0x62, 0xe0, 0xbb, 0x10, 0x4e, 0x3c, 0x9f, 0xa9, 0x4e, 0x18, 0x07, 0x8c, 0xa8, - 0x67, 0x10, 0xf3, 0x6c, 0xfd, 0x57, 0x01, 0x89, 0x5a, 0xa6, 0xe3, 0x99, 0x3d, 0xf6, 0x5c, 0x9b, - 0x91, 0x10, 0x57, 0xd1, 0x5d, 0xdb, 0x75, 0x43, 0xa0, 0xb4, 0x2a, 0xc8, 0x42, 0x63, 0x5d, 0xcf, - 0x43, 0x5c, 0x41, 0x6f, 0x05, 0xe4, 0x39, 0x84, 0xd5, 0x15, 0x59, 0x68, 0x94, 0xf5, 0x2c, 0xc0, - 0x36, 0xba, 0x13, 0x44, 0xc3, 0x33, 0x88, 0xab, 0x65, 0x59, 0x68, 0xac, 0xed, 0x55, 0x94, 0x4c, - 0x95, 0x92, 0xab, 0x52, 0x5a, 0x7e, 0x7c, 0xb0, 0xff, 0xef, 0xeb, 0xed, 0x87, 0xb1, 0x3d, 0x19, - 0x7f, 0x59, 0x77, 0x88, 0x4f, 0xc1, 0xa7, 0x11, 0xb5, 0x32, 0x5c, 0xfd, 0xcf, 0xdf, 0x3e, 0xae, - 0x70, 0xd6, 0x19, 0x47, 0xa5, 0x1f, 0x0d, 0xbb, 0x10, 0xeb, 0xfc, 0xe0, 0xfa, 0x1f, 0x02, 0x7a, - 0xbb, 0x17, 0x40, 0x68, 0x33, 0x8f, 0xf8, 0xf8, 0x08, 0x6d, 0x90, 0x3c, 0xb0, 0x58, 0x1c, 0x40, - 0xca, 0x73, 0x63, 0x6f, 0x47, 0x59, 0x7e, 0x13, 0x65, 0x01, 0x1b, 0xc4, 0x01, 0xe8, 0xf7, 0x49, - 0x31, 0xc4, 0x1f, 0x22, 0x31, 0xdb, 0x20, 0xa1, 0x95, 0x6b, 0x5e, 0x49, 0x35, 0x3f, 0xc8, 0xf7, - 0x5b, 0x5c, 0xfb, 0x57, 0xe8, 0x6e, 0x10, 0x0d, 0xad, 0x2b, 0x99, 0x8f, 0x94, 0xab, 0xab, 0x2d, - 0xd0, 0x1e, 0x7b, 0x4e, 0x17, 0xe2, 0x83, 0xd5, 0x97, 0xaf, 0xb7, 0x4b, 0x29, 0xff, 0x2e, 0xc4, - 0x75, 0x0d, 0xa1, 0x05, 0x0f, 0x8a, 0x3f, 0x47, 0xab, 0x63, 0x8f, 0xb2, 0xaa, 0x20, 0x97, 0x1b, - 0x6b, 0x7b, 0x8f, 0x6f, 0x65, 0xcd, 0x0f, 0x4a, 0x01, 0xf5, 0x0f, 0x90, 0xd8, 0x72, 0x1c, 0x12, - 0xf9, 0x8c, 0xb3, 0x02, 0x8a, 0x71, 0xe1, 0xb0, 0x75, 0x5e, 0xd7, 0x40, 0xf8, 0x30, 0xbf, 0xe3, - 0xdb, 0x2b, 0x3f, 0x42, 0x9b, 0xa6, 0xef, 0xc2, 0x18, 0x46, 0x69, 0x37, 0x1d, 0x1c, 0x12, 0xba, - 0x5d, 0x88, 0x6f, 0xae, 0xee, 0x20, 0xb4, 0xb0, 0x49, 0x72, 0x23, 0x45, 0x19, 0x3b, 0x0a, 0x7f, - 0xc1, 0xdc, 0x9a, 0xdc, 0xaa, 0xca, 0x02, 0xf1, 0x86, 0x94, 0x9f, 0x05, 0xb4, 0x7e, 0x04, 0xb6, - 0x0b, 0xa1, 0x11, 0x0d, 0x29, 0x30, 0xfc, 0x05, 0x5a, 0x4d, 0xcc, 0x9f, 0x3e, 0xe5, 0xda, 0x9e, - 0xb4, 0xe4, 0xa1, 0x41, 0xfe, 0x33, 0x0e, 0xee, 0x25, 0xc7, 0xbc, 0xf8, 0x7b, 0x5b, 0xd0, 0x53, - 0x04, 0xfe, 0x04, 0x55, 0x7c, 0x38, 0x67, 0xd6, 0x74, 0x41, 0xcd, 0x3a, 0xb5, 0xe9, 0x29, 0x7f, - 0x48, 0x9c, 0xe4, 0xae, 0x58, 0x1f, 0xd9, 0xf4, 0x14, 0x6f, 0xa1, 0x7b, 0x76, 0x10, 0x64, 0x55, - 0x65, 0x6e, 0xf1, 0x20, 0x48, 0x52, 0xbb, 0xbf, 0x0b, 0xe8, 0xfe, 0x1b, 0x96, 0xc1, 0x9f, 0x22, - 0xa9, 0xd7, 0xd7, 0xf4, 0xd6, 0xa0, 0xd3, 0x3b, 0xb6, 0x06, 0x3f, 0xf4, 0x35, 0xcb, 0x3c, 0x36, - 0xfa, 0xda, 0x61, 0xe7, 0xdb, 0x8e, 0xd6, 0x16, 0x4b, 0x52, 0x65, 0x36, 0x97, 0xc5, 0x2e, 0xc4, - 0xbd, 0xc0, 0xf4, 0x69, 0x00, 0x8e, 0x77, 0xe2, 0x81, 0x8b, 0xbf, 0x41, 0x3b, 0xd7, 0x50, 0xad, - 0x76, 0xbb, 0x93, 0x46, 0x3d, 0xdd, 0x32, 0xfb, 0xed, 0xd6, 0x40, 0x13, 0x05, 0xe9, 0xe1, 0x6c, - 0x2e, 0xbf, 0xdb, 0x85, 0xb8, 0xe5, 0xba, 0x5e, 0xd2, 0xb1, 0x17, 0x9a, 0x81, 0x6b, 0x33, 0xc0, - 0xbb, 0x68, 0xf3, 0x1a, 0x5e, 0xd7, 0xbe, 0xeb, 0x3d, 0x6b, 0x3d, 0x11, 0x57, 0xa4, 0x8d, 0xd9, - 0x5c, 0x46, 0xc9, 0xf7, 0x80, 0x09, 0x99, 0xda, 0x63, 0x69, 0xf5, 0xa7, 0x5f, 0x6a, 0xa5, 0xdd, - 0xff, 0x04, 0xf4, 0xe0, 0x69, 0x04, 0x11, 0xe8, 0x40, 0xa3, 0x31, 0x4b, 0xb9, 0x7f, 0x8d, 0x1e, - 0x3f, 0x35, 0x35, 0x33, 0x01, 0x1b, 0xe6, 0x93, 0xc1, 0x4d, 0xf4, 0xa5, 0xd9, 0x5c, 0xde, 0x2c, - 0xe0, 0x8a, 0x22, 0x3e, 0x43, 0x5b, 0xcb, 0x70, 0xc3, 0x3c, 0x3c, 0xd4, 0x0c, 0x43, 0x14, 0xa4, - 0xcd, 0xd9, 0x5c, 0xc6, 0x05, 0xa8, 0x11, 0x39, 0x4e, 0xf2, 0x55, 0xf6, 0x51, 0x75, 0x19, 0xa6, - 0x7d, 0xdf, 0x31, 0x06, 0x86, 0xb8, 0x22, 0xbd, 0x37, 0x9b, 0xcb, 0xef, 0x14, 0x50, 0xda, 0xb9, - 0x47, 0x19, 0xbd, 0xb9, 0x57, 0xaa, 0x59, 0x6b, 0x8b, 0xe5, 0xa5, 0x5e, 0xa9, 0x76, 0x70, 0x33, - 0xed, 0x07, 0xdd, 0x97, 0x17, 0x35, 0xe1, 0xd5, 0x45, 0x4d, 0xf8, 0xe7, 0xa2, 0x26, 0xbc, 0xb8, - 0xac, 0x95, 0x5e, 0x5d, 0xd6, 0x4a, 0x7f, 0x5d, 0xd6, 0x4a, 0x3f, 0x36, 0x47, 0x1e, 0x3b, 0x8d, - 0x86, 0x8a, 0x43, 0x26, 0x2a, 0x9f, 0x74, 0xc7, 0xc0, 0x9e, 0x93, 0xf0, 0x4c, 0xcd, 0x47, 0xfc, - 0xf9, 0x62, 0xc8, 0x27, 0xb3, 0x84, 0x0e, 0xef, 0xa4, 0x9e, 0xdb, 0xff, 0x3f, 0x00, 0x00, 0xff, - 0xff, 0x99, 0xab, 0xaa, 0x75, 0x04, 0x06, 0x00, 0x00, + // 575 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0xcf, 0x6e, 0xd3, 0x4e, + 0x10, 0xce, 0x36, 0xfd, 0xf5, 0xd7, 0x6e, 0x23, 0x11, 0xad, 0x22, 0x48, 0x73, 0x70, 0x82, 0x85, + 0x50, 0x0e, 0x74, 0x4d, 0xd2, 0x03, 0x55, 0x39, 0x25, 0xa8, 0x52, 0x51, 0x00, 0x55, 0xe6, 0xcf, + 0x81, 0x4b, 0xb4, 0xb6, 0xa7, 0x8e, 0x15, 0xc7, 0xbb, 0xf2, 0xae, 0xd3, 0xf8, 0x21, 0x90, 0x7a, + 0xe1, 0x11, 0x78, 0x03, 0x1e, 0xa2, 0xe2, 0xd4, 0x23, 0xa7, 0x82, 0x92, 0x37, 0xe0, 0x09, 0x90, + 0xbd, 0x76, 0x80, 0x16, 0x71, 0x9b, 0xd9, 0xef, 0x9b, 0xd9, 0x6f, 0xe7, 0x9b, 0xc5, 0x1d, 0x58, + 0x70, 0x97, 0xc7, 0x60, 0x79, 0xdc, 0x3f, 0xe3, 0xdc, 0xb3, 0xe6, 0xbd, 0x32, 0xa4, 0x22, 0xe6, + 0x8a, 0x13, 0x52, 0x30, 0x68, 0x79, 0x3c, 0xef, 0xb5, 0x1a, 0x3e, 0xf7, 0x79, 0x0e, 0x5b, 0x59, + 0xa4, 0x99, 0xad, 0x3d, 0x9f, 0x73, 0x3f, 0x04, 0x2b, 0xcf, 0x9c, 0xe4, 0xcc, 0x62, 0x51, 0x5a, + 0x40, 0xed, 0x9b, 0x90, 0x0a, 0x66, 0x20, 0x15, 0x9b, 0x89, 0x82, 0xf0, 0xc0, 0xe5, 0x72, 0xc6, + 0xa5, 0x25, 0x15, 0x9b, 0x06, 0x91, 0x6f, 0xcd, 0x7b, 0x0e, 0x28, 0xd6, 0x2b, 0xf3, 0xf2, 0x06, + 0xcd, 0x1a, 0xeb, 0xab, 0x75, 0xa2, 0x21, 0xf3, 0x13, 0xc2, 0xf5, 0x63, 0xad, 0xf4, 0x1d, 0x0b, + 0x03, 0x8f, 0x29, 0x1e, 0x93, 0x26, 0xfe, 0x9f, 0x79, 0x5e, 0x0c, 0x52, 0x36, 0x51, 0x07, 0x75, + 0x6b, 0x76, 0x99, 0x92, 0x06, 0xfe, 0x4f, 0xf0, 0x73, 0x88, 0x9b, 0x1b, 0x1d, 0xd4, 0xad, 0xda, + 0x3a, 0x21, 0x0c, 0x6f, 0x89, 0xc4, 0x99, 0x42, 0xda, 0xac, 0x76, 0x50, 0x77, 0xb7, 0xdf, 0xa0, + 0x5a, 0x37, 0x2d, 0x75, 0xd3, 0x41, 0x94, 0x0e, 0x0f, 0x7e, 0x5c, 0xb7, 0xef, 0xa5, 0x6c, 0x16, + 0x1e, 0x99, 0x2e, 0x8f, 0x24, 0x44, 0x32, 0x91, 0x63, 0x5d, 0x67, 0x7e, 0xf9, 0xbc, 0xdf, 0x28, + 0x74, 0xb9, 0x71, 0x2a, 0x14, 0xa7, 0xa7, 0x89, 0x33, 0x82, 0xd4, 0x2e, 0x1a, 0x9b, 0x0f, 0x71, + 0x7d, 0xe0, 0xba, 0x3c, 0x89, 0xd4, 0x40, 0x4b, 0x01, 0x49, 0x08, 0xde, 0x0c, 0x03, 0xa9, 0x9a, + 0xa8, 0x53, 0xed, 0xd6, 0xec, 0x3c, 0x36, 0xbb, 0x98, 0x3c, 0x2b, 0x9b, 0xff, 0x9b, 0xf9, 0x08, + 0xdf, 0x7d, 0x1b, 0x79, 0x10, 0x82, 0xcf, 0x54, 0xc0, 0x23, 0x1b, 0x5c, 0x1e, 0x7b, 0x23, 0x48, + 0xff, 0xce, 0x7e, 0x8e, 0xf1, 0x7a, 0x3e, 0x92, 0x3c, 0xfd, 0x8d, 0xb1, 0xdb, 0xbf, 0x4f, 0x0b, + 0xe9, 0xe5, 0xd4, 0x0b, 0x17, 0xe8, 0xba, 0x62, 0xb8, 0x79, 0x79, 0xdd, 0xae, 0x14, 0xad, 0x3e, + 0x22, 0x5c, 0x3b, 0x01, 0xe6, 0x41, 0xfc, 0x3a, 0x71, 0x24, 0x28, 0x72, 0x88, 0x37, 0x33, 0x5f, + 0xf3, 0x59, 0xef, 0xf6, 0x5b, 0xb7, 0x86, 0xf7, 0xa6, 0x34, 0x7d, 0xb8, 0x9d, 0xb5, 0xb9, 0xf8, + 0xd6, 0x46, 0x76, 0x5e, 0x41, 0x1e, 0xe3, 0x46, 0x04, 0x0b, 0x35, 0x9e, 0xaf, 0xa5, 0x8d, 0x27, + 0x4c, 0x4e, 0x72, 0x77, 0x6a, 0x36, 0xc9, 0xb0, 0x5f, 0xaa, 0x4f, 0x98, 0x9c, 0x90, 0x3d, 0xbc, + 0xcd, 0x84, 0xd0, 0xac, 0x6a, 0xe1, 0xad, 0x10, 0x19, 0x64, 0x7e, 0x40, 0xf8, 0xce, 0x08, 0xd2, + 0xd3, 0xcc, 0xd2, 0x97, 0x4c, 0x88, 0x20, 0xf2, 0xc9, 0xe0, 0x8f, 0x87, 0xee, 0xd3, 0xdb, 0x4b, + 0x4d, 0x6f, 0x94, 0xd0, 0x17, 0x81, 0x54, 0xc7, 0x91, 0x8a, 0x53, 0xfd, 0xdc, 0xd6, 0x13, 0xbc, + 0xb3, 0x3e, 0x22, 0x75, 0x5c, 0xcd, 0xd6, 0x24, 0x7b, 0xe9, 0x8e, 0x9d, 0x85, 0xd9, 0x46, 0xcd, + 0x59, 0x98, 0x40, 0xb9, 0x51, 0x79, 0x72, 0xb4, 0x71, 0x88, 0x86, 0xa3, 0xcb, 0xa5, 0x81, 0xae, + 0x96, 0x06, 0xfa, 0xbe, 0x34, 0xd0, 0xc5, 0xca, 0xa8, 0x5c, 0xad, 0x8c, 0xca, 0xd7, 0x95, 0x51, + 0x79, 0xdf, 0xf3, 0x03, 0x35, 0x49, 0x1c, 0xea, 0xf2, 0x99, 0x55, 0x2c, 0xef, 0x2b, 0x50, 0xe7, + 0x3c, 0x9e, 0x5a, 0xe5, 0xbf, 0x5c, 0xac, 0x7f, 0xa6, 0x4a, 0x05, 0x48, 0x67, 0x2b, 0x9f, 0xe6, + 0xc1, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdb, 0x8d, 0x64, 0x24, 0xb9, 0x03, 0x00, 0x00, } func (m *ExocoreValidator) Marshal() (dAtA []byte, err error) { @@ -654,88 +496,6 @@ func (m *ExocoreValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *Operation) 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 *Operation) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Operation) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - { - size, err := m.PubKey.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintDogfood(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x1a - if len(m.OperatorAddress) > 0 { - i -= len(m.OperatorAddress) - copy(dAtA[i:], m.OperatorAddress) - i = encodeVarintDogfood(dAtA, i, uint64(len(m.OperatorAddress))) - i-- - dAtA[i] = 0x12 - } - if m.OperationType != 0 { - i = encodeVarintDogfood(dAtA, i, uint64(m.OperationType)) - i-- - dAtA[i] = 0x8 - } - return len(dAtA) - i, nil -} - -func (m *Operations) 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 *Operations) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *Operations) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.List) > 0 { - for iNdEx := len(m.List) - 1; iNdEx >= 0; iNdEx-- { - { - size, err := m.List[iNdEx].MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintDogfood(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0xa - } - } - return len(dAtA) - i, nil -} - func (m *AccountAddresses) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -903,17 +663,57 @@ func (m *HeaderSubset) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - n3, err3 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):]) - if err3 != nil { - return 0, err3 + n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.Time):]) + if err2 != nil { + return 0, err2 } - i -= n3 - i = encodeVarintDogfood(dAtA, i, uint64(n3)) + i -= n2 + i = encodeVarintDogfood(dAtA, i, uint64(n2)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil } +func (m *KeyPowerMapping) 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 *KeyPowerMapping) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *KeyPowerMapping) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.List) > 0 { + for k := range m.List { + v := m.List[k] + baseI := i + i = encodeVarintDogfood(dAtA, i, uint64(v)) + i-- + dAtA[i] = 0x10 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintDogfood(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintDogfood(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintDogfood(dAtA []byte, offset int, v uint64) int { offset -= sovDogfood(v) base := offset @@ -945,39 +745,6 @@ func (m *ExocoreValidator) Size() (n int) { return n } -func (m *Operation) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if m.OperationType != 0 { - n += 1 + sovDogfood(uint64(m.OperationType)) - } - l = len(m.OperatorAddress) - if l > 0 { - n += 1 + l + sovDogfood(uint64(l)) - } - l = m.PubKey.Size() - n += 1 + l + sovDogfood(uint64(l)) - return n -} - -func (m *Operations) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - if len(m.List) > 0 { - for _, e := range m.List { - l = e.Size() - n += 1 + l + sovDogfood(uint64(l)) - } - } - return n -} - func (m *AccountAddresses) Size() (n int) { if m == nil { return 0 @@ -1057,6 +824,23 @@ func (m *HeaderSubset) Size() (n int) { return n } +func (m *KeyPowerMapping) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.List) > 0 { + for k, v := range m.List { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovDogfood(uint64(len(k))) + 1 + sovDogfood(uint64(v)) + n += mapEntrySize + 1 + sovDogfood(uint64(mapEntrySize)) + } + } + return n +} + func sovDogfood(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1202,7 +986,7 @@ func (m *ExocoreValidator) Unmarshal(dAtA []byte) error { } return nil } -func (m *Operation) Unmarshal(dAtA []byte) error { +func (m *AccountAddresses) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1225,34 +1009,15 @@ func (m *Operation) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Operation: wiretype end group for non-group") + return fmt.Errorf("proto: AccountAddresses: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Operation: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: AccountAddresses: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field OperationType", wireType) - } - m.OperationType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDogfood - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.OperationType |= OperationType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field OperatorAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) } var byteLen int for shift := uint(0); ; shift += 7 { @@ -1279,43 +1044,8 @@ func (m *Operation) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.OperatorAddress = append(m.OperatorAddress[:0], dAtA[iNdEx:postIndex]...) - if m.OperatorAddress == nil { - m.OperatorAddress = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field PubKey", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDogfood - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthDogfood - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthDogfood - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.PubKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.List = append(m.List, make([]byte, postIndex-iNdEx)) + copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1338,7 +1068,7 @@ func (m *Operation) Unmarshal(dAtA []byte) error { } return nil } -func (m *Operations) Unmarshal(dAtA []byte) error { +func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1361,17 +1091,17 @@ func (m *Operations) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: Operations: wiretype end group for non-group") + return fmt.Errorf("proto: ConsensusAddresses: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: Operations: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: ConsensusAddresses: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDogfood @@ -1381,25 +1111,23 @@ func (m *Operations) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthDogfood } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthDogfood } if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, Operation{}) - if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.List = append(m.List, make([]byte, postIndex-iNdEx)) + copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -1422,7 +1150,7 @@ func (m *Operations) Unmarshal(dAtA []byte) error { } return nil } -func (m *AccountAddresses) Unmarshal(dAtA []byte) error { +func (m *UndelegationRecordKeys) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1445,10 +1173,10 @@ func (m *AccountAddresses) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: AccountAddresses: wiretype end group for non-group") + return fmt.Errorf("proto: UndelegationRecordKeys: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: AccountAddresses: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: UndelegationRecordKeys: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -1504,7 +1232,7 @@ func (m *AccountAddresses) Unmarshal(dAtA []byte) error { } return nil } -func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { +func (m *Validators) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1527,17 +1255,17 @@ func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ConsensusAddresses: wiretype end group for non-group") + return fmt.Errorf("proto: Validators: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ConsensusAddresses: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: Validators: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDogfood @@ -1547,23 +1275,25 @@ func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthDogfood } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthDogfood } if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, make([]byte, postIndex-iNdEx)) - copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) + m.List = append(m.List, types1.Validator{}) + if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -1586,7 +1316,7 @@ func (m *ConsensusAddresses) Unmarshal(dAtA []byte) error { } return nil } -func (m *UndelegationRecordKeys) Unmarshal(dAtA []byte) error { +func (m *HeaderSubset) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1609,17 +1339,17 @@ func (m *UndelegationRecordKeys) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: UndelegationRecordKeys: wiretype end group for non-group") + return fmt.Errorf("proto: HeaderSubset: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: UndelegationRecordKeys: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: HeaderSubset: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) } - var byteLen int + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDogfood @@ -1629,79 +1359,64 @@ func (m *UndelegationRecordKeys) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - byteLen |= int(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - if byteLen < 0 { + if msglen < 0 { return ErrInvalidLengthDogfood } - postIndex := iNdEx + byteLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthDogfood } if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, make([]byte, postIndex-iNdEx)) - copy(m.List[len(m.List)-1], dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipDogfood(dAtA[iNdEx:]) - if err != nil { + if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { return err } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthDogfood + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextValidatorsHash", wireType) } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *Validators) 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 ErrIntOverflowDogfood + if byteLen < 0 { + return ErrInvalidLengthDogfood } - if iNdEx >= l { + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthDogfood + } + if postIndex > l { return io.ErrUnexpectedEOF } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break + m.NextValidatorsHash = append(m.NextValidatorsHash[:0], dAtA[iNdEx:postIndex]...) + if m.NextValidatorsHash == nil { + m.NextValidatorsHash = []byte{} } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: Validators: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: Validators: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + iNdEx = postIndex + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) } - var msglen int + var byteLen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowDogfood @@ -1711,24 +1426,24 @@ func (m *Validators) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + byteLen |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + if byteLen < 0 { return ErrInvalidLengthDogfood } - postIndex := iNdEx + msglen + postIndex := iNdEx + byteLen if postIndex < 0 { return ErrInvalidLengthDogfood } if postIndex > l { return io.ErrUnexpectedEOF } - m.List = append(m.List, types1.Validator{}) - if err := m.List[len(m.List)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err + m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) + if m.AppHash == nil { + m.AppHash = []byte{} } iNdEx = postIndex default: @@ -1752,7 +1467,7 @@ func (m *Validators) Unmarshal(dAtA []byte) error { } return nil } -func (m *HeaderSubset) Unmarshal(dAtA []byte) error { +func (m *KeyPowerMapping) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1775,15 +1490,15 @@ func (m *HeaderSubset) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: HeaderSubset: wiretype end group for non-group") + return fmt.Errorf("proto: KeyPowerMapping: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: HeaderSubset: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: KeyPowerMapping: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Time", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field List", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -1810,77 +1525,89 @@ func (m *HeaderSubset) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.Time, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NextValidatorsHash", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDogfood - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if byteLen < 0 { - return ErrInvalidLengthDogfood - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthDogfood - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.NextValidatorsHash = append(m.NextValidatorsHash[:0], dAtA[iNdEx:postIndex]...) - if m.NextValidatorsHash == nil { - m.NextValidatorsHash = []byte{} - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) - } - var byteLen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowDogfood - } - if iNdEx >= l { - return io.ErrUnexpectedEOF + if m.List == nil { + m.List = make(map[string]int64) + } + var mapkey string + var mapvalue int64 + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } } - b := dAtA[iNdEx] - iNdEx++ - byteLen |= int(b&0x7F) << shift - if b < 0x80 { - break + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthDogfood + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthDogfood + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDogfood + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + mapvalue |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + } else { + iNdEx = entryPreIndex + skippy, err := skipDogfood(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthDogfood + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } } - if byteLen < 0 { - return ErrInvalidLengthDogfood - } - postIndex := iNdEx + byteLen - if postIndex < 0 { - return ErrInvalidLengthDogfood - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.AppHash = append(m.AppHash[:0], dAtA[iNdEx:postIndex]...) - if m.AppHash == nil { - m.AppHash = []byte{} - } + m.List[mapkey] = mapvalue iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/dogfood/types/expected_keepers.go b/x/dogfood/types/expected_keepers.go index 06ca74df4..6c6862d9f 100644 --- a/x/dogfood/types/expected_keepers.go +++ b/x/dogfood/types/expected_keepers.go @@ -55,6 +55,12 @@ type OperatorKeeper interface { ) (bool, sdk.AccAddress) IsOperatorJailedForChainId(sdk.Context, sdk.AccAddress, string) bool Jail(sdk.Context, sdk.ConsAddress, string) + // GetActiveOperatorsForChainId should return a list of operators and their public keys. + // These operators should not be in the process of opting our, and should not be jailed + // whether permanently or temporarily. + GetActiveOperatorsForChainId( + sdk.Context, string, + ) ([]sdk.AccAddress, []tmprotocrypto.PublicKey) } // DelegationKeeper represents the expected keeper interface for the delegation module. @@ -72,6 +78,10 @@ type EpochsHooks interface { // RestakingKeeper represents the expected keeper interface for the restaking module. type RestakingKeeper interface { GetOperatorAssetValue(sdk.Context, sdk.AccAddress) (int64, error) + IsStakingAsset(sdk.Context, string) bool + GetAvgDelegatedValue( + sdk.Context, []sdk.AccAddress, []string, string, + ) ([]int64, error) } // SlashingKeeper represents the expected keeper interface for the (exo-)slashing module. diff --git a/x/dogfood/types/keys.go b/x/dogfood/types/keys.go index 1303fb4d0..849b5ec54 100644 --- a/x/dogfood/types/keys.go +++ b/x/dogfood/types/keys.go @@ -53,6 +53,7 @@ const ( // PendingUndelegationsByte is the byte used to store the list of undelegations that will // mature at the end of the current block. PendingUndelegationsByte + // ValidatorSetBytePrefix is the prefix for the historical validator set store. ValidatorSetBytePrefix @@ -61,6 +62,12 @@ const ( // HeaderBytePrefix is the prefix for the header store. HeaderBytePrefix + + // EpochEndByte is the byte key for the epoch end store. + EpochEndByte + + // KeyPowerMappingByte is the byte key for the consensus key to vote power mapping store. + KeyPowerMappingByte ) // ExocoreValidatorKey returns the key for the validator store. @@ -169,6 +176,16 @@ func PendingUndelegationsKey() []byte { return []byte{PendingUndelegationsByte} } +// EpochEndKey returns the key for the epoch end store. +func EpochEndKey() []byte { + return []byte{EpochEndByte} +} + +// KeyPowerMappingKey returns the key for the consensus key to vote power mapping store. +func KeyPowerMappingKey() []byte { + return []byte{KeyPowerMappingByte} +} + // SafeInt64ToUint64 is a wrapper function to convert an int64 // to a uint64. It returns (0, false) if the conversion is not possible. // This is safe as long as the int64 is non-negative. diff --git a/x/dogfood/types/params.go b/x/dogfood/types/params.go index f1b272b56..a07d14f3e 100644 --- a/x/dogfood/types/params.go +++ b/x/dogfood/types/params.go @@ -2,12 +2,14 @@ package types import ( "fmt" + "strings" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/ethereum/go-ethereum/common/hexutil" "gopkg.in/yaml.v2" - epochTypes "github.com/evmos/evmos/v14/x/epochs/types" + epochtypes "github.com/evmos/evmos/v14/x/epochs/types" ) var _ paramtypes.ParamSet = (*Params)(nil) @@ -20,21 +22,24 @@ const ( DefaultEpochsUntilUnbonded = 7 // DefaultEpochIdentifier is the epoch identifier which is used, by default, to identify the // epoch. Note that the options include week, day or hour. - DefaultEpochIdentifier = epochTypes.HourEpochID - // DefaultMaxValidators is the default maximum number of bonded validators. + DefaultEpochIdentifier = epochtypes.HourEpochID + // DefaultMaxValidators is the default maximum number of bonded validators. It is defined as + // a copy here so that we can use a value other than that in x/staking, if necessary. DefaultMaxValidators = stakingtypes.DefaultMaxValidators // DefaultHistorical entries is the number of entries of historical staking data to persist. - // Apps that don't use IBC can ignore this value by not adding the staking module to the - // application module manager's SetOrderBeginBlockers. + // It is defined as a copy here so that we can use a value other than that in x/staking, if + // necessary. DefaultHistoricalEntries = stakingtypes.DefaultHistoricalEntries + // DefaultAssetIDs is the default asset IDs accepted by the dogfood module. If multiple + // asset IDs are to be supported by default, separate them with a pipe character. + DefaultAssetIDs = "0xdac17f958d2ee523a2206206994597c13d831ec7_0x65" ) // Reflection based keys for params subspace. var ( KeyEpochsUntilUnbonded = []byte("EpochsUntilUnbonded") KeyEpochIdentifier = []byte("EpochIdentifier") - KeyMaxValidators = []byte("MaxValidators") - KeyHistoricalEntries = []byte("HistoricalEntries") + KeyAssetIDs = []byte("AssetIDs") ) // ParamKeyTable returns a key table with the necessary registered params. @@ -48,12 +53,14 @@ func NewParams( epochIdentifier string, maxValidators uint32, historicalEntries uint32, + assetIDs []string, ) Params { return Params{ EpochsUntilUnbonded: epochsUntilUnbonded, EpochIdentifier: epochIdentifier, MaxValidators: maxValidators, HistoricalEntries: historicalEntries, + AssetIDs: assetIDs, } } @@ -64,6 +71,7 @@ func DefaultParams() Params { DefaultEpochIdentifier, DefaultMaxValidators, DefaultHistoricalEntries, + strings.Split(DefaultAssetIDs, "|"), ) } @@ -78,18 +86,23 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair( KeyEpochIdentifier, &p.EpochIdentifier, - epochTypes.ValidateEpochIdentifierInterface, + epochtypes.ValidateEpochIdentifierInterface, ), paramtypes.NewParamSetPair( - KeyMaxValidators, + stakingtypes.KeyMaxValidators, &p.MaxValidators, ValidatePositiveUint32, ), paramtypes.NewParamSetPair( - KeyHistoricalEntries, + stakingtypes.KeyHistoricalEntries, &p.HistoricalEntries, ValidatePositiveUint32, ), + paramtypes.NewParamSetPair( + KeyAssetIDs, + &p.AssetIDs, + ValidateAssetIDs, + ), } } @@ -98,7 +111,7 @@ func (p Params) Validate() error { if err := ValidatePositiveUint32(p.EpochsUntilUnbonded); err != nil { return fmt.Errorf("epochs until unbonded: %w", err) } - if err := epochTypes.ValidateEpochIdentifierInterface(p.EpochIdentifier); err != nil { + if err := epochtypes.ValidateEpochIdentifierInterface(p.EpochIdentifier); err != nil { return fmt.Errorf("epoch identifier: %w", err) } if err := ValidatePositiveUint32(p.MaxValidators); err != nil { @@ -129,3 +142,33 @@ func (p Params) String() string { } return string(out) } + +// ValidateAssetIDs checks whether the supplied value is a valid asset ID. +func ValidateAssetIDs(i interface{}) error { + var val []string + if val, ok := i.([]string); !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } else if len(val) == 0 { + return fmt.Errorf("invalid parameter value: %v", val) + } + for _, assetID := range val { + if !strings.Contains(assetID, "_") { + return fmt.Errorf("invalid parameter value (missing underscore): %v", val) + } + split := strings.Split(assetID, "_") + if len(split) != 2 { + return fmt.Errorf( + "invalid parameter value (unexpected number of underscores): %v", val, + ) + } + if len(split[0]) == 0 || len(split[1]) == 0 { + return fmt.Errorf("invalid parameter value (empty parts): %v", val) + } + // i cannot validate the address because it may be on a client chain and i have + // no idea what format or length it may have. i can only validate the chain ID. + if _, err := hexutil.DecodeUint64(split[1]); err != nil { + return fmt.Errorf("invalid parameter value (not a number): %v", split[1]) + } + } + return nil +} diff --git a/x/dogfood/types/params.pb.go b/x/dogfood/types/params.pb.go index 1b35e818a..a59e27d9e 100644 --- a/x/dogfood/types/params.pb.go +++ b/x/dogfood/types/params.pb.go @@ -36,6 +36,11 @@ type Params struct { MaxValidators uint32 `protobuf:"varint,3,opt,name=max_validators,json=maxValidators,proto3" json:"max_validators,omitempty"` // HistoricalEntries is the number of historical entries to persist. HistoricalEntries uint32 `protobuf:"varint,4,opt,name=historical_entries,json=historicalEntries,proto3" json:"historical_entries,omitempty"` + // AssetIDs is the ids of the assets which will be accepted by the module. + // It must be within the list of assets supported by the restaking module. + // The typical format of these IDs is + // lower(assetAddress) + _ + hex(clientChainLzID) + AssetIDs []string `protobuf:"bytes,5,rep,name=asset_ids,json=assetIds,proto3" json:"asset_ids,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -98,6 +103,13 @@ func (m *Params) GetHistoricalEntries() uint32 { return 0 } +func (m *Params) GetAssetIDs() []string { + if m != nil { + return m.AssetIDs + } + return nil +} + func init() { proto.RegisterType((*Params)(nil), "exocore.dogfood.v1.Params") } @@ -105,25 +117,27 @@ func init() { func init() { proto.RegisterFile("exocore/dogfood/v1/params.proto", fileDescriptor_e8747fb70c97d97f) } var fileDescriptor_e8747fb70c97d97f = []byte{ - // 290 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0x3f, 0x4b, 0xc3, 0x40, - 0x18, 0x87, 0x73, 0x5a, 0x0a, 0x1e, 0xd4, 0x3f, 0xa7, 0x42, 0x70, 0xb8, 0x16, 0x41, 0xa8, 0x83, - 0x39, 0xaa, 0x9b, 0xa3, 0xd0, 0x41, 0x04, 0x91, 0x42, 0x1d, 0x5c, 0xc2, 0x35, 0x77, 0x4d, 0x0f, - 0x9b, 0xbc, 0xe1, 0xee, 0x1a, 0xe3, 0xb7, 0x70, 0x74, 0xf4, 0xbb, 0xb8, 0x38, 0x76, 0x74, 0x94, - 0xe4, 0x8b, 0x48, 0x2f, 0x31, 0x6e, 0xc7, 0xef, 0x79, 0xee, 0x1d, 0x1e, 0xdc, 0x97, 0x05, 0x44, - 0xa0, 0x25, 0x13, 0x10, 0xcf, 0x01, 0x04, 0xcb, 0x47, 0x2c, 0xe3, 0x9a, 0x27, 0x26, 0xc8, 0x34, - 0x58, 0x20, 0xa4, 0x11, 0x82, 0x46, 0x08, 0xf2, 0xd1, 0xc9, 0x51, 0x0c, 0x31, 0x38, 0xcc, 0x36, - 0xaf, 0xda, 0x3c, 0xfd, 0x44, 0xb8, 0xfb, 0xe0, 0xbe, 0x92, 0x4b, 0x7c, 0x2c, 0x33, 0x88, 0x16, - 0x26, 0x5c, 0xa5, 0x56, 0x2d, 0xc3, 0x55, 0x3a, 0x83, 0x54, 0x48, 0xe1, 0xa3, 0x01, 0x1a, 0xf6, - 0x26, 0x87, 0x35, 0x9c, 0x6e, 0xd8, 0xb4, 0x41, 0xe4, 0x1c, 0xef, 0xbb, 0x39, 0x54, 0x42, 0xa6, - 0x56, 0xcd, 0x95, 0xd4, 0xfe, 0xd6, 0x00, 0x0d, 0x77, 0x26, 0x7b, 0x6e, 0xbf, 0x6d, 0x67, 0x72, - 0x86, 0x77, 0x13, 0x5e, 0x84, 0x39, 0x5f, 0x2a, 0xc1, 0x2d, 0x68, 0xe3, 0x6f, 0xbb, 0xbb, 0xbd, - 0x84, 0x17, 0x8f, 0xed, 0x48, 0x2e, 0x30, 0x59, 0x28, 0x63, 0x41, 0xab, 0x88, 0x2f, 0x43, 0x99, - 0x5a, 0xad, 0xa4, 0xf1, 0x3b, 0x4e, 0x3d, 0xf8, 0x27, 0xe3, 0x1a, 0x5c, 0x77, 0xde, 0x3f, 0xfa, - 0xde, 0xcd, 0xdd, 0x57, 0x49, 0xd1, 0xba, 0xa4, 0xe8, 0xa7, 0xa4, 0xe8, 0xad, 0xa2, 0xde, 0xba, - 0xa2, 0xde, 0x77, 0x45, 0xbd, 0xa7, 0x51, 0xac, 0xec, 0x62, 0x35, 0x0b, 0x22, 0x48, 0xd8, 0xb8, - 0x8e, 0x72, 0x2f, 0xed, 0x0b, 0xe8, 0x67, 0xf6, 0x17, 0xb1, 0x68, 0x33, 0xda, 0xd7, 0x4c, 0x9a, - 0x59, 0xd7, 0x95, 0xb9, 0xfa, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x52, 0x3e, 0xbb, 0xe0, 0x66, 0x01, + // 322 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0x3f, 0x4f, 0x02, 0x31, + 0x18, 0x87, 0xaf, 0x82, 0x04, 0x1a, 0xf1, 0x4f, 0xd5, 0xe4, 0xe2, 0x70, 0x10, 0x13, 0x13, 0x18, + 0xbc, 0x0b, 0xba, 0xb9, 0x49, 0x64, 0x20, 0x26, 0xc6, 0x90, 0xe0, 0xe0, 0xd2, 0x94, 0x6b, 0x39, + 0x1a, 0xb9, 0x7b, 0x2f, 0x6d, 0xc1, 0xf3, 0x5b, 0x38, 0x3a, 0xfa, 0x71, 0x1c, 0x19, 0x9d, 0x8c, + 0x39, 0x76, 0x3f, 0x83, 0xa1, 0x87, 0xb8, 0x35, 0xcf, 0xf3, 0xeb, 0x3b, 0x3c, 0xb8, 0x21, 0x32, + 0x08, 0x41, 0x89, 0x80, 0x43, 0x34, 0x06, 0xe0, 0xc1, 0xbc, 0x13, 0xa4, 0x4c, 0xb1, 0x58, 0xfb, + 0xa9, 0x02, 0x03, 0x84, 0xac, 0x07, 0xfe, 0x7a, 0xe0, 0xcf, 0x3b, 0x27, 0x47, 0x11, 0x44, 0x60, + 0x75, 0xb0, 0x7a, 0x15, 0xcb, 0xd3, 0x1f, 0x84, 0x2b, 0xf7, 0xf6, 0x2b, 0xb9, 0xc0, 0xc7, 0x22, + 0x85, 0x70, 0xa2, 0xe9, 0x2c, 0x31, 0x72, 0x4a, 0x67, 0xc9, 0x08, 0x12, 0x2e, 0xb8, 0x8b, 0x9a, + 0xa8, 0x55, 0x1f, 0x1c, 0x16, 0x72, 0xb8, 0x72, 0xc3, 0xb5, 0x22, 0x6d, 0xbc, 0x6f, 0x31, 0x95, + 0x5c, 0x24, 0x46, 0x8e, 0xa5, 0x50, 0xee, 0x56, 0x13, 0xb5, 0x6a, 0x83, 0x3d, 0xcb, 0xfb, 0x1b, + 0x4c, 0xce, 0xf0, 0x6e, 0xcc, 0x32, 0x3a, 0x67, 0x53, 0xc9, 0x99, 0x01, 0xa5, 0xdd, 0x92, 0xbd, + 0x5b, 0x8f, 0x59, 0xf6, 0xb0, 0x81, 0xe4, 0x1c, 0x93, 0x89, 0xd4, 0x06, 0x94, 0x0c, 0xd9, 0x94, + 0x8a, 0xc4, 0x28, 0x29, 0xb4, 0x5b, 0xb6, 0xd3, 0x83, 0x7f, 0xd3, 0x2b, 0x04, 0x69, 0xe3, 0x1a, + 0xd3, 0x5a, 0x18, 0x2a, 0xb9, 0x76, 0xb7, 0x9b, 0xa5, 0x56, 0xad, 0xbb, 0x93, 0x7f, 0x35, 0xaa, + 0xd7, 0x2b, 0xd8, 0xbf, 0xd1, 0x83, 0xaa, 0xd5, 0x7d, 0xae, 0xaf, 0xca, 0x6f, 0xef, 0x0d, 0xa7, + 0x7b, 0xfb, 0x91, 0x7b, 0x68, 0x91, 0x7b, 0xe8, 0x3b, 0xf7, 0xd0, 0xeb, 0xd2, 0x73, 0x16, 0x4b, + 0xcf, 0xf9, 0x5c, 0x7a, 0xce, 0x63, 0x27, 0x92, 0x66, 0x32, 0x1b, 0xf9, 0x21, 0xc4, 0x41, 0xaf, + 0xe8, 0x77, 0x27, 0xcc, 0x33, 0xa8, 0xa7, 0xe0, 0xaf, 0x77, 0xb6, 0x29, 0x6e, 0x5e, 0x52, 0xa1, + 0x47, 0x15, 0x1b, 0xf1, 0xf2, 0x37, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x8d, 0x3f, 0x7c, 0x91, 0x01, 0x00, 0x00, } @@ -147,6 +161,15 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.AssetIDs) > 0 { + for iNdEx := len(m.AssetIDs) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.AssetIDs[iNdEx]) + copy(dAtA[i:], m.AssetIDs[iNdEx]) + i = encodeVarintParams(dAtA, i, uint64(len(m.AssetIDs[iNdEx]))) + i-- + dAtA[i] = 0x2a + } + } if m.HistoricalEntries != 0 { i = encodeVarintParams(dAtA, i, uint64(m.HistoricalEntries)) i-- @@ -202,6 +225,12 @@ func (m *Params) Size() (n int) { if m.HistoricalEntries != 0 { n += 1 + sovParams(uint64(m.HistoricalEntries)) } + if len(m.AssetIDs) > 0 { + for _, s := range m.AssetIDs { + l = len(s) + n += 1 + l + sovParams(uint64(l)) + } + } return n } @@ -329,6 +358,38 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AssetIDs", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AssetIDs = append(m.AssetIDs, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipParams(dAtA[iNdEx:])