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 test #58

Merged
merged 11 commits into from
Sep 20, 2024
Merged
60 changes: 60 additions & 0 deletions finality-provider/service/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"math/rand"
"os"
"path/filepath"
"strings"
"testing"
"time"

bbntypes "github.com/babylonlabs-io/babylon/types"
bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
Expand Down Expand Up @@ -138,3 +140,61 @@ func FuzzRegisterFinalityProvider(f *testing.F) {
require.Equal(t, true, fpInfo.IsRunning)
})
}

func FuzzSyncFinalityProviderStatus(f *testing.F) {
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
testutil.AddRandomSeedsToFuzzer(f, 10)
f.Fuzz(func(t *testing.T, seed int64) {
r := rand.New(rand.NewSource(2))

logger := zap.NewNop()

// create an EOTS manager
eotsHomeDir := filepath.Join(t.TempDir(), "eots-home")
eotsCfg := eotscfg.DefaultConfigWithHomePath(eotsHomeDir)
dbBackend, err := eotsCfg.DatabaseConfig.GetDbBackend()
require.NoError(t, err)
em, err := eotsmanager.NewLocalEOTSManager(eotsHomeDir, eotsCfg.KeyringBackend, dbBackend, logger)
require.NoError(t, err)
defer func() {
dbBackend.Close()
err = os.RemoveAll(eotsHomeDir)
require.NoError(t, err)
}()

// Create randomized config
fpHomeDir := filepath.Join(t.TempDir(), "fp-home")
fpCfg := config.DefaultConfigWithHome(fpHomeDir)
fpCfg.SyncFpStatusInterval = time.Millisecond * 100
fpdb, err := fpCfg.DatabaseConfig.GetDbBackend()
require.NoError(t, err)

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

blkInfo := &types.BlockInfo{Height: currentHeight}
mockClientController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes()
mockClientController.EXPECT().QueryBestBlock().Return(blkInfo, nil).AnyTimes()
mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), gomock.Any()).Return(uint64(2), nil).AnyTimes()
mockClientController.EXPECT().QueryBlock(gomock.Any()).Return(blkInfo, nil).AnyTimes()

app, err := service.NewFinalityProviderApp(&fpCfg, mockClientController, em, fpdb, logger)
require.NoError(t, err)

err = app.Start()
require.NoError(t, err)
defer func() {
err = app.Stop()
require.NoError(t, err)
}()

fp := testutil.GenStoredFinalityProvider(r, t, app, passphrase, hdPath, nil)

require.Eventually(t, func() bool {
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
fpInfo, err := app.GetFinalityProviderInfo(fp.GetBIP340BTCPK())
require.NoError(t, err)

return strings.EqualFold(fpInfo.Status, proto.FinalityProviderStatus_ACTIVE.String())
}, time.Second*5, time.Millisecond*200, "should eventually become active")
})
}
126 changes: 126 additions & 0 deletions finality-provider/store/fpstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/babylonlabs-io/finality-provider/finality-provider/config"
"github.com/babylonlabs-io/finality-provider/finality-provider/proto"
fpstore "github.com/babylonlabs-io/finality-provider/finality-provider/store"
"github.com/babylonlabs-io/finality-provider/testutil"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -78,3 +79,128 @@ func FuzzFinalityProvidersStore(f *testing.F) {
require.ErrorIs(t, err, fpstore.ErrFinalityProviderNotFound)
})
}

func TestUpdateFpStatusFromVotingPower(t *testing.T) {
r := rand.New(rand.NewSource(10))

tcs := []struct {
name string
fpStoredStatus proto.FinalityProviderStatus
votingPowerOnChain uint64
expStatus proto.FinalityProviderStatus
expErr error
}{
{
"zero vp: Created to Registered",
proto.FinalityProviderStatus_CREATED,
0,
proto.FinalityProviderStatus_REGISTERED,
nil,
},
{
"zero vp: Active to Inactive",
proto.FinalityProviderStatus_ACTIVE,
0,
proto.FinalityProviderStatus_INACTIVE,
nil,
},
{
"zero vp: Slashed to Slashed",
proto.FinalityProviderStatus_SLASHED,
0,
proto.FinalityProviderStatus_SLASHED,
nil,
},
{
"vp > 0: Slashed to Active",
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
proto.FinalityProviderStatus_SLASHED,
15,
proto.FinalityProviderStatus_ACTIVE,
nil,
},
{
"vp > 0: Created to Active",
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
proto.FinalityProviderStatus_CREATED,
1,
proto.FinalityProviderStatus_ACTIVE,
nil,
},
{
"vp > 0: Inactive to Active",
proto.FinalityProviderStatus_INACTIVE,
1,
proto.FinalityProviderStatus_ACTIVE,
nil,
},
{
"err: fp not found and vp > 0",
proto.FinalityProviderStatus_INACTIVE,
1,
proto.FinalityProviderStatus_INACTIVE,
fpstore.ErrFinalityProviderNotFound,
},
{
"err: fp not found and vp == 0 && created",
proto.FinalityProviderStatus_CREATED,
0,
proto.FinalityProviderStatus_SLASHED,
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
fpstore.ErrFinalityProviderNotFound,
},
{
"err: fp not found and vp == 0 && active",
proto.FinalityProviderStatus_ACTIVE,
0,
proto.FinalityProviderStatus_SLASHED,
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
fpstore.ErrFinalityProviderNotFound,
},
}

homePath := t.TempDir()
cfg := config.DefaultDBConfigWithHomePath(homePath)

fpdb, err := cfg.GetDbBackend()
require.NoError(t, err)
fps, err := fpstore.NewFinalityProviderStore(fpdb)
require.NoError(t, err)

defer func() {
err := fpdb.Close()
require.NoError(t, err)
err = os.RemoveAll(homePath)
require.NoError(t, err)
}()

for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
fp := testutil.GenRandomFinalityProvider(r, t)
fp.Status = tc.fpStoredStatus
if tc.expErr == nil {
err = fps.CreateFinalityProvider(
sdk.MustAccAddressFromBech32(fp.FPAddr),
fp.BtcPk,
fp.Description,
fp.Commission,
fp.KeyName,
fp.ChainID,
fp.Pop.BtcSig,
)
require.NoError(t, err)

err = fps.SetFpStatus(fp.BtcPk, fp.Status)
require.NoError(t, err)
}

actStatus, err := fps.UpdateFpStatusFromVotingPower(tc.votingPowerOnChain, fp)
if tc.expErr != nil {
require.EqualError(t, err, tc.expErr.Error())
return
}
require.NoError(t, err)
require.Equal(t, tc.expStatus, actStatus)

storedFp, err := fps.GetFinalityProvider(fp.BtcPk)
require.NoError(t, err)
require.Equal(t, tc.expStatus, storedFp.Status)
})
}
}
124 changes: 124 additions & 0 deletions finality-provider/store/storedfp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package store_test

import (
"math/rand"
"testing"

"github.com/babylonlabs-io/finality-provider/finality-provider/proto"
"github.com/babylonlabs-io/finality-provider/testutil"
"github.com/stretchr/testify/require"
)

func TestShouldStart(t *testing.T) {
tcs := []struct {
name string
currFpStatus proto.FinalityProviderStatus
expShouldStart bool
}{
{
"Created: Should NOT start",
proto.FinalityProviderStatus_CREATED,
false,
},
{
"Slashed: Should NOT start",
proto.FinalityProviderStatus_SLASHED,
false,
},
{
"Inactive: Should start",
proto.FinalityProviderStatus_INACTIVE,
true,
},
{
"Registered: Should start",
proto.FinalityProviderStatus_REGISTERED,
true,
},
{
"Active: Should start",
proto.FinalityProviderStatus_ACTIVE,
true,
},
}

r := rand.New(rand.NewSource(10))
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
fp := testutil.GenRandomFinalityProvider(r, t)
fp.Status = tc.currFpStatus

shouldStart := fp.ShouldStart()
require.Equal(t, tc.expShouldStart, shouldStart)
})
}
}

func TestShouldSyncStatusFromVotingPower(t *testing.T) {
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
tcs := []struct {
name string
votingPowerOnChain uint64
currFpStatus proto.FinalityProviderStatus
expShouldSyncStatus bool
}{
{
"zero vp and Registered: Should NOT sync",
0,
proto.FinalityProviderStatus_REGISTERED,
false,
},
{
"zero vp and Inactive: Should NOT sync",
0,
proto.FinalityProviderStatus_INACTIVE,
false,
},
{
"zero vp and Slashed: Should NOT sync",
0,
proto.FinalityProviderStatus_SLASHED,
false,
},
{
"zero vp and Created: Should sync",
0,
proto.FinalityProviderStatus_CREATED,
true,
},
{
"zero vp and Active: Should sync",
0,
proto.FinalityProviderStatus_ACTIVE,
true,
},
{
"some vp: Should sync",
1,
proto.FinalityProviderStatus_SLASHED,
true,
},
{
"some vp: Should sync from even inactive",
1,
proto.FinalityProviderStatus_INACTIVE,
true,
},
{
"some vp: Should sync even if it is already active",
10,
proto.FinalityProviderStatus_ACTIVE,
true,
},
}

r := rand.New(rand.NewSource(10))
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
fp := testutil.GenRandomFinalityProvider(r, t)
fp.Status = tc.currFpStatus

shouldSync := fp.ShouldSyncStatusFromVotingPower(tc.votingPowerOnChain)
require.Equal(t, tc.expShouldSyncStatus, shouldSync)
})
}
}
Loading