Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sequencer): added reward addr and whitelisted relayers #1313

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ibctesting/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ func (s *utilSuite) registerSequencer() {
RestApiUrls: []string{"https://api.wpd.evm.rollapp.noisnemyd.xyz:443"},
},
bond,
s.hubChain().SenderAccount.GetAddress().String(),
[]string{},
)
s.Require().NoError(err) // message committed
_, err = s.hubChain().SendMsgs(msgCreateSequencer)
Expand Down
27 changes: 26 additions & 1 deletion proto/dymensionxyz/dymension/sequencer/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package dymensionxyz.dymension.sequencer;
import "cosmos_proto/cosmos.proto";
import "gogoproto/gogo.proto";
import "cosmos/base/v1beta1/coin.proto";
import "cosmos/msg/v1/msg.proto";

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

Expand All @@ -17,4 +16,30 @@ message EventIncreasedBond {
cosmos.base.v1beta1.Coin added_amount = 2 [(gogoproto.nullable) = false];
// bond is the new active bond amount of the sequencer
repeated cosmos.base.v1beta1.Coin bond = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];
}

message EventRotationStarted {
// RollappId defines the rollapp to which the sequencer belongs.
string rollapp_id = 1;
// NextProposerAddr is the bech32-encoded address of the next proposer.
// can be empty if no sequencer is available to be the next proposer.
string next_proposer_addr = 2;
// RewardAddr is a bech32-encoded address of the sequencer's reward address.
string reward_addr = 3;
// WhitelistedRelayers is a list of the whitelisted relayer addresses. Addresses are bech32-encoded strings.
repeated string whitelisted_relayers = 4;
}

message EventUpdateRewardAddress {
// Operator is the bech32-encoded address of the actor sending the update
string creator = 1;
// RewardAddr is a bech32 encoded sdk acc address
string reward_addr = 2;
}

message EventUpdateWhitelistedRelayers {
// Operator is the bech32-encoded address of the actor sending the update
string creator = 1;
// Relayers is an array of the whitelisted relayer addresses. Addresses are bech32-encoded strings.
repeated string relayers = 2;
}
5 changes: 5 additions & 0 deletions proto/dymensionxyz/dymension/sequencer/sequencer.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ message Sequencer {
// notice_period_time defines the time when the sequencer will finish it's notice period if started
google.protobuf.Timestamp notice_period_time = 11
[ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ];

// RewardAddr is a bech32 encoded sdk acc address
string reward_addr = 12;
// WhitelistedRelayers is an array of the whitelisted relayer addresses. Addresses are bech32-encoded strings.
repeated string whitelisted_relayers = 13;
}

// BondReduction defines an object which holds the information about the sequencer and its queued unbonding amount
Expand Down
29 changes: 29 additions & 0 deletions proto/dymensionxyz/dymension/sequencer/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ service Msg {
rpc CreateSequencer (MsgCreateSequencer) returns (MsgCreateSequencerResponse);
// UpdateSequencerInformation defines a method for updating the sequencer's metadata.
rpc UpdateSequencerInformation (MsgUpdateSequencerInformation) returns (MsgUpdateSequencerInformationResponse);
// UpdateRewardAddress defines a method for updating the sequencer's reward address.
rpc UpdateRewardAddress(MsgUpdateRewardAddress) returns (MsgUpdateRewardAddressResponse);
// UpdateWhitelistedRelayers defines a method for updating the sequencer's whitelisted relater list.
rpc UpdateWhitelistedRelayers(MsgUpdateWhitelistedRelayers) returns (MsgUpdateWhitelistedRelayersResponse);
// Unbond defines a method for removing coins from sequencer's bond
rpc Unbond (MsgUnbond) returns (MsgUnbondResponse);
// IncreaseBond defines a method for increasing a sequencer's bond amount
Expand Down Expand Up @@ -63,6 +67,11 @@ message MsgCreateSequencer {
SequencerMetadata metadata = 4 [(gogoproto.nullable) = false];
// entry bond for the sequencer.
cosmos.base.v1beta1.Coin bond = 5 [(gogoproto.nullable) = false];
// RewardAddr is the bech32-encoded sequencer's reward address. Empty is valid.
// If empty, the creator address is used.
string reward_addr = 6;
// WhitelistedRelayers is an array of the whitelisted relayer addresses. Addresses are bech32-encoded strings.
repeated string whitelisted_relayers = 7;
}

message MsgCreateSequencerResponse {}
Expand All @@ -77,6 +86,26 @@ message MsgUpdateSequencerInformation {

message MsgUpdateSequencerInformationResponse {}

message MsgUpdateRewardAddress {
option (cosmos.msg.v1.signer) = "creator";
// Creator is the bech32-encoded address of the actor sending the update
string creator = 1;
// RewardAddr is a bech32 encoded sdk acc address
string reward_addr = 2;
}

message MsgUpdateRewardAddressResponse {}

message MsgUpdateWhitelistedRelayers {
option (cosmos.msg.v1.signer) = "creator";
// Creator is the bech32-encoded address of the actor sending the update
string creator = 1;
// Relayers is an array of the whitelisted relayer addresses. Addresses are bech32-encoded strings.
repeated string relayers = 2;
}

message MsgUpdateWhitelistedRelayersResponse {}

// MsgUnbond defines a SDK message for performing an undelegation from a
// bond and a sequencer.
message MsgUnbond {
Expand Down
81 changes: 79 additions & 2 deletions x/sequencer/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
Expand All @@ -26,18 +27,29 @@ func GetTxCmd() *cobra.Command {

cmd.AddCommand(CmdCreateSequencer())
cmd.AddCommand(CmdUpdateSequencer())
cmd.AddCommand(CmdUpdateRewardAddress())
cmd.AddCommand(CmdUpdateWhitelistedRelayers())
cmd.AddCommand(CmdUnbond())
cmd.AddCommand(CmdIncreaseBond())
cmd.AddCommand(CmdDecreaseBond())

return cmd
}

const (
FlagRewardAddress = "reward-address"
FlagWhitelistedRelayers = "whitelisted-relayers"
)

func CmdCreateSequencer() *cobra.Command {
cmd := &cobra.Command{
Use: "create-sequencer [pubkey] [rollapp-id] [bond] [metadata]",
Use: "create-sequencer [pubkey] [rollapp-id] [bond] [metadata] --reward-address [reward_addr] --whitelisted-relayers [addr1,addr2,addr3]",
Short: "Create a new sequencer for a rollapp",
Args: cobra.MinimumNArgs(3),
Long: `Create a new sequencer for a rollapp.
Metadata is an optional arg.
Reward address is an optional flag-arg. It expects a bech32-encoded address which will be used as a sequencer's reward address.
Whitelisted relayers is an optional flag-arg. It expects a comma-separated list of bech32-encoded addresses.`,
Args: cobra.MinimumNArgs(3),
RunE: func(cmd *cobra.Command, args []string) (err error) {
argPubkey := args[0]
argRollappId := args[1]
Expand All @@ -50,6 +62,13 @@ func CmdCreateSequencer() *cobra.Command {
}
}

rewardAddr, _ := cmd.Flags().GetString(FlagRewardAddress)

var whitelistedRelayers []string
if relayers, _ := cmd.Flags().GetString(FlagWhitelistedRelayers); relayers != "" {
whitelistedRelayers = strings.Split(relayers, ",")
}

clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
Expand All @@ -72,6 +91,8 @@ func CmdCreateSequencer() *cobra.Command {
argRollappId,
&metadata,
bondCoin,
rewardAddr,
whitelistedRelayers,
)
if err != nil {
return err
Expand All @@ -82,6 +103,8 @@ func CmdCreateSequencer() *cobra.Command {
}

flags.AddTxFlagsToCmd(cmd)
cmd.Flags().String(FlagRewardAddress, "", "Sequencer reward address")
cmd.Flags().String(FlagWhitelistedRelayers, "", "Sequencer whitelisted relayers")

return cmd
}
Expand Down Expand Up @@ -119,6 +142,60 @@ func CmdUpdateSequencer() *cobra.Command {
return cmd
}

func CmdUpdateRewardAddress() *cobra.Command {
short := "Update a sequencer reward address"
cmd := &cobra.Command{
Use: "update-reward-address [addr]",
Example: "update-reward-address ethm1lhk5cnfrhgh26w5r6qft36qerg4dclfev9nprc --from foouser",
Args: cobra.ExactArgs(1),
Short: short,
RunE: func(cmd *cobra.Command, args []string) error {
ctx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := &types.MsgUpdateRewardAddress{
Creator: sdk.ValAddress(ctx.GetFromAddress()).String(),
RewardAddr: args[0],
}

return tx.GenerateOrBroadcastTxCLI(ctx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func CmdUpdateWhitelistedRelayers() *cobra.Command {
short := "Update a sequencer whitelisted relayer list"
cmd := &cobra.Command{
Use: "update-whitelisted-relayers [relayers]",
Example: "update-whitelisted-relayers ethm1lhk5cnfrhgh26w5r6qft36qerg4dclfev9nprc,ethm1lhasdf8969asdfgj2g3j4,ethmasdfkjhgjkhg123j4hgasv7ghi4v --from foouser",
Args: cobra.ExactArgs(1),
Short: short,
RunE: func(cmd *cobra.Command, args []string) error {
ctx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := &types.MsgUpdateWhitelistedRelayers{
Creator: sdk.ValAddress(ctx.GetFromAddress()).String(),
Relayers: strings.Split(args[0], ","),
}

return tx.GenerateOrBroadcastTxCLI(ctx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

func CmdUnbond() *cobra.Command {
cmd := &cobra.Command{
Use: "unbond",
Expand Down
8 changes: 8 additions & 0 deletions x/sequencer/keeper/msg_server_create_sequencer.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe
return nil, err
}

// set a reward address. if empty, use a creator address.
rewardAddr := msg.RewardAddr
if msg.RewardAddr == "" {
rewardAddr = msg.Creator
}

bond := sdk.NewCoins(msg.Bond)
sequencer := types.Sequencer{
Address: msg.Creator,
Expand All @@ -86,7 +92,9 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe
Metadata: msg.Metadata,
Status: types.Bonded,
Tokens: bond,
RewardAddr: rewardAddr,
}
sequencer.SetWhitelistedRelayers(msg.WhitelistedRelayers)

// we currently only support setting next proposer (or empty one) before the rotation started. This is in order to
// avoid handling the case a potential next proposer bonds in the middle of a rotation.
Expand Down
25 changes: 19 additions & 6 deletions x/sequencer/keeper/msg_server_create_sequencer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"reflect"
"slices"
"time"

errorsmod "cosmossdk.io/errors"
Expand Down Expand Up @@ -155,6 +156,7 @@ func (suite *SequencerTestSuite) TestCreateSequencer() {
for i := 0; i < 10; i++ {
pubkey := ed25519.GenPrivKey().PubKey()
addr := sdk.AccAddress(pubkey.Address())
addr1 := sdk.AccAddress(pubkey.Address())
err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond))
suite.Require().NoError(err)
pkAny, err := codectypes.NewAnyWithValue(pubkey)
Expand All @@ -169,15 +171,19 @@ func (suite *SequencerTestSuite) TestCreateSequencer() {
Metadata: types.SequencerMetadata{
Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"},
},
RewardAddr: addr1.String(),
WhitelistedRelayers: []string{addr.String()},
}
// sequencerExpect is the expected result of creating a sequencer
sequencerExpect := types.Sequencer{
Address: sequencerMsg.GetCreator(),
DymintPubKey: sequencerMsg.GetDymintPubKey(),
Status: types.Bonded,
RollappId: rollappId,
Tokens: sdk.NewCoins(bond),
Metadata: sequencerMsg.GetMetadata(),
Address: sequencerMsg.GetCreator(),
DymintPubKey: sequencerMsg.GetDymintPubKey(),
Status: types.Bonded,
RollappId: rollappId,
Tokens: sdk.NewCoins(bond),
Metadata: sequencerMsg.GetMetadata(),
RewardAddr: addr1.String(),
WhitelistedRelayers: []string{addr.String()},
}

// create sequencer
Expand Down Expand Up @@ -517,6 +523,7 @@ func getAll(suite *SequencerTestSuite) (map[string]*types.Sequencer, int) {

// equalSequencer receives two sequencers and compares them. If they are not equal, fails the test
func (suite *SequencerTestSuite) equalSequencer(s1 *types.Sequencer, s2 *types.Sequencer) {
suite.T().Helper()
eq := compareSequencers(s1, s2)
suite.Require().True(eq, "expected: %v\nfound: %v", *s1, *s2)
}
Expand Down Expand Up @@ -558,5 +565,11 @@ func compareSequencers(s1, s2 *types.Sequencer) bool {
if !reflect.DeepEqual(s1.Metadata, s2.Metadata) {
return false
}
if s1.RewardAddr != s2.RewardAddr {
return false
}
if !slices.Equal(s1.WhitelistedRelayers, s2.WhitelistedRelayers) {
return false
}
return true
}
37 changes: 37 additions & 0 deletions x/sequencer/keeper/msg_server_update_reward_address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package keeper

import (
"context"
"fmt"

errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/dymensionxyz/gerr-cosmos/gerrc"
"github.com/dymensionxyz/sdk-utils/utils/uevent"

"github.com/dymensionxyz/dymension/v3/x/sequencer/types"
)

// UpdateRewardAddress defines a method for updating the sequencer's reward address.
func (k msgServer) UpdateRewardAddress(goCtx context.Context, msg *types.MsgUpdateRewardAddress) (*types.MsgUpdateRewardAddressResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

seq, ok := k.GetSequencer(ctx, msg.Creator)
if !ok {
return nil, errorsmod.Wrap(gerrc.ErrNotFound, "sequencer")
}

seq.RewardAddr = msg.RewardAddr

k.SetSequencer(ctx, seq)

err := uevent.EmitTypedEvent(ctx, &types.EventUpdateRewardAddress{
Creator: msg.Creator,
RewardAddr: msg.RewardAddr,
})
if err != nil {
return nil, fmt.Errorf("emit event: %w", err)
}

return &types.MsgUpdateRewardAddressResponse{}, nil
}
Loading
Loading