Skip to content

Commit

Permalink
feat(state): enable fee granting (#3304)
Browse files Browse the repository at this point in the history
  • Loading branch information
vgonkivs committed Apr 16, 2024
1 parent 0231275 commit 332739f
Show file tree
Hide file tree
Showing 10 changed files with 315 additions and 12 deletions.
6 changes: 5 additions & 1 deletion cmd/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,13 @@ func PersistentPreRunEnv(cmd *cobra.Command, nodeType node.Type, _ []string) err
return err
}

err = state.ParseFlags(cmd, &cfg.State)
if err != nil {
return err
}

rpc_cfg.ParseFlags(cmd, &cfg.RPC)
gateway.ParseFlags(cmd, &cfg.Gateway)
state.ParseFlags(cmd, &cfg.State)

switch nodeType {
case node.Light:
Expand Down
83 changes: 83 additions & 0 deletions nodebuilder/state/cmd/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import (
"github.com/celestiaorg/celestia-node/state"
)

var (
amount uint64
)

func init() {
Cmd.AddCommand(
accountAddressCmd,
Expand All @@ -26,6 +30,16 @@ func init() {
queryDelegationCmd,
queryUnbondingCmd,
queryRedelegationCmd,
grantFeeCmd,
revokeGrantFeeCmd,
)

grantFeeCmd.PersistentFlags().Uint64Var(
&amount,
"amount",
0,
"specifies the spend limit(in utia) for the grantee.\n"+
"The default value is 0 which means the grantee does not have a spend limit.",
)
}

Expand Down Expand Up @@ -402,6 +416,75 @@ var queryRedelegationCmd = &cobra.Command{
},
}

var grantFeeCmd = &cobra.Command{
Use: "grant-fee [granteeAddress] [fee] [gasLimit]",
Short: "Grant an allowance to a specified grantee account to pay the fees for their transactions.\n" +
"Grantee can spend any amount of tokens in case the spend limit is not set.",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := cmdnode.ParseClientFromCtx(cmd.Context())
if err != nil {
return err
}
defer client.Close()

granteeAddr, err := parseAddressFromString(args[0])
if err != nil {
return fmt.Errorf("error parsing an address:%v", err)
}

fee, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return fmt.Errorf("error parsing a fee:%v", err)
}
gasLimit, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return fmt.Errorf("error parsing a gas limit:%v", err)
}

txResponse, err := client.State.GrantFee(
cmd.Context(),
granteeAddr.Address.(state.AccAddress),
math.NewInt(int64(amount)), math.NewInt(fee), gasLimit,
)
return cmdnode.PrintOutput(txResponse, err, nil)
},
}

var revokeGrantFeeCmd = &cobra.Command{
Use: "revoke-grant-fee [granteeAddress] [fee] [gasLimit]",
Short: "Removes permission for grantee to submit PFB transactions which will be paid by granter.",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
client, err := cmdnode.ParseClientFromCtx(cmd.Context())
if err != nil {
return err
}
defer client.Close()

granteeAddr, err := parseAddressFromString(args[0])
if err != nil {
return fmt.Errorf("error parsing an address:%v", err)
}

fee, err := strconv.ParseInt(args[1], 10, 64)
if err != nil {
return fmt.Errorf("error parsing a fee:%v", err)
}
gasLimit, err := strconv.ParseUint(args[2], 10, 64)
if err != nil {
return fmt.Errorf("error parsing a gas limit:%v", err)
}

txResponse, err := client.State.RevokeGrantFee(
cmd.Context(),
granteeAddr.Address.(state.AccAddress),
math.NewInt(fee), gasLimit,
)
return cmdnode.PrintOutput(txResponse, err, nil)
},
}

func parseAddressFromString(addrStr string) (state.Address, error) {
var address state.Address
err := address.UnmarshalJSON([]byte(addrStr))
Expand Down
4 changes: 4 additions & 0 deletions nodebuilder/state/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package state

import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"

"github.com/celestiaorg/celestia-node/state"
)

var defaultKeyringBackend = keyring.BackendTest
Expand All @@ -11,12 +13,14 @@ var defaultKeyringBackend = keyring.BackendTest
type Config struct {
KeyringAccName string
KeyringBackend string
GranterAddress state.AccAddress
}

func DefaultConfig() Config {
return Config{
KeyringAccName: "",
KeyringBackend: defaultKeyringBackend,
GranterAddress: state.AccAddress{},
}
}

Expand Down
7 changes: 4 additions & 3 deletions nodebuilder/state/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ func coreAccessor(
signer *apptypes.KeyringSigner,
sync *sync.Syncer[*header.ExtendedHeader],
fraudServ libfraud.Service[*header.ExtendedHeader],
opts []state.Option,
) (*state.CoreAccessor, Module, *modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]) {
ca := state.NewCoreAccessor(signer, sync, corecfg.IP, corecfg.RPCPort, corecfg.GRPCPort)

return ca, ca, &modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]{
ca := state.NewCoreAccessor(signer, sync, corecfg.IP, corecfg.RPCPort, corecfg.GRPCPort, opts...)
sBreaker := &modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]{
Service: ca,
FraudType: byzantine.BadEncoding,
FraudServ: fraudServ,
}
return ca, ca, sBreaker
}
15 changes: 14 additions & 1 deletion nodebuilder/state/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package state
import (
"fmt"

sdktypes "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
)

var (
keyringAccNameFlag = "keyring.accname"
keyringBackendFlag = "keyring.backend"

granterAddressFlag = "granter.address"
)

// Flags gives a set of hardcoded State flags.
Expand All @@ -21,15 +24,25 @@ func Flags() *flag.FlagSet {
flags.String(keyringBackendFlag, defaultKeyringBackend, fmt.Sprintf("Directs node's keyring signer to use the given "+
"backend. Default is %s.", defaultKeyringBackend))

flags.String(granterAddressFlag, "", "Account address that will pay for all transactions submitted from the node.")
return flags
}

// ParseFlags parses State flags from the given cmd and saves them to the passed config.
func ParseFlags(cmd *cobra.Command, cfg *Config) {
func ParseFlags(cmd *cobra.Command, cfg *Config) error {
keyringAccName := cmd.Flag(keyringAccNameFlag).Value.String()
if keyringAccName != "" {
cfg.KeyringAccName = keyringAccName
}

cfg.KeyringBackend = cmd.Flag(keyringBackendFlag).Value.String()

addr := cmd.Flag(granterAddressFlag).Value.String()
if addr == "" {
return nil
}

sdkAddress, err := sdktypes.AccAddressFromBech32(addr)
cfg.GranterAddress = sdkAddress
return err
}
30 changes: 30 additions & 0 deletions nodebuilder/state/mocks/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion nodebuilder/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ var log = logging.Logger("module/state")
func ConstructModule(tp node.Type, cfg *Config, coreCfg *core.Config) fx.Option {
// sanitize config values before constructing module
cfgErr := cfg.Validate()

opts := make([]state.Option, 0)
if !cfg.GranterAddress.Empty() {
opts = append(opts, state.WithGranter(cfg.GranterAddress))
}
baseComponents := fx.Options(
fx.Supply(*cfg),
fx.Error(cfgErr),
fx.Supply(opts),
fxutil.ProvideIf(coreCfg.IsEndpointConfigured(), fx.Annotate(
coreAccessor,
fx.OnStart(func(ctx context.Context,
Expand Down
48 changes: 48 additions & 0 deletions nodebuilder/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,21 @@ type Module interface {
srcValAddr,
dstValAddr state.ValAddress,
) (*types.QueryRedelegationsResponse, error)

GrantFee(
ctx context.Context,
grantee state.AccAddress,
amount,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error)

RevokeGrantFee(
ctx context.Context,
grantee state.AccAddress,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error)
}

// API is a wrapper around Module for the RPC.
Expand Down Expand Up @@ -160,6 +175,20 @@ type API struct {
srcValAddr,
dstValAddr state.ValAddress,
) (*types.QueryRedelegationsResponse, error) `perm:"read"`
GrantFee func(
ctx context.Context,
grantee state.AccAddress,
amount,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error) `perm:"write"`

RevokeGrantFee func(
ctx context.Context,
grantee state.AccAddress,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error) `perm:"write"`
}
}

Expand Down Expand Up @@ -256,3 +285,22 @@ func (api *API) QueryRedelegations(
func (api *API) Balance(ctx context.Context) (*state.Balance, error) {
return api.Internal.Balance(ctx)
}

func (api *API) GrantFee(
ctx context.Context,
grantee state.AccAddress,
amount,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error) {
return api.Internal.GrantFee(ctx, grantee, amount, fee, gasLim)
}

func (api *API) RevokeGrantFee(
ctx context.Context,
grantee state.AccAddress,
fee state.Int,
gasLim uint64,
) (*state.TxResponse, error) {
return api.Internal.RevokeGrantFee(ctx, grantee, fee, gasLim)
}
19 changes: 19 additions & 0 deletions nodebuilder/state/stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,22 @@ func (s stubbedStateModule) QueryRedelegations(
) (*types.QueryRedelegationsResponse, error) {
return nil, ErrNoStateAccess
}

func (s stubbedStateModule) GrantFee(
_ context.Context,
_ state.AccAddress,
_,
_ state.Int,
_ uint64,
) (*state.TxResponse, error) {
return nil, ErrNoStateAccess
}

func (s stubbedStateModule) RevokeGrantFee(
_ context.Context,
_ state.AccAddress,
_ state.Int,
_ uint64,
) (*state.TxResponse, error) {
return nil, ErrNoStateAccess
}
Loading

0 comments on commit 332739f

Please sign in to comment.