Skip to content

Commit

Permalink
remove status update loop
Browse files Browse the repository at this point in the history
  • Loading branch information
gitferry committed Dec 18, 2024
1 parent d3a44ab commit 4ca005d
Show file tree
Hide file tree
Showing 10 changed files with 40 additions and 139 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ build-docker:

.PHONY: test
test:
go test ./...
go test -v ./...

test-e2e:
go test -mod=readonly -failfast -timeout=25m -v $(PACKAGES_E2E) -count=1 --tags=e2e
Expand Down Expand Up @@ -139,4 +139,4 @@ release:
else
release:
@echo "Error: GITHUB_TOKEN is not defined. Please define it before running 'make release'."
endif
endif
3 changes: 0 additions & 3 deletions finality-provider/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const (
defaultNumPubRandMax = 100000
defaultMinRandHeightGap = 35000
defaultBatchSubmissionSize = 1000
defaultStatusUpdateInterval = 20 * time.Second
defaultRandomInterval = 30 * time.Second
defaultSubmitRetryInterval = 1 * time.Second
defaultSignatureSubmissionInterval = 1 * time.Second
Expand Down Expand Up @@ -61,7 +60,6 @@ type Config struct {
MaxSubmissionRetries uint32 `long:"maxsubmissionretries" description:"The maximum number of retries to submit finality signature or public randomness"`
EOTSManagerAddress string `long:"eotsmanageraddress" description:"The address of the remote EOTS manager; Empty if the EOTS manager is running locally"`
BatchSubmissionSize uint32 `long:"batchsubmissionsize" description:"The size of a batch in one submission"`
StatusUpdateInterval time.Duration `long:"statusupdateinterval" description:"The interval between each update of finality-provider status"`
RandomnessCommitInterval time.Duration `long:"randomnesscommitinterval" description:"The interval between each attempt to commit public randomness"`
SubmissionRetryInterval time.Duration `long:"submissionretryinterval" description:"The interval between each attempt to submit finality signature or public randomness after a failure"`
SignatureSubmissionInterval time.Duration `long:"signaturesubmissioninterval" description:"The interval between each finality signature(s) submission"`
Expand Down Expand Up @@ -96,7 +94,6 @@ func DefaultConfigWithHome(homePath string) Config {
NumPubRandMax: defaultNumPubRandMax,
TimestampingDelayBlocks: defaultMinRandHeightGap,
BatchSubmissionSize: defaultBatchSubmissionSize,
StatusUpdateInterval: defaultStatusUpdateInterval,
RandomnessCommitInterval: defaultRandomInterval,
SubmissionRetryInterval: defaultSubmitRetryInterval,
SignatureSubmissionInterval: defaultSignatureSubmissionInterval,
Expand Down
3 changes: 1 addition & 2 deletions finality-provider/service/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,9 @@ func (app *FinalityProviderApp) Start() error {
return
}

app.wg.Add(5)
app.wg.Add(4)
go app.metricsUpdateLoop()
go app.monitorCriticalErr()
go app.monitorStatusUpdate()
go app.registrationLoop()
go app.unjailFpLoop()
})
Expand Down
60 changes: 4 additions & 56 deletions finality-provider/service/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
sdkkeyring "github.com/cosmos/cosmos-sdk/crypto/keyring"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

"github.com/babylonlabs-io/finality-provider/clientcontroller"
"github.com/babylonlabs-io/finality-provider/eotsmanager"
Expand All @@ -45,7 +44,7 @@ func FuzzCreateFinalityProvider(f *testing.F) {
f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(seed))

logger := zap.NewNop()
logger := testutil.GetTestLogger(t)
// create an EOTS manager
eotsHomeDir := filepath.Join(t.TempDir(), "eots-home")
eotsCfg := eotscfg.DefaultConfigWithHomePath(eotsHomeDir)
Expand Down Expand Up @@ -189,7 +188,7 @@ func FuzzSyncFinalityProviderStatus(f *testing.F) {
case 1:
expectedStatus = proto.FinalityProviderStatus_JAILED
case 2:
expectedStatus = proto.FinalityProviderStatus_REGISTERED
expectedStatus = proto.FinalityProviderStatus_INACTIVE
}
}

Expand Down Expand Up @@ -242,56 +241,12 @@ func FuzzUnjailFinalityProvider(f *testing.F) {
})
}

func FuzzStatusUpdate(f *testing.F) {
testutil.AddRandomSeedsToFuzzer(f, 10)
f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(seed))

randomStartingHeight := uint64(r.Int63n(100) + 1)
currentHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)

// setup mocks
votingPower := uint64(r.Intn(2))
mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes()
mockClientController.EXPECT().Close().Return(nil).AnyTimes()
mockClientController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return([]*types.BlockInfo{{Height: randomStartingHeight - 1}}, nil).AnyTimes()
mockClientController.EXPECT().QueryFinalityProviderHighestVotedHeight(gomock.Any()).Return(uint64(0), nil).AnyTimes()
mockClientController.EXPECT().QueryLastCommittedPublicRand(gomock.Any(), uint64(1)).Return(nil, nil).AnyTimes()
mockClientController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes()
mockClientController.EXPECT().QueryFinalityProviderSlashedOrJailed(gomock.Any()).Return(false, false, nil).AnyTimes()

// Create randomized config
pathSuffix := datagen.GenRandomHexStr(r, 10)
fpHomeDir := filepath.Join(t.TempDir(), "fp-home", pathSuffix)
fpCfg := config.DefaultConfigWithHome(fpHomeDir)
// use shorter interval for the test to end faster
fpCfg.StatusUpdateInterval = time.Millisecond * 10
fpCfg.SubmissionRetryInterval = time.Millisecond * 10

// Create fp app
app, fpPk, cleanup := startFPAppWithRegisteredFp(t, r, fpHomeDir, &fpCfg, mockClientController)
defer cleanup()

err := app.StartFinalityProvider(fpPk, passphrase)
require.NoError(t, err)
fpIns, err := app.GetFinalityProviderInstance()
require.NoError(t, err)

if votingPower > 0 {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_ACTIVE)
} else {
waitForStatus(t, fpIns, proto.FinalityProviderStatus_INACTIVE)
}
})
}

func FuzzSaveAlreadyRegisteredFinalityProvider(f *testing.F) {
testutil.AddRandomSeedsToFuzzer(f, 10)
f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(seed))

logger := zap.NewNop()
logger := testutil.GetTestLogger(t)
// create an EOTS manager
eotsHomeDir := filepath.Join(t.TempDir(), "eots-home")
eotsCfg := eotscfg.DefaultConfigWithHomePath(eotsHomeDir)
Expand Down Expand Up @@ -376,15 +331,8 @@ func FuzzSaveAlreadyRegisteredFinalityProvider(f *testing.F) {
})
}

func waitForStatus(t *testing.T, fpIns *service.FinalityProviderInstance, s proto.FinalityProviderStatus) {
require.Eventually(t,
func() bool {
return fpIns.GetStatus() == s
}, eventuallyWaitTimeOut, eventuallyPollTime)
}

func startFPAppWithRegisteredFp(t *testing.T, r *rand.Rand, homePath string, cfg *config.Config, cc clientcontroller.ClientController) (*service.FinalityProviderApp, *bbntypes.BIP340PubKey, func()) {
logger := zap.NewNop()
logger := testutil.GetTestLogger(t)
// create an EOTS manager
eotsHomeDir := filepath.Join(t.TempDir(), "eots-home")
eotsCfg := eotscfg.DefaultConfigWithHomePath(eotsHomeDir)
Expand Down
5 changes: 2 additions & 3 deletions finality-provider/service/chain_poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config"
"github.com/babylonlabs-io/finality-provider/finality-provider/service"
Expand Down Expand Up @@ -49,7 +48,7 @@ func FuzzChainPoller_Start(f *testing.F) {
m := metrics.NewFpMetrics()
pollerCfg := fpcfg.DefaultChainPollerConfig()
pollerCfg.PollInterval = 10 * time.Millisecond
poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, m)
poller := service.NewChainPoller(testutil.GetTestLogger(t), &pollerCfg, mockClientController, m)
err := poller.Start(startHeight)
require.NoError(t, err)
defer func() {
Expand Down Expand Up @@ -100,7 +99,7 @@ func FuzzChainPoller_SkipHeight(f *testing.F) {
m := metrics.NewFpMetrics()
pollerCfg := fpcfg.DefaultChainPollerConfig()
pollerCfg.PollInterval = 1 * time.Second
poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, m)
poller := service.NewChainPoller(testutil.GetTestLogger(t), &pollerCfg, mockClientController, m)
// should expect error if the poller is not started
err := poller.SkipToHeight(skipHeight)
require.Error(t, err)
Expand Down
70 changes: 0 additions & 70 deletions finality-provider/service/event_loops.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,76 +44,6 @@ type UnjailFinalityProviderResponse struct {
TxHash string
}

// monitorStatusUpdate periodically check the status of the running finality provider and update
// it accordingly. We update the status by querying the latest voting power and the slashed_height.
// In particular, we perform the following status transitions (REGISTERED, ACTIVE, INACTIVE):
// 1. if power == 0 and status == ACTIVE, change to INACTIVE
// 2. if power > 0, change to ACTIVE
// NOTE: once error occurs, we log and continue as the status update is not critical to the entire program
func (app *FinalityProviderApp) monitorStatusUpdate() {
defer app.wg.Done()

if app.config.StatusUpdateInterval == 0 {
app.logger.Info("the status update is disabled")
return
}

statusUpdateTicker := time.NewTicker(app.config.StatusUpdateInterval)
defer statusUpdateTicker.Stop()

for {
select {
case <-statusUpdateTicker.C:
fpi := app.fpIns
if fpi == nil {
continue
}

latestBlock, err := app.getLatestBlockWithRetry()
if err != nil {
app.logger.Debug("failed to get the latest block", zap.Error(err))
continue
}
oldStatus := fpi.GetStatus()
power, err := fpi.GetVotingPowerWithRetry(latestBlock.Height)
if err != nil {
app.logger.Debug(
"failed to get the voting power",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.Uint64("height", latestBlock.Height),
zap.Error(err),
)
continue
}
// power > 0 (slashed_height must > 0), set status to ACTIVE
if power > 0 {
if oldStatus != proto.FinalityProviderStatus_ACTIVE {
fpi.MustSetStatus(proto.FinalityProviderStatus_ACTIVE)
app.logger.Debug(
"the finality-provider status is changed to ACTIVE",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.String("old_status", oldStatus.String()),
zap.Uint64("power", power),
)
}
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)
app.logger.Debug(
"the finality-provider status is changed to INACTIVE",
zap.String("fp_btc_pk", fpi.GetBtcPkHex()),
zap.String("old_status", oldStatus.String()),
)
}
case <-app.quit:
app.logger.Info("exiting monitor fp status update loop")
return
}
}
}

// event loop for critical errors
func (app *FinalityProviderApp) monitorCriticalErr() {
defer app.wg.Done()
Expand Down
8 changes: 8 additions & 0 deletions finality-provider/service/fp_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,17 @@ func (fp *FinalityProviderInstance) hasVotingPower(b *types.BlockInfo) (bool, er
zap.Uint64("block_height", b.Height),
)

if fp.GetStatus() == proto.FinalityProviderStatus_ACTIVE {
fp.MustSetStatus(proto.FinalityProviderStatus_INACTIVE)
}

return false, nil
}

if fp.GetStatus() == proto.FinalityProviderStatus_INACTIVE {
fp.MustSetStatus(proto.FinalityProviderStatus_ACTIVE)
}

return true, nil
}

Expand Down
3 changes: 1 addition & 2 deletions finality-provider/service/fp_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
ftypes "github.com/babylonlabs-io/babylon/x/finality/types"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

"github.com/babylonlabs-io/finality-provider/clientcontroller"
"github.com/babylonlabs-io/finality-provider/eotsmanager"
Expand Down Expand Up @@ -147,7 +146,7 @@ func startFinalityProviderAppWithRegisteredFp(
startingHeight uint64,
numPubRand uint32,
) (*service.FinalityProviderApp, *service.FinalityProviderInstance, func()) {
logger := zap.NewNop()
logger := testutil.GetTestLogger(t)
// create an EOTS manager
eotsHomeDir := filepath.Join(t.TempDir(), "eots-home")
eotsCfg := eotscfg.DefaultConfigWithHomePath(eotsHomeDir)
Expand Down
6 changes: 5 additions & 1 deletion itest/e2e_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
//go:build e2e
// +build e2e

package e2etest

import (
"encoding/json"
"errors"
"fmt"
"github.com/babylonlabs-io/finality-provider/finality-provider/store"
"log"
"math/rand"
"os"
"testing"
"time"

"github.com/babylonlabs-io/finality-provider/finality-provider/store"

bbntypes "github.com/babylonlabs-io/babylon/types"
bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"

Expand Down
17 changes: 17 additions & 0 deletions testutil/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package testutil

import (
"testing"

"github.com/stretchr/testify/require"
"go.uber.org/zap"
)

func GetTestLogger(t *testing.T) *zap.Logger {
loggerConfig := zap.NewDevelopmentConfig()
loggerConfig.Level = zap.NewAtomicLevelAt(zap.ErrorLevel)
logger, err := loggerConfig.Build()

require.NoError(t, err)
return logger
}

0 comments on commit 4ca005d

Please sign in to comment.