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(cmd): edit finality provider description #90

Merged
merged 19 commits into from
Oct 15, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

### Misc Improvements

* [#90](https://github.com/babylonlabs-io/finality-provider/pull/90) CLI edit finality provider
* [#91](https://github.com/babylonlabs-io/finality-provider/pull/91) Go releaser setup
and move changelog reminder out
72 changes: 69 additions & 3 deletions clientcontroller/babylon.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package clientcontroller
import (
"context"
"fmt"
"github.com/babylonlabs-io/finality-provider/finality-provider/proto"
"strings"
"time"

sdkErr "cosmossdk.io/errors"
Expand All @@ -13,6 +15,8 @@ import (
btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types"
btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
finalitytypes "github.com/babylonlabs-io/babylon/x/finality/types"
fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config"
"github.com/babylonlabs-io/finality-provider/types"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
Expand All @@ -23,9 +27,7 @@ import (
sttypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/relayer/v2/relayer/provider"
"go.uber.org/zap"

fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config"
"github.com/babylonlabs-io/finality-provider/types"
protobuf "google.golang.org/protobuf/proto"
)

var _ ClientController = &BabylonController{}
Expand Down Expand Up @@ -510,6 +512,70 @@ func (bc *BabylonController) QueryFinalityProviders() ([]*btcstakingtypes.Finali
return fps, nil
}

func (bc *BabylonController) QueryFinalityProvider(fpPk *btcec.PublicKey) (*btcstakingtypes.QueryFinalityProviderResponse, error) {
fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk)
res, err := bc.bbnClient.QueryClient.FinalityProvider(fpPubKey.MarshalHex())
if err != nil {
return nil, fmt.Errorf("failed to query the finality provider %s: %v", fpPubKey.MarshalHex(), err)
}

return res, nil
}

func (bc *BabylonController) EditFinalityProvider(fpPk *btcec.PublicKey,
rate *sdkmath.LegacyDec, description []byte) (*btcstakingtypes.MsgEditFinalityProvider, error) {
var reqDesc proto.Description
if err := protobuf.Unmarshal(description, &reqDesc); err != nil {
return nil, err
}
fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk)

fpRes, err := bc.QueryFinalityProvider(fpPk)
Lazar955 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, err
}

if !strings.EqualFold(fpRes.FinalityProvider.Addr, bc.mustGetTxSigner()) {
return nil, fmt.Errorf("the signer does not correspond to the finality provider's "+
"Babylon address, expected %s got %s", bc.mustGetTxSigner(), fpRes.FinalityProvider.Addr)
}

getValueOrDefault := func(reqValue, defaultValue string) string {
if reqValue != "" {
return reqValue
}
return defaultValue
}

resDesc := fpRes.FinalityProvider.Description

desc := &sttypes.Description{
Moniker: getValueOrDefault(reqDesc.Moniker, resDesc.Moniker),
Identity: getValueOrDefault(reqDesc.Identity, resDesc.Identity),
Website: getValueOrDefault(reqDesc.Website, resDesc.Website),
SecurityContact: getValueOrDefault(reqDesc.SecurityContact, resDesc.SecurityContact),
Details: getValueOrDefault(reqDesc.Details, resDesc.Details),
}

msg := &btcstakingtypes.MsgEditFinalityProvider{
Addr: bc.mustGetTxSigner(),
BtcPk: fpPubKey.MustMarshal(),
Description: desc,
Commission: fpRes.FinalityProvider.Commission,
}

if rate != nil {
msg.Commission = rate
}

_, err = bc.reliablySendMsg(msg, emptyErrs, emptyErrs)
if err != nil {
return nil, fmt.Errorf("failed to query the finality provider %s: %v", fpPk.SerializeCompressed(), err)
}

return msg, nil
}

func (bc *BabylonController) QueryBtcLightClientTip() (*btclctypes.BTCHeaderInfoResponse, error) {
res, err := bc.bbnClient.QueryClient.BTCHeaderChainTip()
if err != nil {
Expand Down
7 changes: 5 additions & 2 deletions clientcontroller/interface.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package clientcontroller

import (
"fmt"

"cosmossdk.io/math"
"fmt"
btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/chaincfg"
Expand Down Expand Up @@ -49,6 +49,9 @@ type ClientController interface {
// QueryFinalityProviderSlashedOrJailed queries if the finality provider is slashed or jailed
QueryFinalityProviderSlashedOrJailed(fpPk *btcec.PublicKey) (slashed bool, jailed bool, err error)

// EditFinalityProvider edits description and commission of a finality provider
EditFinalityProvider(fpPk *btcec.PublicKey, commission *math.LegacyDec, description []byte) (*btcstakingtypes.MsgEditFinalityProvider, error)

// QueryLatestFinalizedBlocks returns the latest finalized blocks
QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error)

Expand Down
77 changes: 73 additions & 4 deletions finality-provider/cmd/fpd/daemon/daemon_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,20 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/babylonlabs-io/finality-provider/finality-provider/proto"
"strconv"

"cosmossdk.io/math"
"github.com/babylonlabs-io/babylon/types"
bbntypes "github.com/babylonlabs-io/babylon/types"
fpcmd "github.com/babylonlabs-io/finality-provider/finality-provider/cmd"
fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config"
dc "github.com/babylonlabs-io/finality-provider/finality-provider/service/client"
"github.com/cosmos/cosmos-sdk/client"
sdkflags "github.com/cosmos/cosmos-sdk/client/flags"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

fpcmd "github.com/babylonlabs-io/finality-provider/finality-provider/cmd"
fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config"
dc "github.com/babylonlabs-io/finality-provider/finality-provider/service/client"
)

var (
Expand Down Expand Up @@ -446,6 +446,75 @@ func runCommandAddFinalitySig(cmd *cobra.Command, args []string) error {
return nil
}

// CommandEditFinalityDescription edits description of finality provider
func CommandEditFinalityDescription() *cobra.Command {
var cmd = &cobra.Command{
Use: "edit-finality-provider [btc_pk]",
Aliases: []string{"efp"},
Short: "Edit finality provider data without resetting unchanged fields",
Long: "Edit the details of a finality provider using the specified BTC public key. " +
"\nThe provided [btc_pk] must correspond to the Babylon address controlled by the key specified in fpd.conf. " +
"\nIf one or more optional flags are passed (such as --moniker, --website, etc.), " +
"the corresponding values are updated, while unchanged fields retain their current values from the Babylon Node.",
Lazar955 marked this conversation as resolved.
Show resolved Hide resolved
Example: fmt.Sprintf(`fpd edit-finality-provider [btc_pk] --daemon-address %s --moniker "new-moniker"`, defaultFpdDaemonAddress),
Args: cobra.ExactArgs(1),
RunE: runCommandEditFinalityDescription,
}
cmd.Flags().String(fpdDaemonAddressFlag, defaultFpdDaemonAddress, "The RPC server address of fpd")
cmd.Flags().String(monikerFlag, "", "The finality provider's (optional) moniker")
cmd.Flags().String(websiteFlag, "", "The finality provider's (optional) website")
cmd.Flags().String(securityContactFlag, "", "The finality provider's (optional) security contact email")
cmd.Flags().String(detailsFlag, "", "The finality provider's (optional) details")
cmd.Flags().String(identityFlag, "", "The (optional) identity signature (ex. UPort or Keybase)")
cmd.Flags().String(commissionRateFlag, "", "The (optional) commission rate percentage (ex. 0.2)")

return cmd
}

func runCommandEditFinalityDescription(cmd *cobra.Command, args []string) error {
fpPk, err := bbntypes.NewBIP340PubKeyFromHex(args[0])
if err != nil {
return err
}

flags := cmd.Flags()
daemonAddress, err := flags.GetString(fpdDaemonAddressFlag)
if err != nil {
return fmt.Errorf("failed to read flag %s: %w", fpdDaemonAddressFlag, err)
}

grpcClient, cleanUp, err := dc.NewFinalityProviderServiceGRpcClient(daemonAddress)
if err != nil {
return err
}
defer func() {
if err := cleanUp(); err != nil {
fmt.Printf("Failed to clean up grpc client: %v\n", err)
}
}()

moniker, _ := cmd.Flags().GetString(monikerFlag)
website, _ := cmd.Flags().GetString(websiteFlag)
securityContact, _ := cmd.Flags().GetString(securityContactFlag)
details, _ := cmd.Flags().GetString(detailsFlag)
identity, _ := cmd.Flags().GetString(identityFlag)
rate, _ := cmd.Flags().GetString(commissionRateFlag)

desc := &proto.Description{
Moniker: moniker,
Identity: identity,
Website: website,
SecurityContact: securityContact,
Details: details,
}

if err := grpcClient.EditFinalityProvider(cmd.Context(), fpPk, desc, rate); err != nil {
return fmt.Errorf("failed to edit finality provider %v err %v", fpPk.MarshalHex(), err)
}

return nil
}

func printRespJSON(resp interface{}) {
jsonBytes, err := json.MarshalIndent(resp, "", " ")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion finality-provider/cmd/fpd/daemon/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@ const (
websiteFlag = "website"
securityContactFlag = "security-contact"
detailsFlag = "details"
commissionRateFlag = "commission"
commissionRateFlag = "commission-rate"
)
1 change: 1 addition & 0 deletions finality-provider/cmd/fpd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func main() {
daemon.CommandGetDaemonInfo(), daemon.CommandCreateFP(), daemon.CommandLsFP(),
daemon.CommandInfoFP(), daemon.CommandRegisterFP(), daemon.CommandAddFinalitySig(),
daemon.CommandExportFP(), daemon.CommandTxs(), daemon.CommandUnjailFP(),
daemon.CommandEditFinalityDescription(),
)

if err := cmd.Execute(); err != nil {
Expand Down
Loading
Loading