Skip to content

Commit

Permalink
refactor(hub-genesis): refactoring x/hub-genesis state (#374)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtsitrin authored Apr 11, 2024
1 parent 807717b commit a0a367f
Show file tree
Hide file tree
Showing 34 changed files with 872 additions and 946 deletions.
4 changes: 2 additions & 2 deletions proto/hub-genesis/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "hub-genesis/params.proto";
import "hub-genesis/hub.proto";
import "hub-genesis/state.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// GenesisState defines the hub-genesis module's genesis state.
message GenesisState {
// params defines all the parameters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];
Hub hub = 2 [ (gogoproto.nullable) = false ];
State state = 2 [(gogoproto.nullable) = false];
}
12 changes: 0 additions & 12 deletions proto/hub-genesis/hub.proto

This file was deleted.

6 changes: 3 additions & 3 deletions proto/hub-genesis/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import "gogoproto/gogo.proto";
message Params {
option (gogoproto.goproto_stringer) = false;

// genesis_triggerer_whitelist is a list of the
// genesis_triggerer_allowlist is a list of the
// accounts that are allowed to trigger a genesis event on the rollapp.
// In the case of an empty list, there are no restrictions
repeated GenesisTriggererParams genesis_triggerer_whitelist = 1 [
(gogoproto.moretags) = "yaml:\"genesis_triggerer_whitelist\"",
repeated GenesisTriggererParams genesis_triggerer_allowlist = 1 [
(gogoproto.moretags) = "yaml:\"genesis_triggerer_allowlist\"",
(gogoproto.nullable) = false
];
}
Expand Down
30 changes: 15 additions & 15 deletions proto/hub-genesis/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,23 @@ package rollapp.hub_genesis;
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";
import "hub-genesis/params.proto";
import "hub-genesis/hub.proto";
import "hub-genesis/state.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// Query provides defines the gRPC querier service.
service Query {
// Hub returns the hub information
rpc Hub(QueryGetHubRequest) returns (QueryGetHubResponse) {
option (google.api.http).get =
"/dymensionxyz/dymension-rdk/hub-genesis/hub/{hub_id}";
}
// Params returns the total set of hub-genesis parameters.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get =
"/dymensionxyz/dymension-rdk/hub-genesis/params";
}
}

message QueryGetHubRequest {
// id is the id of the hub
string hub_id = 1;
}

message QueryGetHubResponse {
// hub is the hub information
Hub hub = 1 [ (gogoproto.nullable) = false ];
// State returns the state of the genesis event.
rpc State(QueryStateRequest) returns (QueryStateResponse) {
option (google.api.http).get =
"/dymensionxyz/dymension-rdk/hub-genesis/state";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
Expand All @@ -40,3 +31,12 @@ message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1 [ (gogoproto.nullable) = false ];
}

// QueryStateRequest is the request type for the Query/State RPC method.
message QueryStateRequest {}

// QueryStateResponse is the response type for the Query/State RPC method.
message QueryStateResponse {
// state holds the state of the genesis event
State state = 1 [(gogoproto.nullable) = false];
}
20 changes: 20 additions & 0 deletions proto/hub-genesis/state.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
syntax = "proto3";
package rollapp.hub_genesis;

import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";

option go_package = "github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types";

// State holds the state of the genesis event
message State {
// is_locked is a boolean that indicates if the genesis event has occured
bool is_locked = 1;

// genesis_tokens is the list of tokens that are expected to be locked on genesis event
repeated cosmos.base.v1beta1.Coin genesis_tokens = 2 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
];

}
2 changes: 1 addition & 1 deletion proto/hub-genesis/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ message MsgHubGenesisEvent {
string address = 1;
// channel_id is the hub channel id on the rollapp
string channel_id = 2;
// hub_id is the hub id
// hub_id is the hub's chainid
string hub_id = 3;
}

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

hubGenQueryCmd.AddCommand(
GetCmdQueryParams(),
GetCmdQueryState(),
)

return hubGenQueryCmd
Expand Down Expand Up @@ -56,3 +57,32 @@ func GetCmdQueryParams() *cobra.Command {

return cmd
}

// GetCmdQueryState implements a command to return the current hub-genesis
// state.
func GetCmdQueryState() *cobra.Command {
cmd := &cobra.Command{
Use: "state",
Short: "Query the current hub-genesis state",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

state := &types.QueryStateRequest{}
res, err := queryClient.State(context.Background(), state)
if err != nil {
return err
}

return clientCtx.PrintProto(&res.State)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
31 changes: 0 additions & 31 deletions x/hub-genesis/genesis.go

This file was deleted.

36 changes: 36 additions & 0 deletions x/hub-genesis/keeper/genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"
)

// InitGenesis new hub-genesis genesis.
func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) {
k.SetParams(ctx, genState.Params)

modAddress := k.accountKeeper.GetModuleAddress(types.ModuleName)
if !k.accountKeeper.HasAccount(ctx, modAddress) {
k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
}

// if tokens provided and waiting to be locked, verify the balance
if !genState.State.IsLocked && !genState.State.GenesisTokens.IsZero() {
// get spendable coins in the module account
spendable := k.bankKeeper.SpendableCoins(ctx, modAddress)
// we expect the genesis balance of the module account to be equal to required genesis tokens
if !spendable.IsEqual(genState.State.GenesisTokens) {
panic(types.ErrWrongGenesisBalance)
}
}
k.SetState(ctx, genState.State)
}

// ExportGenesis returns a GenesisState for a given context and keeper.
func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState {
genesis := types.DefaultGenesisState()
genesis.Params = k.GetParams(ctx)
genesis.State = k.GetState(ctx)

return genesis
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
package hub_genesis_test
package keeper_test

import (
"testing"

testkeepers "github.com/dymensionxyz/dymension-rdk/testutil/keepers"
"github.com/dymensionxyz/dymension-rdk/testutil/nullify"
"github.com/dymensionxyz/dymension-rdk/testutil/utils"
hub_genesis "github.com/dymensionxyz/dymension-rdk/x/hub-genesis"
"github.com/dymensionxyz/dymension-rdk/x/hub-genesis/types"
"github.com/stretchr/testify/require"
)

func TestGenesis(t *testing.T) {
genesisState := &types.GenesisState{}

app := utils.Setup(t, false)
// HubGenesis Keeper
k, ctx := testkeepers.NewTestHubGenesisKeeperFromApp(app)

ak := app.AccountKeeper

hub_genesis.InitGenesis(ctx, *k, ak, genesisState)
got := hub_genesis.ExportGenesis(ctx, *k)
k.InitGenesis(ctx, genesisState)
got := k.ExportGenesis(ctx)
require.NotNil(t, got)

nullify.Fill(&genesisState)
Expand Down
9 changes: 2 additions & 7 deletions x/hub-genesis/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,7 @@ func (q Querier) Params(c context.Context, _ *types.QueryParamsRequest) (*types.
return &types.QueryParamsResponse{Params: params}, nil
}

func (q Querier) Hub(goCtx context.Context, request *types.QueryGetHubRequest) (*types.QueryGetHubResponse, error) {
func (q Querier) State(goCtx context.Context, request *types.QueryStateRequest) (*types.QueryStateResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
hub, found := q.Keeper.GetHub(ctx, request.HubId)
if !found {
return nil, types.ErrUnknownHubID
}

return &types.QueryGetHubResponse{Hub: hub}, nil
return &types.QueryStateResponse{State: q.Keeper.GetState(ctx)}, nil
}
34 changes: 0 additions & 34 deletions x/hub-genesis/keeper/hub.go

This file was deleted.

18 changes: 6 additions & 12 deletions x/hub-genesis/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,22 +55,16 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
}

// lock coins by sending them to an escrow address
func (k Keeper) lockRollappGenesisTokens(ctx sdk.Context, sourceChannel string) error {
account := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)

func (k Keeper) lockRollappGenesisTokens(ctx sdk.Context, sourceChannel string, tokens sdk.Coins) error {
// get spendable coins in the module account
account := k.accountKeeper.GetModuleAccount(ctx, types.ModuleName)
spendable := k.bankKeeper.SpendableCoins(ctx, account.GetAddress())

// send coins to the escrow address
if spendable.Empty() {
return types.ErrGenesisNoCoinsOnModuleAcc
// validate it's enough for the required tokens
if !spendable.IsAllGTE(tokens) {
return types.ErrGenesisInsufficientBalance
}

escrowAddress := ibctypes.GetEscrowAddress("transfer", sourceChannel)

if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, escrowAddress, spendable); err != nil {
return fmt.Errorf("failed to lock coins: %w", err)
}

return nil
return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, escrowAddress, tokens)
}
26 changes: 12 additions & 14 deletions x/hub-genesis/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,40 +26,38 @@ var _ types.MsgServer = msgServer{}
func (m msgServer) TriggerGenesisEvent(goCtx context.Context, msg *types.MsgHubGenesisEvent) (*types.MsgHubGenesisEventResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

// Get the sender and validate they are in the whitelist
if !m.IsAddressInGenesisTriggererWhiteList(ctx, msg.Address) {
// Get the sender and validate they are in the Allowlist
if !m.IsAddressInGenesisTriggererAllowList(ctx, msg.Address) {
return nil, sdkerrors.ErrUnauthorized
}

_, clientState, err := m.channelKeeper.GetChannelClientState(ctx, "transfer", msg.ChannelId)
if err != nil {
return nil, errorsmod.Wrapf(types.ErrInvalidGenesisChannelId, "failed to get client state for channel %s", msg.ChannelId)
return nil, errorsmod.Wrapf(types.ErrFailedGetClientState, "failed to get client state for channel %s: %v", msg.ChannelId, err)
}

tmClientState, ok := clientState.(*tenderminttypes.ClientState)
if !ok {
return nil, errorsmod.Wrapf(types.ErrInvalidGenesisChannelId, "expected tendermint client state, got %T", clientState)
return nil, errorsmod.Wrapf(types.ErrFailedGetClientState, "expected tendermint client state, got %T", clientState)
}

if tmClientState.GetChainID() != msg.HubId {
return nil, errorsmod.Wrapf(types.ErrInvalidGenesisChainId, "channel %s is connected to chain ID %s, expected %s",
msg.ChannelId, tmClientState.GetChainID(), msg.HubId)
return nil, errorsmod.Wrapf(types.ErrChainIDMismatch, "channel %s is connected to chain ID %s",
msg.ChannelId, tmClientState.GetChainID())
}

// if the hub is found, the genesis event was already triggered
_, found := m.GetHub(ctx, msg.HubId)
if found {
// check if genesis event was already triggered
state := m.GetState(ctx)
if state.IsLocked {
return nil, types.ErrGenesisEventAlreadyTriggered
}

hub := types.NewHub(msg.HubId, msg.ChannelId)

if err := m.lockRollappGenesisTokens(ctx, hub.ChannelId); err != nil {
if err := m.lockRollappGenesisTokens(ctx, msg.ChannelId, state.GenesisTokens); err != nil {
return nil, errorsmod.Wrapf(types.ErrLockingGenesisTokens, "failed to lock tokens: %v", err)
}

// we save the hub in order to prevent the genesis event from being triggered again
m.SetHub(ctx, hub)
state.IsLocked = true
m.SetState(ctx, state)

return &types.MsgHubGenesisEventResponse{}, nil
}
Loading

0 comments on commit a0a367f

Please sign in to comment.