Skip to content

Commit

Permalink
chore(pubkey): add proving schemes state and add endblock logic for c…
Browse files Browse the repository at this point in the history
…hecking status
  • Loading branch information
hacheigriega committed Nov 29, 2024
1 parent 100951e commit dc5f3da
Show file tree
Hide file tree
Showing 16 changed files with 1,048 additions and 106 deletions.
8 changes: 8 additions & 0 deletions proto/sedachain/pubkey/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ option go_package = "github.com/sedaprotocol/seda-chain/x/pubkey/types";
message GenesisState {
repeated ValidatorPubKeys validator_pub_keys = 1
[ (gogoproto.nullable) = false ];
repeated ProvingScheme proving_schemes = 2
[ (gogoproto.nullable) = false ];
}

// ValidatorPubKeys defines a validator's list of registered public keys
Expand All @@ -20,3 +22,9 @@ message ValidatorPubKeys {
[ (cosmos_proto.scalar) = "cosmos.ValidatorAddressString" ];
repeated IndexedPubKey indexed_pub_keys = 2 [ (gogoproto.nullable) = false ];
}

// ProvingScheme defines the status of a proving scheme.
message ProvingScheme {
uint32 index = 1;
bool is_enabled = 2;
}
25 changes: 21 additions & 4 deletions proto/sedachain/pubkey/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,34 @@ service Query {
option (google.api.http).get =
"/seda-chain/pubkey/validator_keys/{validator_addr}";
}

// ProvingSchemes returns the statuses of the SEDA proving schemes.
rpc ProvingSchemes(QueryProvingSchemesRequest)
returns (QueryProvingSchemesResponse) {
option (google.api.http).get =
"/seda-chain/pubkey/proving_schemes";
}
}

// QueryValidatorKeysRequest is request type for the Query/ValidatorKeys RPC
// method.
// QueryValidatorKeysRequest is request type for the Query/ValidatorKeys
// RPC method.
message QueryValidatorKeysRequest {
string validator_addr = 1
[ (cosmos_proto.scalar) = "cosmos.ValidatorAddressString" ];
}

// QueryValidatorKeysResponse is response type for the Query/ValidatorKeys RPC
// method.
// QueryValidatorKeysResponse is response type for the Query/ValidatorKeys
// RPC method.
message QueryValidatorKeysResponse {
ValidatorPubKeys validator_pub_keys = 1 [ (gogoproto.nullable) = false ];
}

// QueryProvingSchemesRequest is request type for the Query/ProvingSchemes
// RPC method.
message QueryProvingSchemesRequest {}

// QueryProvingSchemesResponse is response type for the Query/ProvingSchemes
// RPC method.
message QueryProvingSchemesResponse {
repeated ProvingScheme proving_schemes = 1 [ (gogoproto.nullable) = false ];
}
1 change: 0 additions & 1 deletion x/batching/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
abci "github.com/cometbft/cometbft/abci/types"

"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

Expand Down
27 changes: 27 additions & 0 deletions x/pubkey/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func GetQueryCmd() *cobra.Command {

cmd.AddCommand(
GetCmdValidatorKeys(),
GetProvingSchemes(),
)
return cmd
}
Expand Down Expand Up @@ -54,3 +55,29 @@ func GetCmdValidatorKeys() *cobra.Command {
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

// GetProvingSchemes returns the command for querying statuses of the
// SEDA proving schemes.
func GetProvingSchemes() *cobra.Command {
cmd := &cobra.Command{
Use: "proving-schemes",
Short: "Query statuses of the SEDA proving schemes",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {

Check warning on line 66 in x/pubkey/client/cli/query.go

View workflow job for this annotation

GitHub Actions / golangci

unused-parameter: parameter 'args' seems to be unused, consider removing or renaming it as _ (revive)
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.ProvingSchemes(cmd.Context(), &types.QueryProvingSchemesRequest{})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
return cmd
}
63 changes: 63 additions & 0 deletions x/pubkey/keeper/endblock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package keeper

import (
"errors"

"cosmossdk.io/collections"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/sedaprotocol/seda-chain/app/utils"
)

func (k Keeper) EndBlock(ctx sdk.Context) (err error) {
// Use defer to prevent returning an error, which would cause
// the chain to halt.
defer func() {
// Handle a panic.
if r := recover(); r != nil {
k.Logger(ctx).Error("recovered from panic in pubkey end block", "err", r)
}
// Handle an error.
if err != nil {
k.Logger(ctx).Error("error in pubkey end block", "err", err)
}
err = nil
}()

totalPower, err := k.stakingKeeper.GetLastTotalPower(ctx)
if err != nil {
return err
}

// If the sum of the voting power has reached (2/3 + 1), enable
// secp256k1 proving scheme.
var powerSum uint64
err = k.stakingKeeper.IterateLastValidatorPowers(ctx, func(valAddr sdk.ValAddress, power int64) (stop bool) {
_, err := k.GetValidatorKeyAtIndex(ctx, valAddr, utils.SEDAKeyIndexSecp256k1)
if err != nil {
if errors.Is(err, collections.ErrNotFound) {
return false
} else {

Check warning on line 41 in x/pubkey/keeper/endblock.go

View workflow job for this annotation

GitHub Actions / golangci

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
panic(err)
}
} else {
powerSum += uint64(power)
}
return false
})
if err != nil {
return err
}

if requiredPower := ((totalPower.Int64() * 4) / 5) + 1; powerSum >= uint64(requiredPower) {
err = k.EnableProvingScheme(ctx, utils.SEDAKeyIndexSecp256k1)
if err != nil {
return err
}
// TODO: Jail validators (active and inactive) without required
// public keys.
}

return
}
40 changes: 11 additions & 29 deletions x/pubkey/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package keeper

import (
"bytes"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/sedaprotocol/seda-chain/app/utils"
Expand All @@ -23,41 +21,25 @@ func (k Keeper) InitGenesis(ctx sdk.Context, data types.GenesisState) {
}
}
}
for _, scheme := range data.ProvingSchemes {
err := k.SetProvingScheme(ctx, utils.SEDAKeyIndex(scheme.Index), scheme.IsEnabled)
if err != nil {
panic(err)
}
}
}

// ExportGenesis extracts all data from store to genesis state.
func (k Keeper) ExportGenesis(ctx sdk.Context) types.GenesisState {
var gs types.GenesisState

itr, err := k.pubKeys.Iterate(ctx, nil)
var err error
gs.ValidatorPubKeys, err = k.GetAllValidatorPubKeys(ctx)
if err != nil {
panic(err)
}
defer itr.Close()

var currentVal []byte
for ; itr.Valid(); itr.Next() {
kv, err := itr.KeyValue()
if err != nil {
panic(err)
}

// Skip if the validator has already been processed.
if bytes.Equal(kv.Key.K1(), currentVal) {
continue
}
currentVal = kv.Key.K1()

valAddr, err := k.validatorAddressCodec.BytesToString(kv.Key.K1())
if err != nil {
panic(err)
}
res, err := k.GetValidatorKeys(ctx, valAddr)
if err != nil {
panic(err)
}

gs.ValidatorPubKeys = append(gs.ValidatorPubKeys, res)
gs.ProvingSchemes, err = k.GetAllProvingSchemes(ctx)
if err != nil {
panic(err)
}
return gs
}
11 changes: 11 additions & 0 deletions x/pubkey/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/sedaprotocol/seda-chain/x/pubkey/types"
)

Expand All @@ -19,3 +20,13 @@ func (q Querier) ValidatorKeys(ctx context.Context, req *types.QueryValidatorKey
}
return &types.QueryValidatorKeysResponse{ValidatorPubKeys: result}, nil
}

func (q Querier) ProvingSchemes(ctx context.Context, req *types.QueryProvingSchemesRequest) (*types.QueryProvingSchemesResponse, error) {

Check warning on line 24 in x/pubkey/keeper/grpc_query.go

View workflow job for this annotation

GitHub Actions / golangci

unused-parameter: parameter 'req' seems to be unused, consider removing or renaming it as _ (revive)
schemes, err := q.GetAllProvingSchemes(sdk.UnwrapSDKContext(ctx))
if err != nil {
return nil, err
}
return &types.QueryProvingSchemesResponse{
ProvingSchemes: schemes,
}, nil
}
93 changes: 91 additions & 2 deletions x/pubkey/keeper/keeper.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package keeper

import (
"bytes"
"context"
"fmt"

"cosmossdk.io/collections"
"cosmossdk.io/core/address"
storetypes "cosmossdk.io/core/store"
"cosmossdk.io/log"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand All @@ -18,8 +21,9 @@ type Keeper struct {
stakingKeeper types.StakingKeeper
validatorAddressCodec address.Codec

Schema collections.Schema
pubKeys collections.Map[collections.Pair[[]byte, uint32], []byte]
Schema collections.Schema
pubKeys collections.Map[collections.Pair[[]byte, uint32], []byte]
provingSchemes collections.Map[uint32, bool]
}

func NewKeeper(storeService storetypes.KVStoreService, sk types.StakingKeeper, validatorAddressCodec address.Codec) *Keeper {
Expand All @@ -32,6 +36,7 @@ func NewKeeper(storeService storetypes.KVStoreService, sk types.StakingKeeper, v
stakingKeeper: sk,
validatorAddressCodec: validatorAddressCodec,
pubKeys: collections.NewMap(sb, types.PubKeysPrefix, "pubkeys", collections.PairKeyCodec(collections.BytesKey, collections.Uint32Key), collections.BytesValue),
provingSchemes: collections.NewMap(sb, types.ProvingSchemesPrefix, "proving_schemes", collections.Uint32Key, collections.BoolValue),
}

schema, err := sb.Build()
Expand All @@ -58,6 +63,7 @@ func (k Keeper) GetValidatorKeyAtIndex(ctx context.Context, validatorAddr sdk.Va
return pubKey, nil
}

// GetValidatorKeys returns all public keys of a given validator.
func (k Keeper) GetValidatorKeys(ctx context.Context, validatorAddr string) (result types.ValidatorPubKeys, err error) {
valAddr, err := k.validatorAddressCodec.StringToBytes(validatorAddr)
if err != nil {
Expand Down Expand Up @@ -88,3 +94,86 @@ func (k Keeper) GetValidatorKeys(ctx context.Context, validatorAddr string) (res
}
return result, nil
}

// GetAllValidatorPubKeys returns all validator public keys in the store.
func (k Keeper) GetAllValidatorPubKeys(ctx context.Context) ([]types.ValidatorPubKeys, error) {
var valPubKeys []types.ValidatorPubKeys

itr, err := k.pubKeys.Iterate(ctx, nil)
if err != nil {
return nil, err
}
defer itr.Close()

var currentVal []byte
for ; itr.Valid(); itr.Next() {
kv, err := itr.KeyValue()
if err != nil {
return nil, err
}

// Skip if the validator has already been processed.
if bytes.Equal(kv.Key.K1(), currentVal) {
continue
}
currentVal = kv.Key.K1()

valAddr, err := k.validatorAddressCodec.BytesToString(kv.Key.K1())
if err != nil {
return nil, err
}
res, err := k.GetValidatorKeys(ctx, valAddr)
if err != nil {
return nil, err
}

valPubKeys = append(valPubKeys, res)
}
return valPubKeys, err
}

func (k Keeper) SetProvingScheme(ctx context.Context, index utils.SEDAKeyIndex, isEnabled bool) error {
err := k.provingSchemes.Set(ctx, uint32(index), isEnabled)
if err != nil {
return err
}
return nil
}

func (k Keeper) EnableProvingScheme(ctx context.Context, index utils.SEDAKeyIndex) error {
err := k.provingSchemes.Set(ctx, uint32(index), true)
if err != nil {
return err
}
return nil
}

func (k Keeper) GetAllProvingSchemes(ctx sdk.Context) ([]types.ProvingScheme, error) {
itr, err := k.provingSchemes.Iterate(ctx, nil)
if err != nil {
return nil, err
}
defer itr.Close()

var schemes []types.ProvingScheme
for ; itr.Valid(); itr.Next() {
kv, err := itr.KeyValue()
if err != nil {
return nil, err
}

isEnabled, err := k.provingSchemes.Get(ctx, kv.Key)
if err != nil {
return nil, err
}
schemes = append(schemes, types.ProvingScheme{
Index: kv.Key,
IsEnabled: isEnabled,
})
}
return schemes, nil
}

func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}
Loading

0 comments on commit dc5f3da

Please sign in to comment.