Skip to content

Commit

Permalink
chore(data-proxy): add edit message handling
Browse files Browse the repository at this point in the history
Part-of: #316
  • Loading branch information
Thomasvdam committed Aug 22, 2024
1 parent 12fadeb commit 393bb55
Show file tree
Hide file tree
Showing 10 changed files with 646 additions and 81 deletions.
19 changes: 14 additions & 5 deletions proto/sedachain/data_proxy/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,27 @@ message MsgRegisterDataProxyResponse {}
// Allow updating memo and payout address instantly and/or scheduling a fee
// update.
message MsgEditDataProxy {
string new_payout_address = 1
option (cosmos.msg.v1.signer) = "sender";

string sender = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];

string new_payout_address = 2
[ (cosmos_proto.scalar) = "cosmos.AddressString" ];

string new_memo = 2 [ (gogoproto.nullable) = true ];
string new_memo = 3;

cosmos.base.v1beta1.Coin new_fee = 4 [ (gogoproto.nullable) = true ];

cosmos.base.v1beta1.Coin new_fee = 3 [ (gogoproto.nullable) = true ];
// 0 will default to the minimum delay configured in the params
uint32 fee_update_delay = 5;

uint32 fee_update_delay = 4 [ (gogoproto.nullable) = true ];
// hex encoded bytes as the expected flow is users sending updates from the
// browser
string pub_key = 6;
}

// Returns the height at which the fee update will go into effect.
message MsgEditDataProxyResponse { int64 update_height = 1; }
message MsgEditDataProxyResponse { int64 fee_update_height = 1; }

// The request message for the UpdateParams method.
message MsgUpdateParams {
Expand Down
58 changes: 53 additions & 5 deletions x/data-proxy/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import (
)

const (
// FlagKeyFile defines a flag to add arbitrary data to a data proxy.
FlagMemo = "memo"
FlagMemo = "memo"
FlagNewPayoutAddress = "payout-address"
FlagNewFee = "fee"
FlagFeeUpdateDelay = "fee-delay"
)

// GetTxCmd returns the CLI transaction commands for this module
Expand All @@ -28,12 +30,11 @@ func GetTxCmd() *cobra.Command {
}
cmd.AddCommand(
RegisterDataProxy(),
EditDataProxy(),
)
return cmd
}

// AddKey returns the command for adding a new key and uploading its
// public key on chain at a given index.
func RegisterDataProxy() *cobra.Command {
cmd := &cobra.Command{
Use: "register [payout_address] [fee] [public_key_hex] [signature_hex] --from [admin_address]",
Expand Down Expand Up @@ -70,4 +71,51 @@ func RegisterDataProxy() *cobra.Command {
return cmd
}

// TODO Edit tx
func EditDataProxy() *cobra.Command {
cmd := &cobra.Command{
Use: "edit [public_key_hex] --from [admin_address]",
Short: "Edit an existing data proxy. Payout address and memo take effect instantly, fee updates are scheduled according to the minimum delay or a custom delay",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

newMemo, _ := cmd.Flags().GetString(FlagMemo)
newPayoutAddress, _ := cmd.Flags().GetString(FlagNewPayoutAddress)

msg := &types.MsgEditDataProxy{
Sender: clientCtx.GetFromAddress().String(),
PubKey: args[0],
NewMemo: newMemo,
NewPayoutAddress: newPayoutAddress,
}

feeValue, _ := cmd.Flags().GetString(FlagNewFee)
if feeValue != "" {
fee, err := sdk.ParseCoinNormalized(feeValue)
if err != nil {
return err
}

msg.NewFee = &fee

feeUpdateDelay, _ := cmd.Flags().GetUint32(FlagFeeUpdateDelay)

msg.FeeUpdateDelay = feeUpdateDelay
}

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

flags.AddTxFlagsToCmd(cmd)

cmd.Flags().String(FlagMemo, types.DoNotModifyField, "Optionally add a description to the data proxy config")
cmd.Flags().String(FlagNewPayoutAddress, types.DoNotModifyField, "The new payout address for this data proxy")
cmd.Flags().String(FlagNewFee, "", "The new fee to be scheduled for this data proxy")
cmd.Flags().Uint32(FlagFeeUpdateDelay, types.UseMinimumDelay, "Optionally specify a custom delay in blocks. Must be larger than minimum set in module params")

return cmd
}
3 changes: 3 additions & 0 deletions x/data-proxy/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@ func (s *KeeperTestSuite) SetupTest() {
querier := keeper.Querier{Keeper: *s.keeper}
types.RegisterQueryServer(queryHelper, querier)
s.queryClient = types.NewQueryClient(queryHelper)

err := s.keeper.Params.Set(s.ctx, types.DefaultParams())
s.Require().NoError(err)
}
32 changes: 32 additions & 0 deletions x/data-proxy/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,35 @@ func (k Keeper) GetFeeUpdatePubKeys(ctx context.Context, activationHeight int64)

return pubkeys, nil
}

func (k Keeper) processProxyFeeUpdate(ctx sdk.Context, pubKeyBytes []byte, proxyConfig *types.ProxyConfig, newFee *sdk.Coin, updateDelay uint32) (int64, error) {

// Determine update height
updateHeight := ctx.BlockHeight() + int64(updateDelay)
feeUpdate := &types.FeeUpdate{
NewFee: *newFee,
UpdateHeight: updateHeight,
}

// Delete previous pending update, if applicable
if proxyConfig.FeeUpdate != nil {
err := k.FeeUpdateQueue.Remove(ctx, collections.Join(proxyConfig.FeeUpdate.UpdateHeight, pubKeyBytes))
if err != nil {
return 0, err
}
}

// Schedule new update
proxyConfig.FeeUpdate = feeUpdate
err := k.FeeUpdateQueue.Set(ctx, collections.Join(updateHeight, pubKeyBytes))
if err != nil {
return 0, err
}

err = k.DataProxyConfigs.Set(ctx, pubKeyBytes, *proxyConfig)
if err != nil {
return 0, err
}

return updateHeight, nil
}
83 changes: 78 additions & 5 deletions x/data-proxy/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package keeper
import (
"context"
"encoding/hex"
"errors"
"fmt"

"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"

"cosmossdk.io/collections"

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

"github.com/sedaprotocol/seda-chain/x/data-proxy/types"
Expand Down Expand Up @@ -46,6 +49,8 @@ func (m msgServer) RegisterDataProxy(goCtx context.Context, msg *types.MsgRegist
return nil, types.ErrInvalidHex.Wrap(err.Error())
}

// TODO check if fee is in native denom

found, err := m.DataProxyConfigs.Has(ctx, pubKeyBytes)
if err != nil {
return nil, err
Expand All @@ -67,23 +72,91 @@ func (m msgServer) RegisterDataProxy(goCtx context.Context, msg *types.MsgRegist
return nil, types.ErrInvalidSignature
}

err = m.DataProxyConfigs.Set(ctx, pubKeyBytes, types.ProxyConfig{
proxyConfig := types.ProxyConfig{
PayoutAddress: msg.PayoutAddress,
Fee: msg.Fee,
Memo: msg.Memo,
FeeUpdate: nil,
AdminAddress: msg.AdminAddress,
})
}

err = proxyConfig.Validate()
if err != nil {
return nil, err
}

err = m.DataProxyConfigs.Set(ctx, pubKeyBytes, proxyConfig)
if err != nil {
return nil, err
}

return &types.MsgRegisterDataProxyResponse{}, nil
}

func (m msgServer) EditDataProxy(_ context.Context, _ *types.MsgEditDataProxy) (*types.MsgEditDataProxyResponse, error) {
// TODO
return &types.MsgEditDataProxyResponse{}, nil
func (m msgServer) EditDataProxy(goCtx context.Context, msg *types.MsgEditDataProxy) (*types.MsgEditDataProxyResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

if err := msg.Validate(); err != nil {
return nil, err
}

pubKeyBytes, err := hex.DecodeString(msg.PubKey)
if err != nil {
return nil, types.ErrInvalidHex.Wrap(err.Error())
}

proxyConfig, err := m.DataProxyConfigs.Get(ctx, pubKeyBytes)
if err != nil {
if errors.Is(err, collections.ErrNotFound) {
return nil, types.ErrUnknownDataProxy.Wrapf("no data proxy registered for %s", msg.PubKey)
}
return nil, err
}

if msg.Sender != proxyConfig.AdminAddress {
return nil, types.ErrUnauthorized
}

err = proxyConfig.UpdateBasic(msg.NewPayoutAddress, msg.NewMemo)
if err != nil {
return nil, err
}

// If there is no new fee we can terminate early
if msg.NewFee == nil {
err = m.DataProxyConfigs.Set(ctx, pubKeyBytes, proxyConfig)
if err != nil {
return nil, err
}

return &types.MsgEditDataProxyResponse{}, nil
}

// TODO check if fee is in native denom

params, err := m.Keeper.Params.Get(ctx)
if err != nil {
return nil, err
}

updateDelay := params.MinFeeUpdateDelay
// Validate custom delay if passed
if msg.FeeUpdateDelay != types.UseMinimumDelay {
if msg.FeeUpdateDelay < params.MinFeeUpdateDelay {
return nil, types.ErrInvalidDelay.Wrapf("minimum delay %d, got %d", params.MinFeeUpdateDelay, msg.FeeUpdateDelay)
}

updateDelay = msg.FeeUpdateDelay
}

updateHeight, err := m.Keeper.processProxyFeeUpdate(ctx, pubKeyBytes, &proxyConfig, msg.NewFee, updateDelay)
if err != nil {
return nil, err
}

return &types.MsgEditDataProxyResponse{
FeeUpdateHeight: updateHeight,
}, nil
}

func (m msgServer) UpdateParams(goCtx context.Context, req *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) {
Expand Down
Loading

0 comments on commit 393bb55

Please sign in to comment.