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: accomodate ADR-25 to add jailed status to fp instance #56

Merged
merged 5 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 3 additions & 5 deletions clientcontroller/babylon.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,14 @@ func (bc *BabylonController) SubmitBatchFinalitySigs(
return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil
}

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

slashed := res.FinalityProvider.SlashedBtcHeight > 0

return slashed, nil
return res.FinalityProvider.SlashedBtcHeight > 0, res.FinalityProvider.Jailed, nil
}

// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height
Expand Down
4 changes: 2 additions & 2 deletions clientcontroller/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ type ClientController interface {
// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height
QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error)

// QueryFinalityProviderSlashed queries if the finality provider is slashed
QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error)
// QueryFinalityProviderSlashedOrJailed queries if the finality provider is slashed or jailed
QueryFinalityProviderSlashedOrJailed(fpPk *btcec.PublicKey) (slashed bool, jailed bool, err error)

// QueryLatestFinalizedBlocks returns the latest finalized blocks
QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error)
Expand Down
1 change: 1 addition & 0 deletions clientcontroller/retry_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var unrecoverableErrors = []*sdkErr.Error{
finalitytypes.ErrPubRandNotFound,
finalitytypes.ErrTooFewPubRand,
btcstakingtypes.ErrFpAlreadySlashed,
btcstakingtypes.ErrFpAlreadyJailed,
}

// IsUnrecoverable returns true when the error is in the unrecoverableErrors list
Expand Down
2 changes: 1 addition & 1 deletion eotsmanager/proto/eotsmanager.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

104 changes: 55 additions & 49 deletions finality-provider/proto/finality_providers.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions finality-provider/proto/finality_providers.proto
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ enum FinalityProviderStatus {
INACTIVE = 3 [(gogoproto.enumvalue_customname) = "INACTIVE"];
// SLASHED defines a finality provider that has been slashed
SLASHED = 4 [(gogoproto.enumvalue_customname) = "SLASHED"];
// JAILED defines a finality provider that has been jailed
JAILED = 5 [(gogoproto.enumvalue_customname) = "JAILED"];
}

message SignMessageFromChainKeyRequest {
Expand Down
9 changes: 5 additions & 4 deletions finality-provider/service/fp_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -907,14 +907,15 @@ func (fp *FinalityProviderInstance) GetVotingPowerWithRetry(height uint64) (uint
return power, nil
}

func (fp *FinalityProviderInstance) GetFinalityProviderSlashedWithRetry() (bool, error) {
func (fp *FinalityProviderInstance) GetFinalityProviderSlashedOrJailedWithRetry() (bool, bool, error) {
var (
slashed bool
jailed bool
err error
)

if err := retry.Do(func() error {
slashed, err = fp.cc.QueryFinalityProviderSlashed(fp.GetBtcPk())
slashed, jailed, err = fp.cc.QueryFinalityProviderSlashedOrJailed(fp.GetBtcPk())
if err != nil {
return err
}
Expand All @@ -927,8 +928,8 @@ func (fp *FinalityProviderInstance) GetFinalityProviderSlashedWithRetry() (bool,
zap.Error(err),
)
})); err != nil {
return false, err
return false, false, err
}

return slashed, nil
return slashed, jailed, nil
}
31 changes: 27 additions & 4 deletions finality-provider/service/fp_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,12 @@ func (fpm *FinalityProviderManager) monitorCriticalErr() {
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()))
continue
}
if strings.Contains(criticalErr.err.Error(), btcstakingtypes.ErrFpAlreadyJailed.Error()) {
fpm.setFinalityProviderJailed(fpi)
fpm.logger.Debug("the finality-provider has been jailed",
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()))
continue
}
fpm.logger.Fatal(instanceTerminatingMsg,
zap.String("pk", criticalErr.fpBtcPk.MarshalHex()), zap.Error(criticalErr.err))
case <-fpm.quit:
Expand Down Expand Up @@ -166,25 +172,35 @@ func (fpm *FinalityProviderManager) monitorStatusUpdate() {
}
continue
}
slashed, err := fpi.GetFinalityProviderSlashedWithRetry()
slashed, jailed, err := fpi.GetFinalityProviderSlashedOrJailedWithRetry()
if err != nil {
fpm.logger.Debug(
"failed to get the slashed height",
"failed to get the slashed or jailed status",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.Error(err),
)
continue
}
// power == 0 and slashed == true, set status to SLASHED and stop and remove the finality-provider instance
// power == 0 and slashed == true, set status to SLASHED, stop, and remove the finality-provider instance
if slashed {
fpm.setFinalityProviderSlashed(fpi)
fpm.logger.Debug(
fpm.logger.Warn(
"the finality-provider is slashed",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.String("old_status", oldStatus.String()),
)
continue
}
// power == 0 and jailed == true, set status to JAILED, stop, and remove the finality-provider instance
if jailed {
fpm.setFinalityProviderJailed(fpi)
fpm.logger.Warn(
"the finality-provider is jailed",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.String("old_status", oldStatus.String()),
)
continue
}
// power == 0 and slashed_height == 0, change to INACTIVE if the current status is ACTIVE
if oldStatus == proto.FinalityProviderStatus_ACTIVE {
fpi.MustSetStatus(proto.FinalityProviderStatus_INACTIVE)
Expand All @@ -208,6 +224,13 @@ func (fpm *FinalityProviderManager) setFinalityProviderSlashed(fpi *FinalityProv
}
}

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

func (fpm *FinalityProviderManager) StartFinalityProvider(fpPk *bbntypes.BIP340PubKey, passphrase string) error {
if !fpm.isStarted.Load() {
fpm.isStarted.Store(true)
Expand Down
20 changes: 15 additions & 5 deletions finality-provider/service/fp_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

var (
eventuallyWaitTimeOut = 1 * time.Second
eventuallyWaitTimeOut = 5 * time.Second
eventuallyPollTime = 10 * time.Millisecond
)

Expand Down Expand Up @@ -61,9 +61,17 @@ func FuzzStatusUpdate(f *testing.F) {
votingPower := uint64(r.Intn(2))
mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes()
mockClientController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes()
var slashedHeight uint64
var isSlashedOrJailed int
if votingPower == 0 {
mockClientController.EXPECT().QueryFinalityProviderSlashed(gomock.Any()).Return(true, nil).AnyTimes()
// 0 means is slashed, 1 means is jailed, 2 means neither slashed nor jailed
isSlashedOrJailed = r.Intn(3)
if isSlashedOrJailed == 0 {
mockClientController.EXPECT().QueryFinalityProviderSlashedOrJailed(gomock.Any()).Return(true, false, nil).AnyTimes()
} else if isSlashedOrJailed == 1 {
mockClientController.EXPECT().QueryFinalityProviderSlashedOrJailed(gomock.Any()).Return(false, true, nil).AnyTimes()
} else {
mockClientController.EXPECT().QueryFinalityProviderSlashedOrJailed(gomock.Any()).Return(false, false, nil).AnyTimes()
}
}

err := vm.StartFinalityProvider(fpPk, passphrase)
Expand All @@ -76,9 +84,11 @@ func FuzzStatusUpdate(f *testing.F) {
if votingPower > 0 {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_ACTIVE)
} else {
if slashedHeight == 0 && fpIns.GetStatus() == proto.FinalityProviderStatus_ACTIVE {
if isSlashedOrJailed == 2 && fpIns.GetStatus() == proto.FinalityProviderStatus_ACTIVE {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_INACTIVE)
} else if slashedHeight > 0 {
} else if isSlashedOrJailed == 1 {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_JAILED)
} else if isSlashedOrJailed == 0 {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_SLASHED)
}
}
Expand Down
Loading
Loading