diff --git a/app/app.go b/app/app.go index 7e2258b7..edecdc1e 100644 --- a/app/app.go +++ b/app/app.go @@ -102,6 +102,7 @@ import ( "github.com/bitbadges/bitbadgeschain/x/tokenization/types" gammkeeper "github.com/bitbadges/bitbadgeschain/x/gamm/keeper" + potkeeper "github.com/bitbadges/bitbadgeschain/x/pot/keeper" ibchooks "github.com/bitbadges/bitbadgeschain/x/ibc-hooks" ibcratelimitkeeper "github.com/bitbadges/bitbadgeschain/x/ibc-rate-limit/keeper" @@ -173,6 +174,7 @@ type App struct { MapsKeeper mapsmodulekeeper.Keeper ManagerSplitterKeeper managersplittermodulekeeper.Keeper + PotKeeper potkeeper.Keeper GammKeeper gammkeeper.Keeper PoolManagerKeeper poolmanager.Keeper SendmanagerKeeper sendmanagermodulekeeper.Keeper @@ -350,6 +352,11 @@ func New( return nil, err } + // Register x/pot module (Proof of Token — credential-gated validator power) + if err := app.registerPotModule(appOpts); err != nil { + return nil, fmt.Errorf("failed to register pot module: %w", err) + } + // Register EVM modules first (PreciseBank depends on EVM keeper) if err := app.registerEVMModules(appOpts); err != nil { return nil, err @@ -379,8 +386,9 @@ func New( }) // Register custom global transfer checkers (optional) + // Note: x/pot no longer uses a transfer hook. It iterates all validators in + // its EndBlocker to catch both transfer-based and time-dependent credential changes. app.TokenizationKeeper.RegisterCustomGlobalTransferChecker(func(ctx sdk.Context, from string, to string, initiatedBy string, collection *types.TokenCollection, transferBalances []*types.Balance, memo string) []tokenizationmodulekeeper.GlobalTransferChecker { - // Add custom logic as needed here return nil }) diff --git a/app/app_config.go b/app/app_config.go index 08fae251..128d8999 100644 --- a/app/app_config.go +++ b/app/app_config.go @@ -8,6 +8,7 @@ import ( anchormoduletypes "github.com/bitbadges/bitbadgeschain/x/anchor/types" gammtypes "github.com/bitbadges/bitbadgeschain/x/gamm/types" poolmanagertypes "github.com/bitbadges/bitbadgeschain/x/poolmanager/types" + pottypes "github.com/bitbadges/bitbadgeschain/x/pot/types" _ "github.com/bitbadges/bitbadgeschain/x/sendmanager/module" sendmanagermoduletypes "github.com/bitbadges/bitbadgeschain/x/sendmanager/types" @@ -115,6 +116,7 @@ var ( // chain modules anchormoduletypes.ModuleName, tokenizationmoduletypes.ModuleName, + pottypes.ModuleName, // x/pot after tokenization mapsmoduletypes.ModuleName, managersplittermoduletypes.ModuleName, packetforwardtypes.ModuleName, @@ -149,6 +151,7 @@ var ( // chain modules anchormoduletypes.ModuleName, tokenizationmoduletypes.ModuleName, + pottypes.ModuleName, // x/pot no-op BeginBlock but needed for module manager mapsmoduletypes.ModuleName, managersplittermoduletypes.ModuleName, packetforwardtypes.ModuleName, @@ -166,6 +169,7 @@ var ( // cosmos sdk modules crisistypes.ModuleName, govtypes.ModuleName, + pottypes.ModuleName, // x/pot MUST be BEFORE staking: it jails/unjails, then staking emits ValidatorUpdates stakingtypes.ModuleName, feegrant.ModuleName, group.ModuleName, diff --git a/app/pot.go b/app/pot.go new file mode 100644 index 00000000..10a00ef4 --- /dev/null +++ b/app/pot.go @@ -0,0 +1,68 @@ +package app + +import ( + "cosmossdk.io/core/appmodule" + storetypes "cosmossdk.io/store/types" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/types/module" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + potkeeper "github.com/bitbadges/bitbadgeschain/x/pot/keeper" + pot "github.com/bitbadges/bitbadgeschain/x/pot/module" + pottypes "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// registerPotModule registers the x/pot module stores, keeper, and AppModule. +// This follows the same manual registration pattern as registerGammModules. +func (app *App) registerPotModule(_ servertypes.AppOptions) error { + // Register store keys (no transient store needed — x/pot uses persistent KV only). + storeKey := storetypes.NewKVStoreKey(pottypes.StoreKey) + if err := app.RegisterStores(storeKey); err != nil { + return err + } + + // Create the tokenization adapter (wraps the concrete tokenization keeper). + tokenizationAdapter := potkeeper.NewTokenizationKeeperAdapter(app.TokenizationKeeper) + + // Governance authority for MsgUpdateParams. + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + + // Create the staking adapter (for chains using x/staking). + // For PoA chains, replace this with potkeeper.NewPoAAdapter(poaKeeper, potKeeper). + validatorSet := potkeeper.NewStakingAdapter(app.StakingKeeper, app.SlashingKeeper) + + // Create the pot keeper. + app.PotKeeper = potkeeper.NewKeeper( + app.appCodec, + storeKey, + app.Logger(), + authority.String(), + tokenizationAdapter, + validatorSet, + ) + + // Create and register the AppModule. + potModule := pot.NewAppModule(app.appCodec, app.PotKeeper) + if err := app.RegisterModules(potModule); err != nil { + return err + } + + return nil +} + +// RegisterPot registers the x/pot module on the client side so that +// its CLI commands (tx pot, query pot) and interface types are available +// in the binary. This mirrors the RegisterGamm / RegisterIBC pattern. +func RegisterPot(registry cdctypes.InterfaceRegistry) map[string]appmodule.AppModule { + modules := map[string]appmodule.AppModule{ + pottypes.ModuleName: pot.AppModule{}, + } + + for name, m := range modules { + module.CoreAppModuleBasicAdaptor(name, m).RegisterInterfaces(registry) + } + + return modules +} diff --git a/cmd/bitbadgeschaind/cmd/root.go b/cmd/bitbadgeschaind/cmd/root.go index 805f237f..c6252a6c 100644 --- a/cmd/bitbadgeschaind/cmd/root.go +++ b/cmd/bitbadgeschaind/cmd/root.go @@ -107,6 +107,12 @@ func NewRootCmd() *cobra.Command { autoCliOpts.Modules[name] = mod } + potModules := app.RegisterPot(clientCtx.InterfaceRegistry) + for name, mod := range potModules { + moduleBasicManager[name] = module.CoreAppModuleBasicAdaptor(name, mod) + autoCliOpts.Modules[name] = mod + } + initRootCmd(rootCmd, clientCtx.TxConfig, moduleBasicManager) overwriteFlagDefaults(rootCmd, map[string]string{ diff --git a/config.yml b/config.yml index 6e1b4cf7..80d108ca 100644 --- a/config.yml +++ b/config.yml @@ -43,7 +43,8 @@ accounts: address: bb1zecxs0n0kjqr0vjc5ug3kk594zg4s7jn6lj5dj - name: charlie coins: - - 1ubadge + - 99999999999999996ubadge + - 500000000000000ustake - name: keplr address: bb1w63npeee74ewuudzf8cgvy6at4jn4mjr0a9r5p coins: diff --git a/proto/pot/genesis.proto b/proto/pot/genesis.proto new file mode 100644 index 00000000..05fccd71 --- /dev/null +++ b/proto/pot/genesis.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package pot; + +import "gogoproto/gogo.proto"; +import "pot/params.proto"; + +option go_package = "github.com/bitbadges/bitbadgeschain/x/pot/types"; + +message GenesisState { + Params params = 1 [(gogoproto.nullable) = false]; + repeated bytes compliance_jailed_validators = 2; +} diff --git a/proto/pot/params.proto b/proto/pot/params.proto new file mode 100644 index 00000000..a040cda0 --- /dev/null +++ b/proto/pot/params.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; +package pot; + +import "gogoproto/gogo.proto"; + +option go_package = "github.com/bitbadges/bitbadgeschain/x/pot/types"; + +message Params { + uint64 credential_collection_id = 1; + uint64 credential_token_id = 2; + uint64 min_credential_balance = 3; + string mode = 4; +} diff --git a/proto/pot/query.proto b/proto/pot/query.proto new file mode 100644 index 00000000..dc20eacb --- /dev/null +++ b/proto/pot/query.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; +package pot; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "pot/params.proto"; + +option go_package = "github.com/bitbadges/bitbadgeschain/x/pot/types"; + +service Query { + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/pot/params"; + } +} + +message QueryParamsRequest {} + +message QueryParamsResponse { + Params params = 1 [(gogoproto.nullable) = false]; +} diff --git a/proto/pot/tx.proto b/proto/pot/tx.proto new file mode 100644 index 00000000..ef070b46 --- /dev/null +++ b/proto/pot/tx.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package pot; + +import "amino/amino.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos_proto/cosmos.proto"; +import "gogoproto/gogo.proto"; +import "pot/params.proto"; + +option go_package = "github.com/bitbadges/bitbadgeschain/x/pot/types"; + +service Msg { + option (cosmos.msg.v1.service) = true; + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + option (amino.name) = "pot/MsgUpdateParams"; + + string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + Params params = 2 [(gogoproto.nullable) = false]; +} + +message MsgUpdateParamsResponse {} diff --git a/x/pot/client/cli/tx.go b/x/pot/client/cli/tx.go new file mode 100644 index 00000000..7f70af3a --- /dev/null +++ b/x/pot/client/cli/tx.go @@ -0,0 +1,123 @@ +package cli + +import ( + "encoding/json" + "fmt" + "strconv" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/gogoproto/proto" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/spf13/cobra" +) + +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "pot transactions subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand(CmdUpdateParams()) + return cmd +} + +func CmdUpdateParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "update-params [collection-id] [token-id] [min-balance] [mode]", + Short: "Update x/pot params (must be sent from governance authority)", + Long: "Update x/pot params. Mode: staked_multiplier, equal, or credential_weighted. Set collection-id to 0 to disable.", + Args: cobra.ExactArgs(4), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + collectionId, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return fmt.Errorf("invalid collection-id: %w", err) + } + tokenId, err := strconv.ParseUint(args[1], 10, 64) + if err != nil { + return fmt.Errorf("invalid token-id: %w", err) + } + minBalance, err := strconv.ParseUint(args[2], 10, 64) + if err != nil { + return fmt.Errorf("invalid min-balance: %w", err) + } + mode := args[3] + + params := types.Params{ + CredentialCollectionId: collectionId, + CredentialTokenId: tokenId, + MinCredentialBalance: minBalance, + Mode: mode, + } + if err := params.Validate(); err != nil { + return err + } + + msg := &types.MsgUpdateParams{ + Authority: clientCtx.GetFromAddress().String(), + Params: params, + } + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: "Querying commands for the pot module", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand(CmdQueryParams()) + return cmd +} + +func CmdQueryParams() *cobra.Command { + cmd := &cobra.Command{ + Use: "params", + Short: "Query x/pot params", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + // Use ABCI store query since we have JSON-encoded params + // (no protobuf gRPC gateway wired yet). + resp, err := clientCtx.Client.ABCIQuery(cmd.Context(), fmt.Sprintf("/store/%s/key", types.StoreKey), types.ParamsKey) + if err != nil { + return fmt.Errorf("failed to query params: %w", err) + } + if resp.Response.Value == nil { + fmt.Println("x/pot params: not set (module disabled)") + return nil + } + var params types.Params + if err := proto.Unmarshal(resp.Response.Value, ¶ms); err != nil { + // Try JSON fallback + if err2 := json.Unmarshal(resp.Response.Value, ¶ms); err2 != nil { + return fmt.Errorf("failed to unmarshal params: proto: %w, json: %v", err, err2) + } + } + out, _ := json.MarshalIndent(params, "", " ") + fmt.Println(string(out)) + return nil + }, + } + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/x/pot/keeper/abci.go b/x/pot/keeper/abci.go new file mode 100644 index 00000000..6ebe483d --- /dev/null +++ b/x/pot/keeper/abci.go @@ -0,0 +1,269 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// EndBlocker is called at the end of every block. +// +// Architecture (v2 — jail-based, no ValidatorUpdates): +// +// 1. Iterate ALL active validators via the ValidatorSetKeeper abstraction. +// 2. For each validator, check their credential token balance at the current block time. +// This catches both transfer-based and time-dependent credential expiry. +// 3. Validators without credentials are disabled via ValidatorSetKeeper.DisableValidator(). +// For x/staking this calls Jail(); for PoA it sets power to 0. +// 4. Validators who regained credentials and were compliance-jailed by x/pot +// are auto-enabled via ValidatorSetKeeper.EnableValidator(), but only if +// CanSafelyEnable() returns true (respects tombstone/slashing jail for staking). +// 5. x/pot tracks its own "compliance-jailed" set in persistent state to +// distinguish compliance-jailing from slashing-jailing. +// +// SAFETY: +// - Never disables ALL validators. If disabling would leave zero active validators, +// the remaining non-compliant validators are left enabled with a warning log. +// - All state changes are done via CacheContext for atomicity — if endBlockerInner +// returns an error, all changes are rolled back. +// - Individual Disable/Enable calls are wrapped in per-validator recover blocks +// as defense-in-depth. +// +// This EndBlocker returns only an error (via appmodule.HasEndBlocker), NOT +// ValidatorUpdates. This avoids the "validator EndBlock updates already set" +// panic that occurs when two modules return ValidatorUpdates. +func (k Keeper) EndBlocker(ctx sdk.Context) error { + cacheCtx, writeCache := ctx.CacheContext() + err := k.endBlockerInner(cacheCtx) + if err != nil { + k.Logger().Error("pot: EndBlocker failed, changes rolled back", "error", err) + return nil // don't propagate error, just skip this block's changes + } + writeCache() // commit all changes atomically + return nil +} + +// endBlockerInner contains the core EndBlocker logic. It runs inside a CacheContext +// so that any error causes all state changes to be rolled back atomically. +func (k Keeper) endBlockerInner(ctx sdk.Context) error { + params := k.GetParams(ctx) + + // If the module is not enabled (no credential collection configured), skip. + if !params.IsEnabled() { + return nil + } + + // Collect all active validators and check credentials. + type valInfo struct { + operatorAddr string + consAddr sdk.ConsAddress + hasCredential bool + } + + var validators []valInfo + + err := k.validatorSet.IterateActiveValidators(ctx, func(vi types.ValidatorInfo) bool { + // Check credential balance using the validator's account address (bb1...). + balance, err := k.tokenizationKeeper.GetCredentialBalance( + ctx, + params.CredentialCollectionId, + params.CredentialTokenId, + vi.OperatorAddr, + ) + if err != nil { + k.Logger().Error("pot: failed to get credential balance", + "operator", vi.OperatorAddr, "error", err) + // Treat errors as "has credential" to avoid disabling validators + // due to a keeper bug. + validators = append(validators, valInfo{ + operatorAddr: vi.OperatorAddr, + consAddr: vi.ConsAddr, + hasCredential: true, + }) + return false + } + + validators = append(validators, valInfo{ + operatorAddr: vi.OperatorAddr, + consAddr: vi.ConsAddr, + hasCredential: balance >= params.MinCredentialBalance, + }) + return false // continue + }) + if err != nil { + k.Logger().Error("pot: failed to iterate active validators", "error", err) + return nil + } + + // Also check compliance-jailed validators that may have regained credentials. + // These are no longer active, so IterateActiveValidators won't see them. + complianceJailedAddrs := k.GetAllComplianceJailed(ctx) + for _, addrBytes := range complianceJailedAddrs { + consAddr := sdk.ConsAddress(addrBytes) + + // Check if this validator is already in our active list (shouldn't be, but guard). + alreadySeen := false + for _, vi := range validators { + if vi.consAddr.Equals(consAddr) { + alreadySeen = true + break + } + } + if alreadySeen { + continue + } + + // Look up the validator by consensus address (O(1) via the adapter). + foundVal, err := k.validatorSet.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + // Validator no longer exists, clean up stale entry. + k.RemoveComplianceJailed(ctx, consAddr) + continue + } + + balance, err := k.tokenizationKeeper.GetCredentialBalance( + ctx, + params.CredentialCollectionId, + params.CredentialTokenId, + foundVal.OperatorAddr, + ) + if err != nil { + k.Logger().Error("pot: failed to get credential balance for jailed validator", + "operator", foundVal.OperatorAddr, "error", err) + continue + } + + if balance >= params.MinCredentialBalance { + validators = append(validators, valInfo{ + operatorAddr: foundVal.OperatorAddr, + consAddr: consAddr, + hasCredential: true, + }) + } + } + + // SAFETY: Count how many active validators will remain after disabling. + // Never disable ALL validators — that would halt the chain. + bondedCount := 0 + toDisableCount := 0 + for _, vi := range validators { + if !k.IsComplianceJailed(ctx, vi.consAddr) && !vi.hasCredential { + toDisableCount++ + } + // Count validators that are currently active (not already compliance-jailed). + if !k.IsComplianceJailed(ctx, vi.consAddr) { + bondedCount++ + } + } + + // If disabling all non-compliant validators would leave zero active validators, + // skip disabling entirely and log a critical warning. + safeToDisable := true + if bondedCount > 0 && toDisableCount >= bondedCount { + k.Logger().Error("pot: SAFETY — refusing to disable all validators, would halt chain", + "bonded", bondedCount, + "to_disable", toDisableCount, + ) + safeToDisable = false + } + + // Process each validator. + for _, vi := range validators { + isComplianceJailed := k.IsComplianceJailed(ctx, vi.consAddr) + + switch { + case vi.hasCredential && isComplianceJailed: + // Regained credential — check if safe to enable, then try. + if !k.validatorSet.CanSafelyEnable(ctx, vi.consAddr) { + // For staking: tombstoned or slashing jail still active. + // Check if tombstoned specifically to clean up. + jailed, _ := k.validatorSet.IsValidatorJailed(ctx, vi.consAddr) + if !jailed { + // Validator is no longer jailed but CanSafelyEnable is false + // — likely tombstoned. Clean up the stale entry. + k.RemoveComplianceJailed(ctx, vi.consAddr) + k.Logger().Info("pot: removed permanently disabled validator from compliance-jailed set", + "operator", vi.operatorAddr, + ) + } else { + k.Logger().Info("pot: validator regained credential but not safe to enable yet, deferring", + "operator", vi.operatorAddr, + ) + } + } else { + k.safeEnable(ctx, vi.consAddr, vi.operatorAddr) + k.RemoveComplianceJailed(ctx, vi.consAddr) + k.Logger().Info("pot: auto-enabled validator (credential regained)", + "operator", vi.operatorAddr, + ) + } + + case !vi.hasCredential && !isComplianceJailed && safeToDisable: + // Lost credential — disable for compliance. + // Only mark compliance-jailed if disable actually succeeded. + if k.safeDisable(ctx, vi.consAddr, vi.operatorAddr) { + k.SetComplianceJailed(ctx, vi.consAddr) + k.Logger().Info("pot: disabled validator for missing credential", + "operator", vi.operatorAddr, + ) + } + + // case vi.hasCredential && !isComplianceJailed: no action needed + // case !vi.hasCredential && isComplianceJailed: already disabled, no action + } + } + + return nil +} + +// safeDisable calls validatorSet.DisableValidator wrapped in a recover to prevent panics. +// Uses an inner CacheContext so partial writes from a panic are discarded. +// Returns true if the disable call succeeded, false otherwise. +func (k Keeper) safeDisable(ctx sdk.Context, consAddr sdk.ConsAddress, operatorAddr string) (success bool) { + innerCtx, writeInner := ctx.CacheContext() + defer func() { + if r := recover(); r != nil { + k.Logger().Error("pot: recovered from panic during DisableValidator", + "operator", operatorAddr, + "panic", fmt.Sprintf("%v", r), + ) + success = false + // writeInner is never called, so partial state is discarded + } + }() + + if err := k.validatorSet.DisableValidator(innerCtx, consAddr); err != nil { + k.Logger().Warn("pot: failed to disable validator", + "operator", operatorAddr, + "error", err, + ) + return false + } + writeInner() // commit only on success + return true +} + +// safeEnable calls validatorSet.EnableValidator wrapped in a recover to prevent panics. +// Uses an inner CacheContext so partial writes from a panic are discarded. +func (k Keeper) safeEnable(ctx sdk.Context, consAddr sdk.ConsAddress, operatorAddr string) { + innerCtx, writeInner := ctx.CacheContext() + defer func() { + if r := recover(); r != nil { + k.Logger().Error("pot: recovered from panic during EnableValidator", + "operator", operatorAddr, + "panic", fmt.Sprintf("%v", r), + ) + } + }() + + if err := k.validatorSet.EnableValidator(innerCtx, consAddr); err != nil { + k.Logger().Error("pot: failed to enable validator", + "operator", operatorAddr, + "error", err, + ) + return + } + writeInner() // commit only on success +} diff --git a/x/pot/keeper/abci_test.go b/x/pot/keeper/abci_test.go new file mode 100644 index 00000000..bf2f7892 --- /dev/null +++ b/x/pot/keeper/abci_test.go @@ -0,0 +1,507 @@ +package keeper_test + +import ( + "context" + "fmt" + "testing" + + "cosmossdk.io/log" + "cosmossdk.io/store" + "cosmossdk.io/store/metrics" + storetypes "cosmossdk.io/store/types" + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/stretchr/testify/require" + + "github.com/bitbadges/bitbadgeschain/x/pot/keeper" + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// --------------------------------------------------------------------------- +// Mock ValidatorSetKeeper +// --------------------------------------------------------------------------- + +type mockValidator struct { + consAddr sdk.ConsAddress + operatorAddr string // account address (bb1...) + power int64 + jailed bool +} + +type MockValidatorSetKeeper struct { + validators map[string]*mockValidator // key: consAddr hex string + disableCalls []sdk.ConsAddress // track disable calls for assertions + enableCalls []sdk.ConsAddress // track enable calls for assertions + canSafelyEnable map[string]bool // consAddr hex -> override (default: true) +} + +func NewMockValidatorSetKeeper() *MockValidatorSetKeeper { + return &MockValidatorSetKeeper{ + validators: make(map[string]*mockValidator), + canSafelyEnable: make(map[string]bool), + } +} + +func (m *MockValidatorSetKeeper) AddValidator(consAddr sdk.ConsAddress, operatorAddr string, power int64, jailed bool) { + m.validators[consAddr.String()] = &mockValidator{ + consAddr: consAddr, + operatorAddr: operatorAddr, + power: power, + jailed: jailed, + } +} + +func (m *MockValidatorSetKeeper) IterateActiveValidators(_ context.Context, fn func(val types.ValidatorInfo) bool) error { + for _, v := range m.validators { + if v.jailed || v.power <= 0 { + continue + } + if fn(types.ValidatorInfo{ + ConsAddr: v.consAddr, + OperatorAddr: v.operatorAddr, + Power: v.power, + }) { + break + } + } + return nil +} + +func (m *MockValidatorSetKeeper) GetValidatorByConsAddr(_ context.Context, consAddr sdk.ConsAddress) (types.ValidatorInfo, error) { + v, ok := m.validators[consAddr.String()] + if !ok { + return types.ValidatorInfo{}, fmt.Errorf("validator not found: %s", consAddr) + } + return types.ValidatorInfo{ + ConsAddr: v.consAddr, + OperatorAddr: v.operatorAddr, + Power: v.power, + }, nil +} + +func (m *MockValidatorSetKeeper) DisableValidator(_ context.Context, consAddr sdk.ConsAddress) error { + m.disableCalls = append(m.disableCalls, consAddr) + v, ok := m.validators[consAddr.String()] + if !ok { + return fmt.Errorf("validator not found: %s", consAddr) + } + v.jailed = true + return nil +} + +func (m *MockValidatorSetKeeper) EnableValidator(_ context.Context, consAddr sdk.ConsAddress) error { + m.enableCalls = append(m.enableCalls, consAddr) + v, ok := m.validators[consAddr.String()] + if !ok { + return fmt.Errorf("validator not found: %s", consAddr) + } + v.jailed = false + return nil +} + +func (m *MockValidatorSetKeeper) IsValidatorJailed(_ context.Context, consAddr sdk.ConsAddress) (bool, error) { + v, ok := m.validators[consAddr.String()] + if !ok { + return false, fmt.Errorf("validator not found: %s", consAddr) + } + return v.jailed, nil +} + +func (m *MockValidatorSetKeeper) CanSafelyEnable(_ context.Context, consAddr sdk.ConsAddress) bool { + if val, ok := m.canSafelyEnable[consAddr.String()]; ok { + return val + } + return true // default: safe to enable +} + +// --------------------------------------------------------------------------- +// Mock TokenizationKeeper +// --------------------------------------------------------------------------- + +type MockTokenizationKeeper struct { + // key: "collectionId:tokenId:address" -> balance + balances map[string]uint64 +} + +func NewMockTokenizationKeeper() *MockTokenizationKeeper { + return &MockTokenizationKeeper{ + balances: make(map[string]uint64), + } +} + +func (m *MockTokenizationKeeper) SetBalance(collectionId, tokenId uint64, address string, balance uint64) { + key := fmt.Sprintf("%d:%d:%s", collectionId, tokenId, address) + m.balances[key] = balance +} + +func (m *MockTokenizationKeeper) GetCredentialBalance(_ sdk.Context, collectionId, tokenId uint64, address string) (uint64, error) { + key := fmt.Sprintf("%d:%d:%s", collectionId, tokenId, address) + bal, ok := m.balances[key] + if !ok { + return 0, nil + } + return bal, nil +} + +// --------------------------------------------------------------------------- +// Test helper: create a validator with a random consensus key +// --------------------------------------------------------------------------- + +func makeTestValidator(t *testing.T) (sdk.ConsAddress, sdk.AccAddress) { + t.Helper() + privKey := ed25519.GenPrivKey() + pubKey := privKey.PubKey() + consAddr := sdk.ConsAddress(pubKey.Address()) + accAddr := sdk.AccAddress(pubKey.Address()) + return consAddr, accAddr +} + +// setupKeeperWithMocks creates a pot Keeper wired to the given mock keepers. +func setupKeeperWithMocks(t *testing.T, vs *MockValidatorSetKeeper, tk *MockTokenizationKeeper) (keeper.Keeper, sdk.Context) { + t.Helper() + + storeKey := storetypes.NewKVStoreKey(types.StoreKey) + + db := dbm.NewMemDB() + stateStore := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + stateStore.MountStoreWithDB(storeKey, storetypes.StoreTypeIAVL, db) + require.NoError(t, stateStore.LoadLatestVersion()) + + registry := codectypes.NewInterfaceRegistry() + appCodec := codec.NewProtoCodec(registry) + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + + k := keeper.NewKeeper( + appCodec, + storeKey, + log.NewNopLogger(), + authority.String(), + tk, + vs, + ) + + ctx := sdk.NewContext(stateStore, cmtproto.Header{}, false, log.NewNopLogger()) + return k, ctx +} + +// --------------------------------------------------------------------------- +// EndBlocker tests +// --------------------------------------------------------------------------- + +func TestEndBlocker_DisablesValidatorWithoutCredential(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + consAddr2, accAddr2 := makeTestValidator(t) + + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + vs.AddValidator(consAddr2, accAddr2.String(), 200, false) + + // Only validator 1 has a credential. + tk.SetBalance(1, 1, accAddr1.String(), 1) + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + err := k.EndBlocker(ctx) + require.NoError(t, err) + + // Validator 2 should have been disabled. + require.Len(t, vs.disableCalls, 1) + require.Equal(t, consAddr2, vs.disableCalls[0]) + + // Validator 2 should be in compliance-jailed set. + require.True(t, k.IsComplianceJailed(ctx, consAddr2)) + require.False(t, k.IsComplianceJailed(ctx, consAddr1)) +} + +func TestEndBlocker_AutoEnablesWhenCredentialRegained(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + consAddr2, accAddr2 := makeTestValidator(t) + + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + vs.AddValidator(consAddr2, accAddr2.String(), 200, false) + + tk.SetBalance(1, 1, accAddr1.String(), 1) + // Validator 2 initially has no credential. + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + // First EndBlocker: validator 2 gets disabled. + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.Len(t, vs.disableCalls, 1) + require.True(t, k.IsComplianceJailed(ctx, consAddr2)) + + // Give validator 2 a credential. + tk.SetBalance(1, 1, accAddr2.String(), 1) + + // Second EndBlocker: validator 2 should be auto-enabled. + vs.disableCalls = nil + vs.enableCalls = nil + err = k.EndBlocker(ctx) + require.NoError(t, err) + + require.Len(t, vs.enableCalls, 1) + require.Equal(t, consAddr2, vs.enableCalls[0]) + require.False(t, k.IsComplianceJailed(ctx, consAddr2)) +} + +func TestEndBlocker_DoesNotReDisableAlreadyComplianceJailed(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + consAddr2, accAddr2 := makeTestValidator(t) + + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + vs.AddValidator(consAddr2, accAddr2.String(), 200, false) + + tk.SetBalance(1, 1, accAddr1.String(), 1) + // Validator 2 has no credential. + _ = accAddr2 + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + // First EndBlocker: validator 2 gets disabled. + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.Len(t, vs.disableCalls, 1) + + // Second EndBlocker: validator 2 is already compliance-jailed, should NOT be disabled again. + vs.disableCalls = nil + err = k.EndBlocker(ctx) + require.NoError(t, err) + require.Empty(t, vs.disableCalls) +} + +func TestEndBlocker_SafetyRefusesToDisableAllValidators(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + // No credential for the only validator. + _ = accAddr1 + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + err := k.EndBlocker(ctx) + require.NoError(t, err) + + // Should NOT have disabled anyone. + require.Empty(t, vs.disableCalls) + require.False(t, k.IsComplianceJailed(ctx, consAddr1)) +} + +func TestEndBlocker_ModuleDisabled_NoAction(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + // No credential but module disabled. + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 0, // disabled + CredentialTokenId: 0, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.Empty(t, vs.disableCalls) +} + +func TestEndBlocker_AllValidatorsHaveCredentials_NoAction(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + for i := 0; i < 3; i++ { + consAddr, accAddr := makeTestValidator(t) + vs.AddValidator(consAddr, accAddr.String(), int64((i+1)*100), false) + tk.SetBalance(1, 1, accAddr.String(), 1) + } + + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.Empty(t, vs.disableCalls) + require.Empty(t, vs.enableCalls) +} + +func TestEndBlocker_SafetyAllowsPartialDisabling(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + // 3 validators: only the first has a credential. + var accAddrs []sdk.AccAddress + for i := 0; i < 3; i++ { + consAddr, accAddr := makeTestValidator(t) + vs.AddValidator(consAddr, accAddr.String(), 100, false) + accAddrs = append(accAddrs, accAddr) + } + tk.SetBalance(1, 1, accAddrs[0].String(), 1) + + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.Len(t, vs.disableCalls, 2) +} + +func TestEndBlocker_CanSafelyEnableFalse_DefersEnable(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + + consAddr1, accAddr1 := makeTestValidator(t) + consAddr2, accAddr2 := makeTestValidator(t) + + vs.AddValidator(consAddr1, accAddr1.String(), 100, false) + vs.AddValidator(consAddr2, accAddr2.String(), 200, false) + + tk.SetBalance(1, 1, accAddr1.String(), 1) + // Validator 2 has no credential. + + k, ctx := setupKeeperWithMocks(t, vs, tk) + + require.NoError(t, k.SetParams(ctx, types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + })) + + // Disable validator 2. + err := k.EndBlocker(ctx) + require.NoError(t, err) + require.True(t, k.IsComplianceJailed(ctx, consAddr2)) + + // Give credential back, but mark CanSafelyEnable as false (e.g., slashing jail). + tk.SetBalance(1, 1, accAddr2.String(), 1) + vs.canSafelyEnable[consAddr2.String()] = false + + vs.disableCalls = nil + vs.enableCalls = nil + err = k.EndBlocker(ctx) + require.NoError(t, err) + + // Should NOT have enabled — deferred. + require.Empty(t, vs.enableCalls) + // Should still be compliance-jailed. + require.True(t, k.IsComplianceJailed(ctx, consAddr2)) +} + +// --------------------------------------------------------------------------- +// Compliance-jailed state tests +// --------------------------------------------------------------------------- + +func TestComplianceJailedState(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + k, ctx := setupKeeperWithMocks(t, vs, tk) + + consAddr := sdk.ConsAddress(ed25519.GenPrivKey().PubKey().Address()) + + // Initially not compliance-jailed. + require.False(t, k.IsComplianceJailed(ctx, consAddr)) + + // Set compliance-jailed. + k.SetComplianceJailed(ctx, consAddr) + require.True(t, k.IsComplianceJailed(ctx, consAddr)) + + // GetAll should include it. + all := k.GetAllComplianceJailed(ctx) + require.Len(t, all, 1) + + // Remove compliance-jailed. + k.RemoveComplianceJailed(ctx, consAddr) + require.False(t, k.IsComplianceJailed(ctx, consAddr)) + + all = k.GetAllComplianceJailed(ctx) + require.Empty(t, all) +} + +// --------------------------------------------------------------------------- +// SavedPower (PowerStore) tests +// --------------------------------------------------------------------------- + +func TestSavedPower(t *testing.T) { + vs := NewMockValidatorSetKeeper() + tk := NewMockTokenizationKeeper() + k, ctx := setupKeeperWithMocks(t, vs, tk) + + consAddr := sdk.ConsAddress(ed25519.GenPrivKey().PubKey().Address()) + + // Initially no saved power. + power, found := k.GetSavedPower(ctx, consAddr) + require.False(t, found) + require.Equal(t, int64(0), power) + + // Set saved power. + k.SetSavedPower(ctx, consAddr, 42) + power, found = k.GetSavedPower(ctx, consAddr) + require.True(t, found) + require.Equal(t, int64(42), power) + + // Remove saved power. + k.RemoveSavedPower(ctx, consAddr) + power, found = k.GetSavedPower(ctx, consAddr) + require.False(t, found) + require.Equal(t, int64(0), power) +} diff --git a/x/pot/keeper/grpc_query.go b/x/pot/keeper/grpc_query.go new file mode 100644 index 00000000..d255aaa3 --- /dev/null +++ b/x/pot/keeper/grpc_query.go @@ -0,0 +1,18 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +var _ types.QueryServer = Keeper{} + +// Params implements the Query/Params gRPC method. +func (k Keeper) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + params := k.GetParams(ctx) + return &types.QueryParamsResponse{Params: params}, nil +} diff --git a/x/pot/keeper/hooks.go b/x/pot/keeper/hooks.go new file mode 100644 index 00000000..b11b0053 --- /dev/null +++ b/x/pot/keeper/hooks.go @@ -0,0 +1,12 @@ +package keeper + +// This file previously contained the transient-queue and hook-based approach +// (EnqueueAddress, DrainQueue, OnCredentialTransfer). +// +// That approach was removed because: +// 1. Time-dependent credential expiry is missed when no transfer event fires. +// 2. Returning ValidatorUpdates from two modules (x/staking + x/pot) causes +// an instant chain halt ("validator EndBlock updates already set"). +// +// The new approach iterates all bonded validators in EndBlocker and uses +// staking Jail/Unjail. See abci.go. diff --git a/x/pot/keeper/hooks_test.go b/x/pot/keeper/hooks_test.go new file mode 100644 index 00000000..977f5c81 --- /dev/null +++ b/x/pot/keeper/hooks_test.go @@ -0,0 +1,4 @@ +package keeper_test + +// The hook/queue tests were removed along with the transient-queue approach. +// See abci_test.go for the replacement tests using the jail-based architecture. diff --git a/x/pot/keeper/invariants.go b/x/pot/keeper/invariants.go new file mode 100644 index 00000000..8fe8b407 --- /dev/null +++ b/x/pot/keeper/invariants.go @@ -0,0 +1,52 @@ +package keeper + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// RegisterInvariants registers all x/pot invariants. +func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { + ir.RegisterRoute(types.ModuleName, "compliance-jailed-valid", ComplianceJailedValidInvariant(k)) +} + +// ComplianceJailedValidInvariant checks that: +// 1. Every address in the compliance-jailed set corresponds to an existing validator. +// 2. Every compliance-jailed validator is actually disabled (jailed/power=0). +func ComplianceJailedValidInvariant(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + var msg string + broken := false + + complianceJailed := k.GetAllComplianceJailed(ctx) + for _, addrBytes := range complianceJailed { + consAddr := sdk.ConsAddress(addrBytes) + + // Check that the validator exists. + _, err := k.validatorSet.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + msg += fmt.Sprintf("\tcompliance-jailed validator %s does not exist in validator set\n", consAddr) + broken = true + continue + } + + // Check that the validator is actually jailed/disabled. + jailed, jErr := k.validatorSet.IsValidatorJailed(ctx, consAddr) + if jErr != nil { + msg += fmt.Sprintf("\tcompliance-jailed validator %s: error checking jailed status: %v\n", + consAddr, jErr) + broken = true + continue + } + if !jailed { + msg += fmt.Sprintf("\tcompliance-jailed validator %s is not disabled in validator set\n", consAddr) + broken = true + } + } + + return sdk.FormatInvariant(types.ModuleName, "compliance-jailed-valid", msg), broken + } +} diff --git a/x/pot/keeper/keeper.go b/x/pot/keeper/keeper.go new file mode 100644 index 00000000..bbae75e8 --- /dev/null +++ b/x/pot/keeper/keeper.go @@ -0,0 +1,141 @@ +package keeper + +import ( + "context" + "encoding/binary" + "fmt" + + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// Keeper holds references to the abstract validator set and tokenization keepers +// plus its own KV store (for params, compliance-jailed set, and saved power). +type Keeper struct { + cdc codec.BinaryCodec + logger log.Logger + + // storeKey is for persistent state (params + compliance-jailed set + saved power). + storeKey storetypes.StoreKey + + // authority is the address capable of executing MsgUpdateParams (typically x/gov). + authority string + + // External keeper interfaces — never concrete types. + validatorSet types.ValidatorSetKeeper + tokenizationKeeper types.TokenizationKeeper +} + +// NewKeeper creates a new x/pot keeper. +func NewKeeper( + cdc codec.BinaryCodec, + storeKey storetypes.StoreKey, + logger log.Logger, + authority string, + tokenizationKeeper types.TokenizationKeeper, + validatorSet types.ValidatorSetKeeper, +) Keeper { + if _, err := sdk.AccAddressFromBech32(authority); err != nil { + panic(fmt.Sprintf("invalid authority address: %s", authority)) + } + + return Keeper{ + cdc: cdc, + storeKey: storeKey, + logger: logger, + authority: authority, + validatorSet: validatorSet, + tokenizationKeeper: tokenizationKeeper, + } +} + +// GetAuthority returns the module's governance authority address. +func (k Keeper) GetAuthority() string { + return k.authority +} + +// Logger returns a module-specific logger. +func (k Keeper) Logger() log.Logger { + return k.logger.With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// -------------------------------------------------------------------------- +// Compliance-jailed validator set (persistent KV store) +// -------------------------------------------------------------------------- + +// SetComplianceJailed marks a validator (by consensus address) as compliance-jailed +// in x/pot's own state. +func (k Keeper) SetComplianceJailed(ctx sdk.Context, consAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + store.Set(types.ComplianceJailedKey(consAddr), []byte{1}) +} + +// RemoveComplianceJailed removes a validator from the compliance-jailed set. +func (k Keeper) RemoveComplianceJailed(ctx sdk.Context, consAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ComplianceJailedKey(consAddr)) +} + +// IsComplianceJailed returns true if the validator is in x/pot's compliance-jailed set. +func (k Keeper) IsComplianceJailed(ctx sdk.Context, consAddr sdk.ConsAddress) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.ComplianceJailedKey(consAddr)) +} + +// GetAllComplianceJailed returns all consensus addresses in the compliance-jailed set. +func (k Keeper) GetAllComplianceJailed(ctx sdk.Context) [][]byte { + store := ctx.KVStore(k.storeKey) + iter := store.Iterator( + types.ComplianceJailedPrefix, + storetypes.PrefixEndBytes(types.ComplianceJailedPrefix), + ) + defer iter.Close() + + var addrs [][]byte + for ; iter.Valid(); iter.Next() { + key := iter.Key() + addr := make([]byte, len(key)-len(types.ComplianceJailedPrefix)) + copy(addr, key[len(types.ComplianceJailedPrefix):]) + addrs = append(addrs, addr) + } + return addrs +} + +// -------------------------------------------------------------------------- +// Saved power store (for PoA adapter — implements types.PowerStore) +// -------------------------------------------------------------------------- + +// GetSavedPower returns the saved voting power for a validator, plus a bool +// indicating whether an entry existed. +func (k Keeper) GetSavedPower(ctx context.Context, consAddr sdk.ConsAddress) (int64, bool) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + store := sdkCtx.KVStore(k.storeKey) + bz := store.Get(types.SavedPowerKey(consAddr)) + if bz == nil { + return 0, false + } + return int64(binary.BigEndian.Uint64(bz)), true +} + +// SetSavedPower persists the saved voting power for a validator. +func (k Keeper) SetSavedPower(ctx context.Context, consAddr sdk.ConsAddress, power int64) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + store := sdkCtx.KVStore(k.storeKey) + bz := make([]byte, 8) + binary.BigEndian.PutUint64(bz, uint64(power)) + store.Set(types.SavedPowerKey(consAddr), bz) +} + +// RemoveSavedPower deletes the saved voting power entry for a validator. +func (k Keeper) RemoveSavedPower(ctx context.Context, consAddr sdk.ConsAddress) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + store := sdkCtx.KVStore(k.storeKey) + store.Delete(types.SavedPowerKey(consAddr)) +} + +// Compile-time check that Keeper implements PowerStore. +var _ types.PowerStore = Keeper{} diff --git a/x/pot/keeper/msg_server.go b/x/pot/keeper/msg_server.go new file mode 100644 index 00000000..9949838c --- /dev/null +++ b/x/pot/keeper/msg_server.go @@ -0,0 +1,61 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +type msgServer struct { + Keeper +} + +// Ensure msgServer implements the MsgServer interface. +var _ types.MsgServer = msgServer{} + +// NewMsgServerImpl returns an implementation of the MsgServer interface. +func NewMsgServerImpl(keeper Keeper) msgServer { + return msgServer{Keeper: keeper} +} + +// UpdateParams handles MsgUpdateParams. +func (k msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if k.GetAuthority() != msg.Authority { + return nil, types.ErrInvalidSigner.Wrapf("invalid authority; expected %s, got %s", k.GetAuthority(), msg.Authority) + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + // Read old params before updating so we can detect credential collection changes. + oldParams := k.GetParams(ctx) + + if err := k.SetParams(ctx, msg.Params); err != nil { + return nil, err + } + + // Fix 4: If CredentialCollectionId changed, clear all compliance-jailed entries. + // All validators will be re-evaluated on the next EndBlocker with the new collection. + if oldParams.CredentialCollectionId != msg.Params.CredentialCollectionId { + for _, addrBytes := range k.GetAllComplianceJailed(ctx) { + consAddr := sdk.ConsAddress(addrBytes) + k.RemoveComplianceJailed(ctx, consAddr) + + // Enable if safe (respects tombstone/slashing for staking, always true for PoA). + if k.validatorSet.CanSafelyEnable(ctx, consAddr) { + k.safeEnable(ctx, consAddr, consAddr.String()) + } + } + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + "pot_params_updated", + sdk.NewAttribute("authority", msg.Authority), + sdk.NewAttribute("mode", msg.Params.Mode), + ), + ) + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/pot/keeper/params.go b/x/pot/keeper/params.go new file mode 100644 index 00000000..ee588477 --- /dev/null +++ b/x/pot/keeper/params.go @@ -0,0 +1,49 @@ +package keeper + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// GetParams returns the current x/pot params from the persistent store. +// It tries protobuf first, falls back to JSON (old format), and self-heals +// by re-writing as protobuf on JSON success. +func (k Keeper) GetParams(ctx sdk.Context) types.Params { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ParamsKey) + if bz == nil { + return types.DefaultParams() + } + + var params types.Params + // Try protobuf first (new format). + if err := k.cdc.Unmarshal(bz, ¶ms); err == nil { + return params + } + // Fall back to JSON (old format) — self-healing migration. + if err := json.Unmarshal(bz, ¶ms); err == nil { + // Re-write as protobuf for future reads. + newBz, err := k.cdc.Marshal(¶ms) + if err == nil { + store.Set(types.ParamsKey, newBz) + } + return params + } + // Both failed — return defaults. + return types.DefaultParams() +} + +// SetParams persists the x/pot params to the store using protobuf encoding. +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) error { + if err := params.Validate(); err != nil { + return err + } + + store := ctx.KVStore(k.storeKey) + bz := k.cdc.MustMarshal(¶ms) + store.Set(types.ParamsKey, bz) + return nil +} diff --git a/x/pot/keeper/poa_adapter.go b/x/pot/keeper/poa_adapter.go new file mode 100644 index 00000000..b360592e --- /dev/null +++ b/x/pot/keeper/poa_adapter.go @@ -0,0 +1,109 @@ +package keeper + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// PoAKeeper is the interface that a PoA keeper must satisfy for x/pot integration. +// Chain developers using PoA implement this interface wrapping their actual PoA keeper. +type PoAKeeper interface { + // IterateActiveValidators walks validators with power > 0. + // The callback receives the raw consensus address bytes, operator address string, + // and voting power. Return true to stop iteration. + IterateActiveValidators(ctx context.Context, fn func(consAddr []byte, operatorAddr string, power int64) bool) error + + // GetValidatorByConsAddr looks up a validator. + GetValidatorByConsAddr(ctx context.Context, consAddr []byte) (operatorAddr string, power int64, err error) + + // SetValidatorPower updates a validator's voting power. + SetValidatorPower(ctx context.Context, consAddr []byte, power int64) error +} + +// PoAValidatorSetAdapter wraps a PoAKeeper into a ValidatorSetKeeper. +// It persists saved power via a PowerStore so that disabled validators +// can have their power restored on re-enable. +type PoAValidatorSetAdapter struct { + poaKeeper PoAKeeper + powerStore types.PowerStore +} + +// NewPoAAdapter creates a new PoAValidatorSetAdapter. +// The powerStore should be the x/pot Keeper (which implements types.PowerStore) +// to persist saved power across blocks. +func NewPoAAdapter(pk PoAKeeper, ps types.PowerStore) *PoAValidatorSetAdapter { + return &PoAValidatorSetAdapter{poaKeeper: pk, powerStore: ps} +} + +// IterateActiveValidators walks all PoA validators with positive power. +func (a *PoAValidatorSetAdapter) IterateActiveValidators(ctx context.Context, fn func(val types.ValidatorInfo) bool) error { + return a.poaKeeper.IterateActiveValidators(ctx, func(consAddr []byte, operatorAddr string, power int64) bool { + return fn(types.ValidatorInfo{ + ConsAddr: sdk.ConsAddress(consAddr), + OperatorAddr: operatorAddr, + Power: power, + }) + }) +} + +// GetValidatorByConsAddr looks up a PoA validator by consensus address. +func (a *PoAValidatorSetAdapter) GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (types.ValidatorInfo, error) { + operatorAddr, power, err := a.poaKeeper.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + return types.ValidatorInfo{}, err + } + return types.ValidatorInfo{ + ConsAddr: consAddr, + OperatorAddr: operatorAddr, + Power: power, + }, nil +} + +// DisableValidator saves the validator's current power and sets it to 0. +func (a *PoAValidatorSetAdapter) DisableValidator(ctx context.Context, consAddr sdk.ConsAddress) error { + _, power, err := a.poaKeeper.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + return fmt.Errorf("cannot disable validator: %w", err) + } + + // Save current power so it can be restored later. + if power > 0 { + a.powerStore.SetSavedPower(ctx, consAddr, power) + } + + return a.poaKeeper.SetValidatorPower(ctx, consAddr, 0) +} + +// EnableValidator restores the validator's saved power. +func (a *PoAValidatorSetAdapter) EnableValidator(ctx context.Context, consAddr sdk.ConsAddress) error { + savedPower, found := a.powerStore.GetSavedPower(ctx, consAddr) + if !found || savedPower <= 0 { + // No saved power — use a default of 1 to re-enable. + savedPower = 1 + } + + a.powerStore.RemoveSavedPower(ctx, consAddr) + return a.poaKeeper.SetValidatorPower(ctx, consAddr, savedPower) +} + +// IsValidatorJailed returns true if the validator's power is 0. +// In PoA, "jailed" means "disabled" (power == 0). +func (a *PoAValidatorSetAdapter) IsValidatorJailed(ctx context.Context, consAddr sdk.ConsAddress) (bool, error) { + _, power, err := a.poaKeeper.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + return false, err + } + return power == 0, nil +} + +// CanSafelyEnable always returns true for PoA — there is no slashing concept. +func (a *PoAValidatorSetAdapter) CanSafelyEnable(_ context.Context, _ sdk.ConsAddress) bool { + return true +} + +// Compile-time check that PoAValidatorSetAdapter implements ValidatorSetKeeper. +var _ types.ValidatorSetKeeper = (*PoAValidatorSetAdapter)(nil) diff --git a/x/pot/keeper/query.go b/x/pot/keeper/query.go new file mode 100644 index 00000000..b6ff0253 --- /dev/null +++ b/x/pot/keeper/query.go @@ -0,0 +1,66 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// QueryParamsResponse is the response for the Params query. +type QueryParamsResponse struct { + Params types.Params `json:"params"` +} + +// QueryCredentialStatusRequest is the request for querying a validator's credential status. +type QueryCredentialStatusRequest struct { + ValidatorAddress string `json:"validator_address"` +} + +// QueryCredentialStatusResponse is the response for the CredentialStatus query. +type QueryCredentialStatusResponse struct { + HasCredential bool `json:"has_credential"` + CredentialBalance uint64 `json:"credential_balance"` + IsValidator bool `json:"is_validator"` + IsBonded bool `json:"is_bonded"` + IsJailed bool `json:"is_jailed"` + IsComplianceJailed bool `json:"is_compliance_jailed"` +} + +// QueryParams returns the current module parameters. +// Once proto/gRPC is added, this will become a proper gRPC query handler. +func (k Keeper) QueryParams(ctx sdk.Context) QueryParamsResponse { + return QueryParamsResponse{Params: k.GetParams(ctx)} +} + +// QueryCredentialStatus returns the credential status for a given validator address. +// This is useful for dashboards and debugging. +func (k Keeper) QueryCredentialStatus(ctx sdk.Context, req QueryCredentialStatusRequest) QueryCredentialStatusResponse { + params := k.GetParams(ctx) + resp := QueryCredentialStatusResponse{} + + if !params.IsEnabled() { + return resp + } + + // The query accepts either a validator operator address or an account address. + // We cannot call the old staking keeper directly — use the abstract interface. + // For now, the query provides credential balance and compliance-jailed status. + // Detailed staking info (IsBonded, IsJailed) is only available when the + // ValidatorSetKeeper can look up by the provided address. + + // Check credential balance using the provided address directly. + balance, err := k.tokenizationKeeper.GetCredentialBalance( + ctx, + params.CredentialCollectionId, + params.CredentialTokenId, + req.ValidatorAddress, + ) + if err != nil { + return resp + } + + resp.CredentialBalance = balance + resp.HasCredential = balance >= params.MinCredentialBalance + resp.IsValidator = true // Assume valid if queried; full validation requires staking context. + return resp +} diff --git a/x/pot/keeper/staking_adapter.go b/x/pot/keeper/staking_adapter.go new file mode 100644 index 00000000..0ef08758 --- /dev/null +++ b/x/pot/keeper/staking_adapter.go @@ -0,0 +1,118 @@ +package keeper + +import ( + "context" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +// StakingValidatorSetAdapter wraps the existing StakingKeeper + SlashingKeeper +// into the abstract ValidatorSetKeeper interface. +type StakingValidatorSetAdapter struct { + stakingKeeper types.StakingKeeper + slashingKeeper types.SlashingKeeper +} + +// NewStakingAdapter creates a new StakingValidatorSetAdapter. +func NewStakingAdapter(sk types.StakingKeeper, slk types.SlashingKeeper) *StakingValidatorSetAdapter { + return &StakingValidatorSetAdapter{stakingKeeper: sk, slashingKeeper: slk} +} + +// IterateActiveValidators walks all bonded validators by power and converts +// each to a ValidatorInfo. The callback returns true to stop iteration. +func (a *StakingValidatorSetAdapter) IterateActiveValidators(ctx context.Context, fn func(val types.ValidatorInfo) bool) error { + return a.stakingKeeper.IterateBondedValidatorsByPower(ctx, func(_ int64, val stakingtypes.ValidatorI) bool { + consAddrBytes, err := val.GetConsAddr() + if err != nil { + return false // skip, continue iteration + } + + // Convert valoper (bbvaloper...) to account address (bb1...). + operatorAddr := val.GetOperator() + valAddr, err := sdk.ValAddressFromBech32(operatorAddr) + if err != nil { + return false // skip + } + accAddr := sdk.AccAddress(valAddr).String() + + info := types.ValidatorInfo{ + ConsAddr: sdk.ConsAddress(consAddrBytes), + OperatorAddr: accAddr, + Power: 0, // power is not used by the EndBlocker currently + } + return fn(info) + }) +} + +// GetValidatorByConsAddr looks up a validator by consensus address. +func (a *StakingValidatorSetAdapter) GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (types.ValidatorInfo, error) { + val, err := a.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + return types.ValidatorInfo{}, err + } + + // Convert valoper to account address. + operatorAddr := val.GetOperator() + valAddr, valErr := sdk.ValAddressFromBech32(operatorAddr) + accAddr := operatorAddr + if valErr == nil { + accAddr = sdk.AccAddress(valAddr).String() + } + + return types.ValidatorInfo{ + ConsAddr: consAddr, + OperatorAddr: accAddr, + Power: 0, + }, nil +} + +// DisableValidator jails a validator via x/staking. +func (a *StakingValidatorSetAdapter) DisableValidator(ctx context.Context, consAddr sdk.ConsAddress) error { + return a.stakingKeeper.Jail(ctx, consAddr) +} + +// EnableValidator unjails a validator via x/staking. +func (a *StakingValidatorSetAdapter) EnableValidator(ctx context.Context, consAddr sdk.ConsAddress) error { + return a.stakingKeeper.Unjail(ctx, consAddr) +} + +// IsValidatorJailed checks the staking module's jailed flag. +func (a *StakingValidatorSetAdapter) IsValidatorJailed(ctx context.Context, consAddr sdk.ConsAddress) (bool, error) { + val, err := a.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + if err != nil { + return false, fmt.Errorf("validator not found: %w", err) + } + return val.IsJailed(), nil +} + +// CanSafelyEnable checks whether it is safe to unjail a validator by consulting +// the slashing module. Returns false if tombstoned or if the slashing jail +// period has not yet expired. +func (a *StakingValidatorSetAdapter) CanSafelyEnable(ctx context.Context, consAddr sdk.ConsAddress) bool { + // Tombstoned validators are permanently banned. + if a.slashingKeeper.IsTombstoned(ctx, consAddr) { + return false + } + + // Check jailed-until — respect slashing jail period. + signingInfo, err := a.slashingKeeper.GetValidatorSigningInfo(ctx, consAddr) + if err != nil { + // No signing info means validator was never slashing-jailed; safe to unjail. + return true + } + + // If JailedUntil is set and hasn't passed yet, don't enable. + sdkCtx := sdk.UnwrapSDKContext(ctx) + if !signingInfo.JailedUntil.IsZero() && !signingInfo.JailedUntil.Before(sdkCtx.BlockTime()) { + return false + } + + return true +} + +// Compile-time check that StakingValidatorSetAdapter implements ValidatorSetKeeper. +var _ types.ValidatorSetKeeper = (*StakingValidatorSetAdapter)(nil) diff --git a/x/pot/keeper/tokenization_adapter.go b/x/pot/keeper/tokenization_adapter.go new file mode 100644 index 00000000..b0fbd44a --- /dev/null +++ b/x/pot/keeper/tokenization_adapter.go @@ -0,0 +1,82 @@ +package keeper + +import ( + "fmt" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + + tokenizationkeeper "github.com/bitbadges/bitbadgeschain/x/tokenization/keeper" + tokenizationtypes "github.com/bitbadges/bitbadgeschain/x/tokenization/types" +) + +// TokenizationKeeperAdapter adapts the concrete x/tokenization keeper to the +// x/pot TokenizationKeeper interface. It wraps all calls defensively so that +// no panic can escape — missing collections or balance errors return 0. +type TokenizationKeeperAdapter struct { + keeper *tokenizationkeeper.Keeper +} + +// NewTokenizationKeeperAdapter creates a new adapter wrapping the tokenization keeper. +func NewTokenizationKeeperAdapter(keeper *tokenizationkeeper.Keeper) *TokenizationKeeperAdapter { + return &TokenizationKeeperAdapter{keeper: keeper} +} + +// GetCredentialBalance returns the balance of a specific token for a given address. +// Returns 0 if the collection is not found, the balance query fails, or any other error. +// This method never panics. +func (a *TokenizationKeeperAdapter) GetCredentialBalance(ctx sdk.Context, collectionId uint64, tokenId uint64, address string) (balance uint64, err error) { + // Top-level recover to guarantee no panic escapes. + defer func() { + if r := recover(); r != nil { + balance = 0 + err = fmt.Errorf("panic in GetCredentialBalance: %v", r) + } + }() + + // Fetch collection from store. + collection, found := a.keeper.GetCollectionFromStore(ctx, sdkmath.NewUint(collectionId)) + if !found { + return 0, nil + } + + // Fetch the balance store for this address. + balanceStore, _, balErr := a.keeper.GetBalanceOrApplyDefault(ctx, collection, address) + if balErr != nil { + return 0, nil + } + + // Build ranges for a single token ID at current block time. + tokenIdRange := &tokenizationtypes.UintRange{ + Start: sdkmath.NewUint(tokenId), + End: sdkmath.NewUint(tokenId), + } + + blockTimeMs := uint64(ctx.BlockTime().UnixMilli()) + timeRange := &tokenizationtypes.UintRange{ + Start: sdkmath.NewUint(blockTimeMs), + End: sdkmath.NewUint(blockTimeMs), + } + + fetchedBalances, fetchErr := tokenizationtypes.GetBalancesForIds( + ctx, + []*tokenizationtypes.UintRange{tokenIdRange}, + []*tokenizationtypes.UintRange{timeRange}, + balanceStore.Balances, + ) + if fetchErr != nil { + return 0, nil + } + + if len(fetchedBalances) == 0 { + return 0, nil + } + + // The amount is an sdkmath.Uint — convert to uint64. + amount := fetchedBalances[0].Amount + if amount.IsNil() { + return 0, nil + } + + return amount.Uint64(), nil +} diff --git a/x/pot/module/module.go b/x/pot/module/module.go new file mode 100644 index 00000000..1f654a8b --- /dev/null +++ b/x/pot/module/module.go @@ -0,0 +1,163 @@ +package pot + +import ( + "context" + "encoding/json" + "fmt" + + "cosmossdk.io/core/appmodule" + "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" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/spf13/cobra" + + "github.com/bitbadges/bitbadgeschain/x/pot/client/cli" + "github.com/bitbadges/bitbadgeschain/x/pot/keeper" + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +var ( + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.HasGenesis = (*AppModule)(nil) + _ module.HasConsensusVersion = (*AppModule)(nil) + + _ appmodule.AppModule = (*AppModule)(nil) + _ appmodule.HasEndBlocker = (*AppModule)(nil) +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +// AppModuleBasic implements the AppModuleBasic interface. +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the module name. +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the amino codec for the module. +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types. +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +// DefaultGenesis returns the default genesis state (JSON). +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + gs := types.DefaultGenesis() + bz, err := json.Marshal(gs) + if err != nil { + panic(fmt.Errorf("failed to marshal default genesis state: %w", err)) + } + return bz +} + +// ValidateGenesis validates the genesis state. +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error { + var gs types.GenesisState + if err := json.Unmarshal(bz, &gs); err != nil { + return err + } + return gs.Validate() +} + +// RegisterGRPCGatewayRoutes registers gRPC gateway routes. +// No-op until full gRPC gateway is wired. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} + +// GetTxCmd returns the root tx command for the module. +func (a AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// GetQueryCmd returns the root query command for the module. +func (a AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface for x/pot. +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper +} + +// NewAppModule creates a new AppModule. +func NewAppModule(cdc codec.Codec, keeper keeper.Keeper) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + } +} + +// RegisterServices registers module gRPC services (Msg + Query). +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// RegisterInvariants registers module invariants. +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + keeper.RegisterInvariants(ir, am.keeper) +} + +// InitGenesis initializes the module genesis state. +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) { + var gs types.GenesisState + if err := json.Unmarshal(data, &gs); err != nil { + panic(err) + } + if err := am.keeper.SetParams(ctx, gs.Params); err != nil { + panic(err) + } + + // Restore compliance-jailed set from genesis. + for _, addrBytes := range gs.ComplianceJailedValidators { + am.keeper.SetComplianceJailed(ctx, sdk.ConsAddress(addrBytes)) + } +} + +// ExportGenesis exports the module genesis state. +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + gs := types.GenesisState{ + Params: am.keeper.GetParams(ctx), + ComplianceJailedValidators: am.keeper.GetAllComplianceJailed(ctx), + } + bz, err := json.Marshal(gs) + if err != nil { + panic(fmt.Errorf("failed to marshal genesis state: %w", err)) + } + return bz +} + +// ConsensusVersion returns the module consensus version. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// EndBlock runs the x/pot EndBlocker. +func (am AppModule) EndBlock(goCtx context.Context) error { + ctx := sdk.UnwrapSDKContext(goCtx) + return am.keeper.EndBlocker(ctx) +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (am AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (am AppModule) IsAppModule() {} diff --git a/x/pot/types/codec.go b/x/pot/types/codec.go new file mode 100644 index 00000000..7cf2e19f --- /dev/null +++ b/x/pot/types/codec.go @@ -0,0 +1,31 @@ +package types + +import ( + "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/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgUpdateParams{}, "pot/MsgUpdateParams", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +// NOTE: This is required for the GetSignBytes function +func init() { + RegisterCodec(Amino) + Amino.Seal() +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + AminoCdc = codec.NewAminoCodec(Amino) +) diff --git a/x/pot/types/errors.go b/x/pot/types/errors.go new file mode 100644 index 00000000..05361844 --- /dev/null +++ b/x/pot/types/errors.go @@ -0,0 +1,14 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "cosmossdk.io/errors" +) + +// x/pot module sentinel errors +var ( + ErrInvalidSigner = sdkerrors.Register(ModuleName, 1100, "expected gov account as only signer for proposal message") + ErrInvalidRequest = sdkerrors.Register(ModuleName, 1101, "invalid request") + ErrInvalidParams = sdkerrors.Register(ModuleName, 1102, "invalid params") +) diff --git a/x/pot/types/expected_keepers.go b/x/pot/types/expected_keepers.go new file mode 100644 index 00000000..486cd6af --- /dev/null +++ b/x/pot/types/expected_keepers.go @@ -0,0 +1,111 @@ +package types + +import ( + "context" + + sdkmath "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// --------------------------------------------------------------------------- +// Abstract validator set interface (supports both x/staking and PoA) +// --------------------------------------------------------------------------- + +// ValidatorInfo contains the information x/pot needs about a validator. +type ValidatorInfo struct { + ConsAddr sdk.ConsAddress + OperatorAddr string // account address (bb1...) for credential lookup + Power int64 // current voting power +} + +// ValidatorSetKeeper abstracts the validator set management layer. +// Implementations exist for both x/staking and PoA. +type ValidatorSetKeeper interface { + // IterateActiveValidators walks all validators with positive power. + IterateActiveValidators(ctx context.Context, fn func(val ValidatorInfo) bool) error + + // GetValidatorByConsAddr looks up a validator by consensus address. + // Returns the validator info or an error if not found. + GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (ValidatorInfo, error) + + // DisableValidator removes a validator from the active set. + // For x/staking: calls Jail(). For PoA: sets power to 0. + DisableValidator(ctx context.Context, consAddr sdk.ConsAddress) error + + // EnableValidator restores a validator to the active set. + // For x/staking: calls Unjail(). For PoA: restores saved power. + EnableValidator(ctx context.Context, consAddr sdk.ConsAddress) error + + // IsValidatorJailed returns whether the validator is currently disabled/jailed. + IsValidatorJailed(ctx context.Context, consAddr sdk.ConsAddress) (bool, error) + + // CanSafelyEnable checks whether EnableValidator is safe to call. + // For x/staking: checks not tombstoned and JailedUntil has passed. + // For PoA: always returns true (no slashing concept). + CanSafelyEnable(ctx context.Context, consAddr sdk.ConsAddress) bool +} + +// PowerStore abstracts the persistence of saved validator power for the PoA adapter. +// The Keeper implements this interface so the PoA adapter can store/retrieve +// saved power without a circular dependency. +type PowerStore interface { + GetSavedPower(ctx context.Context, consAddr sdk.ConsAddress) (int64, bool) + SetSavedPower(ctx context.Context, consAddr sdk.ConsAddress, power int64) + RemoveSavedPower(ctx context.Context, consAddr sdk.ConsAddress) +} + +// --------------------------------------------------------------------------- +// Concrete keeper interfaces (used internally by the StakingAdapter) +// --------------------------------------------------------------------------- + +// StakingKeeper defines the interface for the x/staking keeper that x/pot needs. +// Used by StakingValidatorSetAdapter — not referenced directly by the Keeper struct. +type StakingKeeper interface { + // GetValidator returns the validator for the given operator address. + GetValidator(ctx context.Context, addr sdk.ValAddress) (stakingtypes.Validator, error) + + // IterateBondedValidatorsByPower iterates over bonded validators sorted by power. + IterateBondedValidatorsByPower(ctx context.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error + + // IterateValidators iterates over all validators. + IterateValidators(ctx context.Context, fn func(index int64, validator stakingtypes.ValidatorI) (stop bool)) error + + // PowerReduction returns the power reduction factor (tokens per unit of consensus power). + PowerReduction(ctx context.Context) sdkmath.Int + + // Jail sets Jailed=true on a validator, causing x/staking's EndBlocker to + // remove them from the active set (power → 0) via ValidatorUpdates. + // Jailing does NOT slash — slashing is a separate mechanism. + Jail(ctx context.Context, consAddr sdk.ConsAddress) error + + // Unjail sets Jailed=false on a validator, allowing x/staking's EndBlocker + // to re-add them to the active set if they have enough stake. + Unjail(ctx context.Context, consAddr sdk.ConsAddress) error + + // GetValidatorByConsAddr returns a validator by consensus address. + GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (stakingtypes.Validator, error) +} + +// SlashingKeeper defines the interface for the x/slashing keeper that x/pot needs. +// Used by StakingValidatorSetAdapter — not referenced directly by the Keeper struct. +type SlashingKeeper interface { + // GetValidatorSigningInfo returns the signing info for a validator by consensus address. + GetValidatorSigningInfo(ctx context.Context, address sdk.ConsAddress) (slashingtypes.ValidatorSigningInfo, error) + + // IsTombstoned returns true if a validator has been permanently removed from the validator set. + IsTombstoned(ctx context.Context, consAddr sdk.ConsAddress) bool +} + +// TokenizationKeeper defines the interface for the x/tokenization keeper that x/pot needs. +// We define a minimal interface so x/pot does not import x/tokenization's concrete types. +// +// The wiring code in app.go should create an adapter struct that implements this interface +// using the concrete x/tokenization keeper methods (GetCollectionFromStore, GetBalanceOrApplyDefault, etc.). +type TokenizationKeeper interface { + // GetCredentialBalance returns the balance of a specific token for a given address. + // collectionId and tokenId identify the credential token to check. + // Returns the balance amount (0 if not found) and any error. + GetCredentialBalance(ctx sdk.Context, collectionId uint64, tokenId uint64, address string) (uint64, error) +} diff --git a/x/pot/types/genesis.pb.go b/x/pot/types/genesis.pb.go new file mode 100644 index 00000000..3a2ccdb5 --- /dev/null +++ b/x/pot/types/genesis.pb.go @@ -0,0 +1,377 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pot/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 + +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` + ComplianceJailedValidators [][]byte `protobuf:"bytes,2,rep,name=compliance_jailed_validators,json=complianceJailedValidators,proto3" json:"compliance_jailed_validators,omitempty"` +} + +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_fc256747c6cecf15, []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 (m *GenesisState) GetComplianceJailedValidators() [][]byte { + if m != nil { + return m.ComplianceJailedValidators + } + return nil +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "pot.GenesisState") +} + +func init() { proto.RegisterFile("pot/genesis.proto", fileDescriptor_fc256747c6cecf15) } + +var fileDescriptor_fc256747c6cecf15 = []byte{ + // 234 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x2c, 0xc8, 0x2f, 0xd1, + 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2e, + 0xc8, 0x2f, 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xf3, 0xf5, 0x41, 0x2c, 0x88, 0x94, 0x94, + 0x00, 0x48, 0x75, 0x41, 0x62, 0x51, 0x62, 0x2e, 0x54, 0xb1, 0x52, 0x35, 0x17, 0x8f, 0x3b, 0x44, + 0x77, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x26, 0x17, 0x1b, 0x44, 0x5e, 0x82, 0x51, 0x81, 0x51, + 0x83, 0xdb, 0x88, 0x5b, 0xaf, 0x20, 0xbf, 0x44, 0x2f, 0x00, 0x2c, 0xe4, 0xc4, 0x72, 0xe2, 0x9e, + 0x3c, 0x43, 0x10, 0x54, 0x81, 0x90, 0x03, 0x97, 0x4c, 0x72, 0x7e, 0x6e, 0x41, 0x4e, 0x66, 0x62, + 0x5e, 0x72, 0x6a, 0x7c, 0x56, 0x62, 0x66, 0x4e, 0x6a, 0x4a, 0x7c, 0x59, 0x62, 0x4e, 0x66, 0x4a, + 0x62, 0x49, 0x7e, 0x51, 0xb1, 0x04, 0x93, 0x02, 0xb3, 0x06, 0x4f, 0x90, 0x14, 0x42, 0x8d, 0x17, + 0x58, 0x49, 0x18, 0x5c, 0x85, 0x93, 0xe7, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, + 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, + 0x44, 0xe9, 0xa7, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x27, 0x65, 0x96, + 0x24, 0x25, 0xa6, 0xa4, 0xa7, 0x16, 0x23, 0x58, 0xc9, 0x19, 0x89, 0x99, 0x79, 0xfa, 0x15, 0xfa, + 0x20, 0xef, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0xbd, 0x63, 0x0c, 0x08, 0x00, 0x00, + 0xff, 0xff, 0x75, 0xfc, 0x1f, 0xff, 0x10, 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 + if len(m.ComplianceJailedValidators) > 0 { + for iNdEx := len(m.ComplianceJailedValidators) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.ComplianceJailedValidators[iNdEx]) + copy(dAtA[i:], m.ComplianceJailedValidators[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ComplianceJailedValidators[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + { + 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)) + if len(m.ComplianceJailedValidators) > 0 { + for _, b := range m.ComplianceJailedValidators { + l = len(b) + 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 + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ComplianceJailedValidators", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ComplianceJailedValidators = append(m.ComplianceJailedValidators, make([]byte, postIndex-iNdEx)) + copy(m.ComplianceJailedValidators[len(m.ComplianceJailedValidators)-1], dAtA[iNdEx:postIndex]) + 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/pot/types/genesis_helpers.go b/x/pot/types/genesis_helpers.go new file mode 100644 index 00000000..1a6e4806 --- /dev/null +++ b/x/pot/types/genesis_helpers.go @@ -0,0 +1,13 @@ +package types + +// DefaultGenesis returns the default genesis state for x/pot. +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +// Validate performs basic validation of the genesis state. +func (gs GenesisState) Validate() error { + return gs.Params.Validate() +} diff --git a/x/pot/types/keys.go b/x/pot/types/keys.go new file mode 100644 index 00000000..fbf3265c --- /dev/null +++ b/x/pot/types/keys.go @@ -0,0 +1,44 @@ +package types + +const ( + // ModuleName defines the module name + ModuleName = "pot" + + // StoreKey defines the primary module store key (for params and compliance-jailed set) + StoreKey = ModuleName +) + +var ( + // ParamsKey is the key for storing module params + ParamsKey = []byte("p_pot") + + // ComplianceJailedPrefix is the prefix for the set of validator consensus addresses + // that x/pot has jailed for missing credentials. This lets us distinguish + // compliance-jailing from slashing-jailing so we can auto-unjail when + // credentials are regained. + // Each entry is ComplianceJailedPrefix | consAddr_bytes -> []byte{1} + ComplianceJailedPrefix = []byte("cj/") + + // SavedPowerPrefix is the prefix for persisting a validator's voting power + // before the PoA adapter disables them. When the validator is re-enabled, + // the saved power is restored. + // Each entry is SavedPowerPrefix | consAddr_bytes -> big-endian int64 + SavedPowerPrefix = []byte("sp/") +) + +// ComplianceJailedKey returns the KV store key for tracking a compliance-jailed validator. +// Uses make+copy to avoid corrupting the package-level prefix slice. +func ComplianceJailedKey(consAddr []byte) []byte { + key := make([]byte, len(ComplianceJailedPrefix)+len(consAddr)) + copy(key, ComplianceJailedPrefix) + copy(key[len(ComplianceJailedPrefix):], consAddr) + return key +} + +// SavedPowerKey returns the KV store key for a validator's saved power. +func SavedPowerKey(consAddr []byte) []byte { + key := make([]byte, len(SavedPowerPrefix)+len(consAddr)) + copy(key, SavedPowerPrefix) + copy(key[len(SavedPowerPrefix):], consAddr) + return key +} diff --git a/x/pot/types/params.pb.go b/x/pot/types/params.pb.go new file mode 100644 index 00000000..5e8ffc1f --- /dev/null +++ b/x/pot/types/params.pb.go @@ -0,0 +1,426 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pot/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 + +type Params struct { + CredentialCollectionId uint64 `protobuf:"varint,1,opt,name=credential_collection_id,json=credentialCollectionId,proto3" json:"credential_collection_id,omitempty"` + CredentialTokenId uint64 `protobuf:"varint,2,opt,name=credential_token_id,json=credentialTokenId,proto3" json:"credential_token_id,omitempty"` + MinCredentialBalance uint64 `protobuf:"varint,3,opt,name=min_credential_balance,json=minCredentialBalance,proto3" json:"min_credential_balance,omitempty"` + Mode string `protobuf:"bytes,4,opt,name=mode,proto3" json:"mode,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_a87f67103239c2e5, []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 (m *Params) GetCredentialCollectionId() uint64 { + if m != nil { + return m.CredentialCollectionId + } + return 0 +} + +func (m *Params) GetCredentialTokenId() uint64 { + if m != nil { + return m.CredentialTokenId + } + return 0 +} + +func (m *Params) GetMinCredentialBalance() uint64 { + if m != nil { + return m.MinCredentialBalance + } + return 0 +} + +func (m *Params) GetMode() string { + if m != nil { + return m.Mode + } + return "" +} + +func init() { + proto.RegisterType((*Params)(nil), "pot.Params") +} + +func init() { proto.RegisterFile("pot/params.proto", fileDescriptor_a87f67103239c2e5) } + +var fileDescriptor_a87f67103239c2e5 = []byte{ + // 249 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x4c, 0xd0, 0x31, 0x4e, 0xc3, 0x30, + 0x14, 0xc6, 0xf1, 0x98, 0x46, 0x95, 0xf0, 0x04, 0xa6, 0xaa, 0x22, 0x06, 0xab, 0x62, 0xea, 0x14, + 0x0f, 0x30, 0x30, 0xb7, 0x53, 0x36, 0x54, 0x31, 0xb1, 0x44, 0x8e, 0x6d, 0xa5, 0x16, 0xb1, 0x9f, + 0x95, 0x3c, 0x24, 0xb8, 0x05, 0x07, 0xe2, 0x00, 0x8c, 0x1d, 0x19, 0x51, 0x72, 0x91, 0x2a, 0xae, + 0xd4, 0x74, 0xfb, 0xac, 0x9f, 0xff, 0xcb, 0xa3, 0x37, 0x01, 0x50, 0x04, 0xd9, 0x4a, 0xd7, 0xe5, + 0xa1, 0x05, 0x04, 0x36, 0x0b, 0x80, 0xf7, 0x8b, 0x1a, 0x6a, 0x88, 0x6f, 0x31, 0xae, 0x13, 0x3d, + 0xfc, 0x10, 0x3a, 0x7f, 0x89, 0x7f, 0xd9, 0x33, 0xcd, 0x54, 0x6b, 0xb4, 0xf1, 0x68, 0x65, 0x53, + 0x2a, 0x68, 0x1a, 0xa3, 0xd0, 0x82, 0x2f, 0xad, 0xce, 0xc8, 0x8a, 0xac, 0xd3, 0xdd, 0x72, 0xf2, + 0xed, 0x99, 0x0b, 0xcd, 0x72, 0x7a, 0x77, 0x51, 0x22, 0xbc, 0x9b, 0x18, 0x5d, 0xc5, 0xe8, 0x76, + 0xa2, 0xd7, 0x51, 0x0a, 0xcd, 0x9e, 0xe8, 0xd2, 0x59, 0x5f, 0x5e, 0x34, 0x95, 0x6c, 0xa4, 0x57, + 0x26, 0x9b, 0xc5, 0x64, 0xe1, 0xac, 0xdf, 0x9e, 0x71, 0x73, 0x32, 0xc6, 0x68, 0xea, 0x40, 0x9b, + 0x2c, 0x5d, 0x91, 0xf5, 0xf5, 0x2e, 0xee, 0x4d, 0xf1, 0xdb, 0x73, 0x72, 0xe8, 0x39, 0xf9, 0xef, + 0x39, 0xf9, 0x1e, 0x78, 0x72, 0x18, 0x78, 0xf2, 0x37, 0xf0, 0xe4, 0x4d, 0xd4, 0x16, 0xf7, 0x1f, + 0x55, 0xae, 0xc0, 0x89, 0xca, 0x62, 0x25, 0x75, 0x6d, 0xba, 0x69, 0xa9, 0xbd, 0xb4, 0x5e, 0x7c, + 0x8a, 0xf1, 0x56, 0xf8, 0x15, 0x4c, 0x57, 0xcd, 0xe3, 0x41, 0x1e, 0x8f, 0x01, 0x00, 0x00, 0xff, + 0xff, 0x9f, 0xf5, 0x89, 0xb3, 0x3f, 0x01, 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 + if len(m.Mode) > 0 { + i -= len(m.Mode) + copy(dAtA[i:], m.Mode) + i = encodeVarintParams(dAtA, i, uint64(len(m.Mode))) + i-- + dAtA[i] = 0x22 + } + if m.MinCredentialBalance != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.MinCredentialBalance)) + i-- + dAtA[i] = 0x18 + } + if m.CredentialTokenId != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.CredentialTokenId)) + i-- + dAtA[i] = 0x10 + } + if m.CredentialCollectionId != 0 { + i = encodeVarintParams(dAtA, i, uint64(m.CredentialCollectionId)) + i-- + dAtA[i] = 0x8 + } + 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 + if m.CredentialCollectionId != 0 { + n += 1 + sovParams(uint64(m.CredentialCollectionId)) + } + if m.CredentialTokenId != 0 { + n += 1 + sovParams(uint64(m.CredentialTokenId)) + } + if m.MinCredentialBalance != 0 { + n += 1 + sovParams(uint64(m.MinCredentialBalance)) + } + l = len(m.Mode) + if l > 0 { + n += 1 + l + sovParams(uint64(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 { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CredentialCollectionId", wireType) + } + m.CredentialCollectionId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CredentialCollectionId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CredentialTokenId", wireType) + } + m.CredentialTokenId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CredentialTokenId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MinCredentialBalance", wireType) + } + m.MinCredentialBalance = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MinCredentialBalance |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Mode", 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.Mode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + 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/pot/types/params_helpers.go b/x/pot/types/params_helpers.go new file mode 100644 index 00000000..8cf3ca34 --- /dev/null +++ b/x/pot/types/params_helpers.go @@ -0,0 +1,50 @@ +package types + +import "fmt" + +const ( + // ModeStakedMultiplier means voting power = staked amount if credential balance > 0, else 0. + // Full PoS economics — credential is a binary compliance gate. + ModeStakedMultiplier = "staked_multiplier" + + // ModeEqual means voting power = 1 if credential balance >= MinCredentialBalance, else 0. + // Democratic consensus — all credentialed validators have equal power. + // Validators still self-delegate (security deposit for slashing). + // NOTE: Not yet implemented — reserved for future use. + ModeEqual = "equal" + + // ModeCredentialWeighted means voting power = credential token balance if >= MinCredentialBalance, else 0. + // Power is proportional to credential token balance, decoupled from staked amount. + // Validators still self-delegate (security deposit for slashing) but power comes from credential balance. + // NOTE: Not yet implemented — reserved for future use. + ModeCredentialWeighted = "credential_weighted" +) + +// DefaultParams returns a default set of parameters with the module effectively disabled +// (collection ID 0 means no credential check is active). +// DefaultParams returns a default set of parameters with the module effectively disabled +// (collection ID 0 means no credential check is active). +func DefaultParams() Params { + return Params{ + CredentialCollectionId: 0, + CredentialTokenId: 0, + MinCredentialBalance: 1, + Mode: ModeStakedMultiplier, + } +} + +// Validate performs basic validation of params. +func (p Params) Validate() error { + if p.Mode != ModeStakedMultiplier { + return fmt.Errorf("invalid mode %q: only %q is currently supported", p.Mode, ModeStakedMultiplier) + } + if p.CredentialCollectionId > 0 && p.MinCredentialBalance == 0 { + return fmt.Errorf("min_credential_balance must be > 0 when module is enabled") + } + return nil +} + +// IsEnabled returns true if the module has a non-zero credential collection configured. +func (p Params) IsEnabled() bool { + return p.CredentialCollectionId > 0 +} diff --git a/x/pot/types/params_test.go b/x/pot/types/params_test.go new file mode 100644 index 00000000..85045ded --- /dev/null +++ b/x/pot/types/params_test.go @@ -0,0 +1,113 @@ +package types_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/bitbadges/bitbadgeschain/x/pot/types" +) + +func TestDefaultParams(t *testing.T) { + p := types.DefaultParams() + require.Equal(t, uint64(0), p.CredentialCollectionId) + require.Equal(t, uint64(0), p.CredentialTokenId) + require.Equal(t, uint64(1), p.MinCredentialBalance) + require.Equal(t, types.ModeStakedMultiplier, p.Mode) +} + +func TestParamsValidate_StakedMultiplier(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + } + require.NoError(t, p.Validate()) +} + +func TestParamsValidate_Equal_Rejected(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeEqual, + } + err := p.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "only \"staked_multiplier\" is currently supported") +} + +func TestParamsValidate_CredentialWeighted_Rejected(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeCredentialWeighted, + } + err := p.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "only \"staked_multiplier\" is currently supported") +} + +func TestParamsValidate_InvalidMode(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: "invalid_mode", + } + err := p.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "invalid mode") +} + +func TestParamsValidate_MinCredentialBalanceZero(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 0, + Mode: types.ModeStakedMultiplier, + } + err := p.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "min_credential_balance must be > 0") +} + +func TestIsEnabled_CollectionIdZero(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 0, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + } + require.False(t, p.IsEnabled()) +} + +func TestIsEnabled_CollectionIdPositive(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 42, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: types.ModeStakedMultiplier, + } + require.True(t, p.IsEnabled()) +} + +func TestParamsValidate_DefaultParamsAreValid(t *testing.T) { + // DefaultParams has MinCredentialBalance=1, Mode=staked_multiplier, so it should be valid. + p := types.DefaultParams() + require.NoError(t, p.Validate()) +} + +func TestParamsValidate_EmptyMode(t *testing.T) { + p := types.Params{ + CredentialCollectionId: 1, + CredentialTokenId: 1, + MinCredentialBalance: 1, + Mode: "", + } + err := p.Validate() + require.Error(t, err) + require.Contains(t, err.Error(), "invalid mode") +} diff --git a/x/pot/types/query.pb.go b/x/pot/types/query.pb.go new file mode 100644 index 00000000..e15f777c --- /dev/null +++ b/x/pot/types/query.pb.go @@ -0,0 +1,530 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pot/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "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 + +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_87ae288ca1a6f1ac, []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 + +type QueryParamsResponse struct { + 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_87ae288ca1a6f1ac, []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), "pot.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "pot.QueryParamsResponse") +} + +func init() { proto.RegisterFile("pot/query.proto", fileDescriptor_87ae288ca1a6f1ac) } + +var fileDescriptor_87ae288ca1a6f1ac = []byte{ + // 262 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0xc8, 0x2f, 0xd1, + 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2e, 0xc8, 0x2f, + 0x91, 0x12, 0x49, 0xcf, 0x4f, 0xcf, 0x07, 0xf3, 0xf5, 0x41, 0x2c, 0x88, 0x94, 0x94, 0x4c, 0x7a, + 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x7e, 0x62, 0x41, 0xa6, 0x7e, 0x62, 0x5e, 0x5e, 0x7e, 0x49, 0x62, + 0x49, 0x66, 0x7e, 0x5e, 0x31, 0x54, 0x56, 0x00, 0x64, 0x52, 0x41, 0x62, 0x51, 0x62, 0x2e, 0x54, + 0x44, 0x49, 0x84, 0x4b, 0x28, 0x10, 0x64, 0x72, 0x00, 0x58, 0x30, 0x28, 0xb5, 0xb0, 0x34, 0xb5, + 0xb8, 0x44, 0xc9, 0x81, 0x4b, 0x18, 0x45, 0xb4, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0x48, 0x93, + 0x8b, 0x0d, 0xa2, 0x59, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x88, 0x5b, 0xaf, 0x20, 0xbf, 0x44, + 0x0f, 0xa2, 0xc8, 0x89, 0xe5, 0xc4, 0x3d, 0x79, 0x86, 0x20, 0xa8, 0x02, 0xa3, 0x48, 0x2e, 0x56, + 0xb0, 0x09, 0x42, 0x01, 0x5c, 0x6c, 0x10, 0x05, 0x42, 0xe2, 0x60, 0xd5, 0x98, 0xb6, 0x49, 0x49, + 0x60, 0x4a, 0x40, 0x2c, 0x54, 0x12, 0x6e, 0xba, 0xfc, 0x64, 0x32, 0x13, 0xaf, 0x10, 0xb7, 0x3e, + 0xc2, 0xe1, 0x4e, 0x9e, 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, 0xa5, 0x9f, + 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x9f, 0x94, 0x59, 0x92, 0x94, 0x98, + 0x92, 0x9e, 0x5a, 0x8c, 0x60, 0x25, 0x67, 0x24, 0x66, 0xe6, 0xe9, 0x57, 0x80, 0xcd, 0x2a, 0xa9, + 0x2c, 0x48, 0x2d, 0x4e, 0x62, 0x03, 0x07, 0x82, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xee, 0xaf, + 0x8b, 0xb1, 0x62, 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 { + 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, "/pot.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 { + 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: "/pot.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 = _Query_serviceDesc +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pot.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "pot/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/pot/types/query.pb.gw.go b/x/pot/types/query.pb.gw.go new file mode 100644 index 00000000..2c009d85 --- /dev/null +++ b/x/pot/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: pot/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}, []string{"pot", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/pot/types/tx.pb.go b/x/pot/types/tx.pb.go new file mode 100644 index 00000000..24ebb644 --- /dev/null +++ b/x/pot/types/tx.pb.go @@ -0,0 +1,587 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: pot/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + 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 + +type MsgUpdateParams struct { + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_d689f918649bf73b, []int{0} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_d689f918649bf73b, []int{1} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.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 *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgUpdateParams)(nil), "pot.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "pot.MsgUpdateParamsResponse") +} + +func init() { proto.RegisterFile("pot/tx.proto", fileDescriptor_d689f918649bf73b) } + +var fileDescriptor_d689f918649bf73b = []byte{ + // 330 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0xc8, 0x2f, 0xd1, + 0x2f, 0xa9, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2e, 0xc8, 0x2f, 0x91, 0x12, 0x4c, + 0xcc, 0xcd, 0xcc, 0xcb, 0xd7, 0x07, 0x93, 0x10, 0x71, 0x29, 0xf1, 0xe4, 0xfc, 0xe2, 0xdc, 0xfc, + 0x62, 0xfd, 0xdc, 0xe2, 0x74, 0xfd, 0x32, 0x43, 0x10, 0x05, 0x95, 0x90, 0x84, 0x48, 0xc4, 0x83, + 0x79, 0xfa, 0x10, 0x0e, 0x54, 0x4a, 0x24, 0x3d, 0x3f, 0x3d, 0x1f, 0x22, 0x0e, 0x62, 0x41, 0x45, + 0x05, 0x40, 0xf6, 0x15, 0x24, 0x16, 0x25, 0xe6, 0x42, 0xd5, 0x29, 0xcd, 0x61, 0xe4, 0xe2, 0xf7, + 0x2d, 0x4e, 0x0f, 0x2d, 0x48, 0x49, 0x2c, 0x49, 0x0d, 0x00, 0xcb, 0x08, 0x99, 0x71, 0x71, 0x26, + 0x96, 0x96, 0x64, 0xe4, 0x17, 0x65, 0x96, 0x54, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70, 0x3a, 0x49, + 0x5c, 0xda, 0xa2, 0x2b, 0x02, 0xb5, 0xc0, 0x31, 0x25, 0xa5, 0x28, 0xb5, 0xb8, 0x38, 0xb8, 0xa4, + 0x28, 0x33, 0x2f, 0x3d, 0x08, 0xa1, 0x54, 0x48, 0x93, 0x8b, 0x0d, 0x62, 0xb6, 0x04, 0x93, 0x02, + 0xa3, 0x06, 0xb7, 0x11, 0xb7, 0x5e, 0x41, 0x7e, 0x89, 0x1e, 0xc4, 0x50, 0x27, 0x96, 0x13, 0xf7, + 0xe4, 0x19, 0x82, 0xa0, 0x0a, 0xac, 0xd4, 0x9a, 0x9e, 0x6f, 0xd0, 0x42, 0x68, 0xed, 0x7a, 0xbe, + 0x41, 0x4b, 0x18, 0xe4, 0x36, 0x34, 0xa7, 0x28, 0x49, 0x72, 0x89, 0xa3, 0x09, 0x05, 0xa5, 0x16, + 0x17, 0xe4, 0xe7, 0x15, 0xa7, 0x1a, 0x05, 0x70, 0x31, 0xfb, 0x16, 0xa7, 0x0b, 0x39, 0x71, 0xf1, + 0xa0, 0x38, 0x5e, 0x04, 0x6c, 0x29, 0x9a, 0x26, 0x29, 0x19, 0x6c, 0xa2, 0x30, 0xa3, 0xa4, 0x58, + 0x1b, 0x9e, 0x6f, 0xd0, 0x62, 0x74, 0xf2, 0x3c, 0xf1, 0x48, 0x8e, 0xf1, 0xc2, 0x23, 0x39, 0xc6, + 0x07, 0x8f, 0xe4, 0x18, 0x27, 0x3c, 0x96, 0x63, 0xb8, 0xf0, 0x58, 0x8e, 0xe1, 0xc6, 0x63, 0x39, + 0x86, 0x28, 0xfd, 0xf4, 0xcc, 0x92, 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0xfd, 0xa4, 0xcc, + 0x92, 0xa4, 0xc4, 0x94, 0xf4, 0xd4, 0x62, 0x04, 0x2b, 0x39, 0x23, 0x31, 0x33, 0x4f, 0xbf, 0x42, + 0x1f, 0x1c, 0x9b, 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0xd0, 0x35, 0x06, 0x04, 0x00, 0x00, + 0xff, 0xff, 0xb2, 0xcd, 0x4e, 0x78, 0xe1, 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 + +// 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 { + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/pot.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/pot.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var Msg_serviceDesc = _Msg_serviceDesc +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "pot.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "pot/tx.proto", +} + +func (m *MsgUpdateParams) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgUpdateParams) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +)