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

chore: keep sync fp status #52

Merged
merged 15 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions clientcontroller/babylon.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ func NewBabylonController(

bbnConfig := fpcfg.BBNConfigToBabylonConfig(cfg)

if err := bbnConfig.Validate(); err != nil {
return nil, fmt.Errorf("invalid config for Babylon client: %w", err)
}
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved

bc, err := bbnclient.New(
&bbnConfig,
logger,
Expand All @@ -59,6 +55,12 @@ func NewBabylonController(
return nil, fmt.Errorf("failed to create Babylon client: %w", err)
}

// makes sure that the key in config really exists and it is a valid bech 32 addr
// to allow using mustGetTxSigner
if _, err := bc.GetAddr(); err != nil {
return nil, err
}

return &BabylonController{
bc,
cfg,
Expand Down
5 changes: 0 additions & 5 deletions finality-provider/cmd/fpd/daemon/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,6 @@ func loadApp(
return nil, fmt.Errorf("failed to create finality-provider app: %v", err)
}

// sync finality-provider status
if err := fpApp.SyncFinalityProviderStatus(); err != nil {
return nil, fmt.Errorf("failed to sync finality-provider status: %w", err)
}

return fpApp, nil
}

Expand Down
5 changes: 3 additions & 2 deletions finality-provider/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
defaultRandomInterval = 30 * time.Second
defaultSubmitRetryInterval = 1 * time.Second
defaultFastSyncInterval = 10 * time.Second
defaultSyncFpStatusInterval = 30 * time.Second
defaultFastSyncLimit = 10
defaultFastSyncGap = 3
defaultMaxSubmissionRetries = 20
Expand Down Expand Up @@ -69,7 +70,7 @@ type Config struct {
FastSyncGap uint64 `long:"fastsyncgap" description:"The block gap that will trigger the fast sync"`
EOTSManagerAddress string `long:"eotsmanageraddress" description:"The address of the remote EOTS manager; Empty if the EOTS manager is running locally"`
MaxNumFinalityProviders uint32 `long:"maxnumfinalityproviders" description:"The maximum number of finality-provider instances running concurrently within the daemon"`
MinutesToWaitForConsumer uint32 `long:"minuteswaitforconsumer" description:"The number of minutes it should wait for the consumer chain to be available, before stop the app"`
SyncFpStatusInterval time.Duration `long:"syncfpstatusinterval" description:"The duration of time that it should sync FP status with the client blockchain"`

BitcoinNetwork string `long:"bitcoinnetwork" description:"Bitcoin network to run on" choise:"mainnet" choice:"regtest" choice:"testnet" choice:"simnet" choice:"signet"`

Expand Down Expand Up @@ -113,7 +114,7 @@ func DefaultConfigWithHome(homePath string) Config {
RpcListener: DefaultRpcListener,
MaxNumFinalityProviders: defaultMaxNumFinalityProviders,
Metrics: metrics.DefaultFpConfig(),
MinutesToWaitForConsumer: 60 * 24 * 7, // one week in minutes
SyncFpStatusInterval: defaultSyncFpStatusInterval,
}

if err := cfg.Validate(); err != nil {
Expand Down
95 changes: 47 additions & 48 deletions finality-provider/service/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"time"

sdkmath "cosmossdk.io/math"
"github.com/avast/retry-go/v4"
bbntypes "github.com/babylonlabs-io/babylon/types"
bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
"github.com/btcsuite/btcd/btcec/v2"
Expand Down Expand Up @@ -72,7 +71,6 @@ func NewFinalityProviderAppFromConfig(
}

logger.Info("successfully connected to a remote EOTS manager", zap.String("address", cfg.EOTSManagerAddress))

return NewFinalityProviderApp(cfg, cc, em, db, logger)
}

Expand Down Expand Up @@ -148,6 +146,11 @@ func (app *FinalityProviderApp) GetInput() *strings.Reader {
return app.input
}

// Logger returns the current logger of FP app.
func (app *FinalityProviderApp) Logger() *zap.Logger {
return app.logger
}

func (app *FinalityProviderApp) ListFinalityProviderInstances() []*FinalityProviderInstance {
return app.fpManager.ListFinalityProviderInstances()
}
Expand Down Expand Up @@ -239,29 +242,7 @@ func (app *FinalityProviderApp) getFpPrivKey(fpPk []byte) (*btcec.PrivateKey, er

// SyncFinalityProviderStatus syncs the status of the finality-providers
func (app *FinalityProviderApp) SyncFinalityProviderStatus() error {
var (
latestBlock *types.BlockInfo
err error
)

attempts := uint(app.config.MinutesToWaitForConsumer)
err = retry.Do(func() error {
latestBlock, err = app.cc.QueryBestBlock()
if err != nil {
return err
}
return nil
}, retry.OnRetry(func(n uint, err error) {
app.logger.Debug(
"failed to query the consumer chain for the latest block",
zap.Uint("attempt", n+1),
zap.Uint("max_attempts", attempts),
zap.Error(err),
)
// waits for consumer chain to become online for one week
// usefull to turn fpd on before the consumer chain node is available
// and waiting for the consumer node to become available to start.
}), retry.Attempts(attempts), retry.Delay(time.Minute), RtyErr)
latestBlock, err := app.cc.QueryBestBlock()
if err != nil {
return err
}
Expand All @@ -278,28 +259,18 @@ func (app *FinalityProviderApp) SyncFinalityProviderStatus() error {
continue
}

if vp > 0 {
// voting power > 0 then set the status to ACTIVE
err = app.fps.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_ACTIVE)
if err != nil {
return err
}
} else if vp == 0 {
// voting power == 0 then set status depending on previous status
switch fp.Status {
case proto.FinalityProviderStatus_CREATED:
// previous status is CREATED then set to REGISTERED
err = app.fps.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_REGISTERED)
if err != nil {
return err
}
case proto.FinalityProviderStatus_ACTIVE:
// previous status is ACTIVE then set to INACTIVE
err = app.fps.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_INACTIVE)
if err != nil {
return err
}
}
if !fp.ShouldSyncStatusFromVotingPower(vp) {
continue
}

bip340PubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fp.BtcPk)
if app.fpManager.IsFinalityProviderRunning(bip340PubKey) {
// if it is running, no need to update status
continue
}

if err := app.fps.UpdateFpStatusFromVotingPower(vp, fp); err != nil {
return err
}
}

Expand All @@ -312,7 +283,8 @@ func (app *FinalityProviderApp) Start() error {
app.startOnce.Do(func() {
app.logger.Info("Starting FinalityProviderApp")

app.wg.Add(3)
app.wg.Add(4)
go app.syncChainFpStatusLoop()
go app.eventLoop()
go app.registrationLoop()
go app.metricsUpdateLoop()
Expand Down Expand Up @@ -682,3 +654,30 @@ func (app *FinalityProviderApp) metricsUpdateLoop() {
}
}
}

func (app *FinalityProviderApp) syncChainFpStatusLoop() {
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
defer app.wg.Done()

interval := app.config.SyncFpStatusInterval
app.logger.Info(
"starting sync FP status loop",
zap.Float64("interval seconds", interval.Seconds()),
)
syncFpStatusTicker := time.NewTicker(interval)

for {
select {
case <-syncFpStatusTicker.C:
// sync finality-provider status
if err := app.SyncFinalityProviderStatus(); err != nil {
app.Logger().Error("failed to sync finality-provider status", zap.Error(err))
continue
}

case <-app.quit:
syncFpStatusTicker.Stop()
app.logger.Info("exiting sync FP status loop")
return
}
}
}
8 changes: 5 additions & 3 deletions finality-provider/service/fp_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func (ce *CriticalError) Error() string {
type FinalityProviderManager struct {
isStarted *atomic.Bool

// mutex to acess map of fp instances (fpis)
mu sync.Mutex
wg sync.WaitGroup

Expand Down Expand Up @@ -247,9 +248,11 @@ func (fpm *FinalityProviderManager) StartAll() error {

for _, fp := range storedFps {
if fp.Status == proto.FinalityProviderStatus_CREATED || fp.Status == proto.FinalityProviderStatus_SLASHED {
fpm.logger.Info("the finality provider cannot be started with status",
fpm.logger.Info(
"the finality provider cannot be started with status",
zap.String("eots-pk", fp.GetBIP340BTCPK().MarshalHex()),
zap.String("status", fp.Status.String()))
zap.String("status", fp.Status.String()),
)
continue
}
if err := fpm.StartFinalityProvider(fp.GetBIP340BTCPK(), ""); err != nil {
Expand All @@ -266,7 +269,6 @@ func (fpm *FinalityProviderManager) Stop() error {
}

var stopErr error

for _, fpi := range fpm.fpis {
if !fpi.IsRunning() {
continue
Expand Down
23 changes: 23 additions & 0 deletions finality-provider/store/fpstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,29 @@ func (s *FinalityProviderStore) SetFpStatus(btcPk *btcec.PublicKey, status proto
return s.setFinalityProviderState(btcPk, setFpStatus)
}

// UpdateFpStatusFromVotingPower based on the current voting power of the finality provider
// updates the status, if it has some voting power, sets to active
func (s *FinalityProviderStore) UpdateFpStatusFromVotingPower(
vp uint64,
fp *StoredFinalityProvider,
) error {
if vp > 0 {
// voting power > 0 then set the status to ACTIVE
return s.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_ACTIVE)
}

// voting power == 0 then set status depending on previous status
switch fp.Status {
case proto.FinalityProviderStatus_CREATED:
// previous status is CREATED then set to REGISTERED
return s.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_REGISTERED)
case proto.FinalityProviderStatus_ACTIVE:
// previous status is ACTIVE then set to INACTIVE
return s.SetFpStatus(fp.BtcPk, proto.FinalityProviderStatus_INACTIVE)
}
return nil
}

// SetFpLastVotedHeight sets the last voted height to the stored last voted height and last processed height
// only if it is larger than the stored one. This is to ensure the stored state to increase monotonically
func (s *FinalityProviderStore) SetFpLastVotedHeight(btcPk *btcec.PublicKey, lastVotedHeight uint64) error {
Expand Down
11 changes: 11 additions & 0 deletions finality-provider/store/storedfp.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,14 @@ func (sfp *StoredFinalityProvider) ToFinalityProviderInfo() *proto.FinalityProvi
Status: sfp.Status.String(),
}
}

// ShouldSyncStatusFromVotingPower returns true if it should modify the status based on the
// blockchain data.
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
func (sfp *StoredFinalityProvider) ShouldSyncStatusFromVotingPower(vp uint64) bool {
if vp > 0 {
return true
}

return sfp.Status == proto.FinalityProviderStatus_CREATED ||
sfp.Status == proto.FinalityProviderStatus_ACTIVE
}
Loading