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
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
2 changes: 2 additions & 0 deletions nodebuilder/state/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ var defaultKeyringBackend = keyring.BackendTest
type Config struct {
KeyringAccName string
KeyringBackend string
GranterAddress string
}

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

Expand Down
9 changes: 5 additions & 4 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],
) (*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]{
granterEnabled string,
) (*state.CoreAccessor, Module, *modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader], error) {
ca, err := state.NewCoreAccessor(signer, sync, corecfg.IP, corecfg.RPCPort, corecfg.GRPCPort, granterEnabled)
sBreaker := &modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]{
Service: ca,
FraudType: byzantine.BadEncoding,
FraudServ: fraudServ,
}
return ca, ca, sBreaker, err
}
5 changes: 5 additions & 0 deletions nodebuilder/state/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
var (
keyringAccNameFlag = "keyring.accname"
keyringBackendFlag = "keyring.backend"

granterAddressFlag = "granter.address"
)

// Flags gives a set of hardcoded State flags.
Expand All @@ -21,6 +23,8 @@ 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, "", "External node's address that will pay for all transactions, submitted by "+
"the local node.")
vgonkivs marked this conversation as resolved.
Show resolved Hide resolved
return flags
}

Expand All @@ -32,4 +36,5 @@ func ParseFlags(cmd *cobra.Command, cfg *Config) {
}

cfg.KeyringBackend = cmd.Flag(keyringBackendFlag).Value.String()
cfg.GranterAddress = cmd.Flag(granterAddressFlag).Value.String()
}
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.

4 changes: 2 additions & 2 deletions nodebuilder/state/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ func ConstructModule(tp node.Type, cfg *Config, coreCfg *core.Config) fx.Option

baseComponents := fx.Options(
fx.Supply(*cfg),
fx.Supply(cfg.GranterAddress),
vgonkivs marked this conversation as resolved.
Show resolved Hide resolved
fx.Error(cfgErr),
fxutil.ProvideIf(coreCfg.IsEndpointConfigured(), fx.Annotate(
coreAccessor,
fxutil.ProvideIf(coreCfg.IsEndpointConfigured(), fx.Annotate(coreAccessor,
fx.OnStart(func(ctx context.Context,
breaker *modfraud.ServiceBreaker[*state.CoreAccessor, *header.ExtendedHeader]) error {
return breaker.Start(ctx)
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