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(state): enable fee granting #3304

Merged
merged 11 commits into from
Apr 16, 2024
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.",
)
vgonkivs marked this conversation as resolved.
Show resolved Hide resolved
}

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" +
vgonkivs marked this conversation as resolved.
Show resolved Hide resolved
"Grantee can spend any amount of tokens in case the spend limit is not set.",
vgonkivs marked this conversation as resolved.
Show resolved Hide resolved
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(
renaynay marked this conversation as resolved.
Show resolved Hide resolved
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
Loading