Skip to content

Commit

Permalink
feat: gov proposal for rollapp fraud event (#622)
Browse files Browse the repository at this point in the history
  • Loading branch information
mtsitrin authored Mar 5, 2024
1 parent d447bab commit bd0aa22
Show file tree
Hide file tree
Showing 26 changed files with 943 additions and 45 deletions.
6 changes: 5 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ import (
ante "github.com/dymensionxyz/dymension/v3/app/ante"
appparams "github.com/dymensionxyz/dymension/v3/app/params"
rollappmodule "github.com/dymensionxyz/dymension/v3/x/rollapp"
rollappmoduleclient "github.com/dymensionxyz/dymension/v3/x/rollapp/client"
rollappmodulekeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper"
rollappmoduletypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types"

Expand Down Expand Up @@ -202,6 +203,7 @@ func getGovProposalHandlers() []govclient.ProposalHandler {
streamermoduleclient.TerminateStreamHandler,
streamermoduleclient.ReplaceStreamHandler,
streamermoduleclient.UpdateStreamHandler,
rollappmoduleclient.SubmitFraudHandler,
)

return govProposalHandlers
Expand Down Expand Up @@ -570,6 +572,7 @@ func New(
keys[rollappmoduletypes.StoreKey],
keys[rollappmoduletypes.MemStoreKey],
app.GetSubspace(rollappmoduletypes.ModuleName),
app.IBCKeeper.ClientKeeper,
)

app.SequencerKeeper = *sequencermodulekeeper.NewKeeper(
Expand Down Expand Up @@ -668,7 +671,8 @@ func New(
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper)).
AddRoute(streamermoduletypes.RouterKey, streamermodule.NewStreamerProposalHandler(app.StreamerKeeper))
AddRoute(streamermoduletypes.RouterKey, streamermodule.NewStreamerProposalHandler(app.StreamerKeeper)).
AddRoute(rollappmoduletypes.RouterKey, rollappmodule.NewRollappProposalHandler(&app.RollappKeeper))

// Create Transfer Keepers
app.TransferKeeper = ibctransferkeeper.NewKeeper(
Expand Down
26 changes: 26 additions & 0 deletions proto/dymension/rollapp/proposal.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
syntax = "proto3";
package dymensionxyz.dymension.rollapp;


import "gogoproto/gogo.proto";

option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types";


message SubmitFraudProposal {
option (gogoproto.equal) = true;
option (gogoproto.goproto_getters) = false;
option (gogoproto.goproto_stringer) = false;

string title = 1;
string description = 2;

// The rollapp id
string rollapp_id = 3;
// The ibc client id of the rollapp
string ibc_client_id = 4;
// The height of the fraudelent block
uint64 fraudelent_height = 5;
// The address of the fraudelent sequencer
string fraudelent_sequencer_address = 6;
}
1 change: 1 addition & 0 deletions testutil/keeper/rollapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func RollappKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) {
storeKey,
memStoreKey,
paramsSubspace,
nil,
)

ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger())
Expand Down
22 changes: 22 additions & 0 deletions utils/client_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package utils

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/osmosis-labs/osmosis/v15/osmoutils"
"github.com/spf13/cobra"
)

func ParseProposal(cmd *cobra.Command) (osmoutils.Proposal, sdk.Coins, error) {
proposal, err := osmoutils.ParseProposalFlags(cmd.Flags())
if err != nil {
return osmoutils.Proposal{}, nil, fmt.Errorf("failed to parse proposal: %w", err)
}

deposit, err := sdk.ParseCoinsNormalized(proposal.Deposit)
if err != nil {
return osmoutils.Proposal{}, nil, err
}
return *proposal, deposit, nil
}
5 changes: 5 additions & 0 deletions x/delayedack/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ func (im IBCMiddleware) AfterStateFinalized(ctx sdk.Context, rollappID string, s
return im.FinalizeRollappPackets(ctx, rollappID, stateEndHeight)
}

func (im IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error {
// TODO: Implement fraud handling
return nil
}

// FinalizeRollappPackets finalizes the packets for the given rollapp until the given height which is
// the end height of the latest finalized state
func (im IBCMiddleware) FinalizeRollappPackets(ctx sdk.Context, rollappID string, stateEndHeight uint64) error {
Expand Down
60 changes: 60 additions & 0 deletions x/rollapp/client/cli/tx_submit_fraud_proposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package cli

import (
"strconv"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/spf13/cobra"

"github.com/dymensionxyz/dymension/v3/x/rollapp/types"

govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"

"github.com/dymensionxyz/dymension/v3/utils"
)

// NewCmdSubmitFraudProposal submits a fraud proposal
func NewCmdSubmitFraudProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-fraud-proposal <rollappID> <height> <propser_addr> <client_id>",
Short: "submit a fraud proposal",
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

proposal, deposit, err := utils.ParseProposal(cmd)
if err != nil {
return err
}

rollappID := args[0]
height, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}

proposerAddr := args[2]
ibcClientID := args[3]

content := types.NewSubmitFraudProposal(proposal.Title, proposal.Description, rollappID, height, proposerAddr, ibcClientID)
msg, err := govtypes.NewMsgSubmitProposal(content, deposit, clientCtx.GetFromAddress())
if err != nil {
return err
}

txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}

cmd.Flags().String(govcli.FlagTitle, "", "The proposal title")
cmd.Flags().String(govcli.FlagDescription, "", "The proposal description")
cmd.Flags().String(govcli.FlagDeposit, "", "The proposal deposit")

return cmd
}
10 changes: 10 additions & 0 deletions x/rollapp/client/proposal_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package client

import (
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
"github.com/dymensionxyz/dymension/v3/x/rollapp/client/cli"
)

var (
SubmitFraudHandler = govclient.NewProposalHandler(cli.NewCmdSubmitFraudProposal)
)
66 changes: 66 additions & 0 deletions x/rollapp/keeper/fraud_proposal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package keeper

import (
"fmt"

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

clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
tmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types"
"github.com/dymensionxyz/dymension/v3/x/rollapp/types"
)

// HandleFraud handles the fraud evidence submitted by the user.
func (k Keeper) HandleFraud(ctx sdk.Context, rollappID, clientId string, height uint64, seqAddr string) error {
// Get the rollapp from the store
_, found := k.GetRollapp(ctx, rollappID)
if !found {
return sdkerrors.Wrapf(types.ErrInvalidRollappID, "rollapp with ID %s not found", rollappID)
}

stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, height)
if err != nil {
return err
}

//TODO: mark the rollapp as frozen (if immutable) or mark the fraud height to allow overwriting

if stateInfo.Sequencer != seqAddr {
return sdkerrors.Wrapf(types.ErrInvalidSequencer, "sequencer address %s does not match the one in the state info", seqAddr)
}

// slash the sequencer
err = k.hooks.FraudSubmitted(ctx, rollappID, height, seqAddr)
if err != nil {
return err
}

//FIXME: make sure the clientId corresponds to the rollappID

clientState, ok := k.ibcclientkeeper.GetClientState(ctx, clientId)
if !ok {
return sdkerrors.Wrapf(types.ErrInvalidClientState, "client state for clientID %s not found", clientId)
}

// Set the client state to frozen
tmClientState, ok := clientState.(*tmtypes.ClientState)
if !ok {
return sdkerrors.Wrapf(types.ErrInvalidClientState, "client state with ID %s is not a tendermint client state", clientId)
}

tmClientState.FrozenHeight = clienttypes.NewHeight(tmClientState.GetLatestHeight().GetRevisionHeight(), tmClientState.GetLatestHeight().GetRevisionNumber())
k.ibcclientkeeper.SetClientState(ctx, clientId, tmClientState)

// Emit an event
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeFraud,
sdk.NewAttribute(types.AttributeKeyRollappId, rollappID),
sdk.NewAttribute(types.AttributeKeyFraudHeight, fmt.Sprint(height)),
sdk.NewAttribute(types.AttributeKeyFraudSequencer, seqAddr),
),
)

return nil
}
25 changes: 14 additions & 11 deletions x/rollapp/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ import (

type (
Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
memKey storetypes.StoreKey
hooks types.MultiRollappHooks
paramstore paramtypes.Subspace
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
memKey storetypes.StoreKey
hooks types.MultiRollappHooks

ibcclientkeeper types.IBCClientKeeper
paramstore paramtypes.Subspace
}
)

Expand All @@ -27,7 +29,7 @@ func NewKeeper(
storeKey,
memKey storetypes.StoreKey,
ps paramtypes.Subspace,

ibcclientkeeper types.IBCClientKeeper,
) *Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
Expand All @@ -36,11 +38,12 @@ func NewKeeper(

return &Keeper{

cdc: cdc,
storeKey: storeKey,
memKey: memKey,
paramstore: ps,
hooks: nil,
cdc: cdc,
storeKey: storeKey,
memKey: memKey,
paramstore: ps,
hooks: nil,
ibcclientkeeper: ibcclientkeeper,
}
}

Expand Down
30 changes: 30 additions & 0 deletions x/rollapp/proposal_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package rollapp

import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dymensionxyz/dymension/v3/x/rollapp/keeper"
"github.com/dymensionxyz/dymension/v3/x/rollapp/types"

govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"

sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

func NewRollappProposalHandler(k *keeper.Keeper) govtypes.Handler {
return func(ctx sdk.Context, content govtypes.Content) error {
switch c := content.(type) {
case *types.SubmitFraudProposal:
return HandleSubmitFraudProposal(ctx, k, c)
default:
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized rollapp proposal content type: %T", c)
}
}
}

func HandleSubmitFraudProposal(ctx sdk.Context, k *keeper.Keeper, p *types.SubmitFraudProposal) error {
err := k.HandleFraud(ctx, p.RollappId, p.IbcClientId, p.FraudelentHeight, p.FraudelentSequencerAddress)
if err != nil {
return err
}
return nil
}
8 changes: 7 additions & 1 deletion x/rollapp/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"

govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)

func RegisterCodec(cdc *codec.LegacyAmino) {
Expand All @@ -20,7 +22,11 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil),
&MsgUpdateState{},
)
// this line is used by starport scaffolding # 3

registry.RegisterImplementations(
(*govtypes.Content)(nil),
&SubmitFraudProposal{},
)

msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
Expand Down
2 changes: 2 additions & 0 deletions x/rollapp/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ var (
ErrRollappsDisabled = sdkerrors.Register(ModuleName, 1022, "rollapps are disabled")
ErrInvalidTokenMetadata = sdkerrors.Register(ModuleName, 1023, "invalid token metadata")
ErrNoFinalizedStateYetForRollapp = sdkerrors.Register(ModuleName, 1024, "no finalized state yet for rollapp")
ErrInvalidClientState = sdkerrors.Register(ModuleName, 1025, "invalid client state")
ErrInvalidSequencer = sdkerrors.Register(ModuleName, 1026, "invalid sequencer")
)
4 changes: 4 additions & 0 deletions x/rollapp/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ const (
AttributeKeyNumBlocks = "num_blocks"
AttributeKeyDAPath = "da_path"
AttributeKeyStatus = "status"

EventTypeFraud = "fraud_proposal"
AttributeKeyFraudHeight = "fraud_height"
AttributeKeyFraudSequencer = "fraud_sequencer"
)
6 changes: 6 additions & 0 deletions x/rollapp/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ibc-go/v6/modules/core/exported"
)

// AccountKeeper defines the expected account keeper used for simulations (noalias)
Expand All @@ -16,3 +17,8 @@ type BankKeeper interface {
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
// Methods imported from bank should be defined here
}

type IBCClientKeeper interface {
GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool)
SetClientState(ctx sdk.Context, clientID string, clientState exported.ClientState)
}
Loading

0 comments on commit bd0aa22

Please sign in to comment.