Skip to content

Commit

Permalink
[backport] chore: Allow running of jailed fp (#260) (#265)
Browse files Browse the repository at this point in the history
Closes #259. This allows jailed fps to still be able to send randomness
and it could start voting immdiately after unjailing.
  • Loading branch information
gitferry authored Jan 6, 2025
1 parent c9ce873 commit 5ed8470
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Improvements

* [#253](https://github.com/babylonlabs-io/finality-provider/issues/253) Refactor to start from the last finalized height
* [#260](https://github.com/babylonlabs-io/finality-provider/pull/260) Allow running of jailed fp

## v0.14.2

Expand Down
7 changes: 0 additions & 7 deletions finality-provider/service/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -544,13 +544,6 @@ func (app *FinalityProviderApp) setFinalityProviderSlashed(fpi *FinalityProvider
}
}

func (app *FinalityProviderApp) setFinalityProviderJailed(fpi *FinalityProviderInstance) {
fpi.MustSetStatus(proto.FinalityProviderStatus_JAILED)
if err := app.removeFinalityProviderInstance(); err != nil {
panic(fmt.Errorf("failed to terminate a jailed finality-provider %s: %w", fpi.GetBtcPkHex(), err))
}
}

// NOTE: this is not safe in production, so only used for testing purpose
func (app *FinalityProviderApp) getFpPrivKey(fpPk []byte) (*btcec.PrivateKey, error) {
record, err := app.eotsManager.KeyRecord(fpPk, "")
Expand Down
12 changes: 9 additions & 3 deletions finality-provider/service/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ func FuzzUnjailFinalityProvider(f *testing.F) {
fpCfg := config.DefaultConfigWithHome(fpHomeDir)
// use shorter interval for the test to end faster
fpCfg.SubmissionRetryInterval = time.Millisecond * 10
fpCfg.SignatureSubmissionInterval = time.Millisecond * 10

blkInfo := &types.BlockInfo{Height: currentHeight}

Expand All @@ -230,12 +231,17 @@ func FuzzUnjailFinalityProvider(f *testing.F) {

expectedTxHash := datagen.GenRandomHexStr(r, 32)
mockClientController.EXPECT().UnjailFinalityProvider(fpPk.MustToBTCPK()).Return(&types.TxResponse{TxHash: expectedTxHash}, nil)
err := app.StartFinalityProvider(fpPk, "")
require.NoError(t, err)
fpIns, err := app.GetFinalityProviderInstance()
require.NoError(t, err)
require.True(t, fpIns.IsJailed())
res, err := app.UnjailFinalityProvider(fpPk)
require.NoError(t, err)
require.Equal(t, expectedTxHash, res.TxHash)
fpInfo, err := app.GetFinalityProviderInfo(fpPk)
require.NoError(t, err)
require.Equal(t, proto.FinalityProviderStatus_INACTIVE.String(), fpInfo.GetStatus())
require.Eventually(t, func() bool {
return !fpIns.IsJailed()
}, eventuallyWaitTimeOut, eventuallyPollTime)
})
}

Expand Down
11 changes: 5 additions & 6 deletions finality-provider/service/event_loops.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ func (app *FinalityProviderApp) monitorCriticalErr() {
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()))
continue
}
if errors.Is(criticalErr.err, ErrFinalityProviderJailed) {
app.setFinalityProviderJailed(fpi)
app.logger.Debug("the finality-provider has been jailed",
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()))
continue
}
app.logger.Fatal(instanceTerminatingMsg,
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()), zap.Error(criticalErr.err))
case <-app.quit:
Expand Down Expand Up @@ -177,6 +171,11 @@ func (app *FinalityProviderApp) unjailFpLoop() {
zap.String("txHash", res.TxHash),
)

// set the status to INACTIVE by default
// the status will be changed to ACTIVE
// if it has voting power for the next height
app.fps.MustSetFpStatus(req.btcPubKey.MustToBTCPK(), proto.FinalityProviderStatus_INACTIVE)

req.successResponse <- &UnjailFinalityProviderResponse{
TxHash: res.TxHash,
}
Expand Down
35 changes: 32 additions & 3 deletions finality-provider/service/fp_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func NewFinalityProviderInstance(
return nil, fmt.Errorf("failed to retrieve the finality provider %s from DB: %w", fpPk.MarshalHex(), err)
}

if !sfp.ShouldStart() {
return nil, fmt.Errorf("the finality provider instance cannot be initiated with status %s", sfp.Status.String())
if sfp.Status == proto.FinalityProviderStatus_SLASHED {
return nil, fmt.Errorf("the finality provider instance is already slashed")
}

return newFinalityProviderInstanceFromStore(sfp, cfg, s, prStore, cc, em, metrics, passphrase, errChan, logger)
Expand Down Expand Up @@ -109,7 +109,8 @@ func (fp *FinalityProviderInstance) Start() error {
}

if fp.IsJailed() {
return fmt.Errorf("%w: %s", ErrFinalityProviderJailed, fp.GetBtcPkHex())
fp.logger.Warn("the finality provider is jailed",
zap.String("pk", fp.GetBtcPkHex()))
}

startHeight, err := fp.DetermineStartHeight()
Expand Down Expand Up @@ -163,7 +164,19 @@ func (fp *FinalityProviderInstance) IsRunning() bool {
return fp.isStarted.Load()
}

// IsJailed returns true if fp is JAILED
// NOTE: it retrieves the the status from the db to
// ensure status is up-to-date
func (fp *FinalityProviderInstance) IsJailed() bool {
storedFp, err := fp.fpState.s.GetFinalityProvider(fp.GetBtcPk())
if err != nil {
panic(fmt.Errorf("failed to retrieve the finality provider %s from db: %w", fp.GetBtcPkHex(), err))
}

if storedFp.Status != fp.GetStatus() {
fp.MustSetStatus(storedFp.Status)
}

return fp.GetStatus() == proto.FinalityProviderStatus_JAILED
}

Expand All @@ -178,6 +191,15 @@ func (fp *FinalityProviderInstance) finalitySigSubmissionLoop() {
if len(pollerBlocks) == 0 {
continue
}

if fp.IsJailed() {
fp.logger.Warn("the finality-provider is jailed",
zap.String("pk", fp.GetBtcPkHex()),
)

continue
}

targetHeight := pollerBlocks[len(pollerBlocks)-1].Height
fp.logger.Debug("the finality-provider received new block(s), start processing",
zap.String("pk", fp.GetBtcPkHex()),
Expand All @@ -198,6 +220,13 @@ func (fp *FinalityProviderInstance) finalitySigSubmissionLoop() {
res, err := fp.retrySubmitSigsUntilFinalized(processedBlocks)
if err != nil {
fp.metrics.IncrementFpTotalFailedVotes(fp.GetBtcPkHex())
if errors.Is(err, ErrFinalityProviderJailed) {
fp.MustSetStatus(proto.FinalityProviderStatus_JAILED)
fp.logger.Debug("the finality-provider has been jailed",
zap.String("pk", fp.GetBtcPkHex()))

continue
}
if !errors.Is(err, ErrFinalityProviderShutDown) {
fp.reportCriticalErr(err)
}
Expand Down
14 changes: 0 additions & 14 deletions finality-provider/store/storedfp.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,3 @@ func (sfp *StoredFinalityProvider) ToFinalityProviderInfo() *proto.FinalityProvi
Status: sfp.Status.String(),
}
}

// ShouldStart returns true if the finality provider should start his instance
// based on the current status of the finality provider.
//
// It returns false if the status is either 'REGISTERED', 'JAILED' or 'SLASHED'.
// It returns true for all the other status.
func (sfp *StoredFinalityProvider) ShouldStart() bool {
if sfp.Status == proto.FinalityProviderStatus_SLASHED ||
sfp.Status == proto.FinalityProviderStatus_JAILED {
return false
}

return true
}
54 changes: 0 additions & 54 deletions finality-provider/store/storedfp_test.go

This file was deleted.

0 comments on commit 5ed8470

Please sign in to comment.