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: add finality activation height #101

Merged
merged 14 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from 13 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
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## Unreleased

### Improvements

* [#101](https://github.com/babylonlabs-io/finality-provider/pull/101) Add finality activation
height check in finality voting and commit pub rand start height

## v0.8.0

### Misc Improvements
### Improvements

* [#97](https://github.com/babylonlabs-io/finality-provider/pull/97) Bump Babylon version to v0.13.0
* [#90](https://github.com/babylonlabs-io/finality-provider/pull/90) CLI edit finality provider
Expand Down
12 changes: 11 additions & 1 deletion clientcontroller/babylon.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package clientcontroller
import (
"context"
"fmt"
"github.com/babylonlabs-io/finality-provider/finality-provider/proto"
"strings"
"time"

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

sdkErr "cosmossdk.io/errors"
sdkmath "cosmossdk.io/math"
bbnclient "github.com/babylonlabs-io/babylon/client/client"
Expand Down Expand Up @@ -387,6 +388,15 @@ func (bc *BabylonController) QueryActivatedHeight() (uint64, error) {
return res.Height, nil
}

func (bc *BabylonController) QueryFinalityActivationBlockHeight() (uint64, error) {
res, err := bc.bbnClient.QueryClient.FinalityParams()
if err != nil {
return 0, fmt.Errorf("failed to query finality params to get finality activation block height: %w", err)
}

return res.FinalityActivationHeight, nil
}

func (bc *BabylonController) QueryBestBlock() (*types.BlockInfo, error) {
blocks, err := bc.queryLatestBlocks(nil, 1, finalitytypes.QueriedBlockStatus_ANY, true)
if err != nil || len(blocks) != 1 {
Expand Down
10 changes: 9 additions & 1 deletion clientcontroller/interface.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package clientcontroller

import (
"cosmossdk.io/math"
"fmt"

"cosmossdk.io/math"
btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
Expand Down Expand Up @@ -71,6 +72,13 @@ type ClientController interface {
// error will be returned if the consumer chain has not been activated
QueryActivatedHeight() (uint64, error)

// QueryFinalityActivationBlockHeight returns the block height of the consumer chain
// starts to accept finality voting and pub rand commit as start height
// error will be returned if the consumer chain failed to get this value
// if the consumer chain wants to accept finality voting at any block height
// the value zero should be returned.
QueryFinalityActivationBlockHeight() (uint64, error)

Close() error
}

Expand Down
1 change: 0 additions & 1 deletion finality-provider/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ func PersistClientCtx(ctx client.Context) func(cmd *cobra.Command, _ []string) e
cmd.SetOut(cmd.OutOrStdout())
cmd.SetErr(cmd.ErrOrStderr())

ctx = ctx.WithCmdContext(cmd.Context())
if err := client.SetCmdClientContextHandler(ctx, cmd); err != nil {
return err
}
Expand Down
20 changes: 11 additions & 9 deletions finality-provider/cmd/cmd_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd_test

import (
"context"
"math/rand"
"path/filepath"
"testing"
Expand All @@ -19,30 +20,31 @@ import (

func TestPersistClientCtx(t *testing.T) {
ctx := client.Context{}
cmd := cobra.Command{}
cmd := &cobra.Command{}
cmd.SetContext(context.Background())
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved

tempDir := t.TempDir()
defaultHome := filepath.Join(tempDir, "defaultHome")

cmd.Flags().String(flags.FlagHome, defaultHome, "The application home directory")
cmd.Flags().String(flags.FlagChainID, "", "chain id")

err := fpcmd.PersistClientCtx(ctx)(&cmd, []string{})
err := fpcmd.PersistClientCtx(ctx)(cmd, []string{})
require.NoError(t, err)

// verify that has the defaults to ctx
ctx = client.GetClientContextFromCmd(&cmd)
ctx = client.GetClientContextFromCmd(cmd)
require.Equal(t, defaultHome, ctx.HomeDir)
require.Equal(t, "", ctx.ChainID)

flagHomeValue := filepath.Join(tempDir, "flagHome")
err = cmd.Flags().Set(flags.FlagHome, flagHomeValue)
require.NoError(t, err)

err = fpcmd.PersistClientCtx(ctx)(&cmd, []string{})
err = fpcmd.PersistClientCtx(ctx)(cmd, []string{})
require.NoError(t, err)

ctx = client.GetClientContextFromCmd(&cmd)
ctx = client.GetClientContextFromCmd(cmd)
require.Equal(t, flagHomeValue, ctx.HomeDir)

r := rand.New(rand.NewSource(10))
Expand All @@ -60,10 +62,10 @@ func TestPersistClientCtx(t *testing.T) {
require.NoError(t, err)

// parses the ctx from cmd with config, should modify the chain ID
err = fpcmd.PersistClientCtx(ctx)(&cmd, []string{})
err = fpcmd.PersistClientCtx(ctx)(cmd, []string{})
require.NoError(t, err)

ctx = client.GetClientContextFromCmd(&cmd)
ctx = client.GetClientContextFromCmd(cmd)
require.Equal(t, flagHomeValue, ctx.HomeDir)
require.Equal(t, randChainID, ctx.ChainID)

Expand All @@ -73,10 +75,10 @@ func TestPersistClientCtx(t *testing.T) {

// parses the ctx from cmd with config, but it has set in flags which should give
// preference over the config set, so it should use from the flag value set.
err = fpcmd.PersistClientCtx(ctx)(&cmd, []string{})
err = fpcmd.PersistClientCtx(ctx)(cmd, []string{})
require.NoError(t, err)

ctx = client.GetClientContextFromCmd(&cmd)
ctx = client.GetClientContextFromCmd(cmd)
require.Equal(t, flagHomeValue, ctx.HomeDir)
require.Equal(t, flagChainID, ctx.ChainID)
}
6 changes: 3 additions & 3 deletions finality-provider/service/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) {
// Create mocked babylon client
randomStartingHeight := uint64(r.Int63n(100) + 1)
currentHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)
mockClientController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes()
mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(),
gomock.Any()).Return(uint64(0), nil).AnyTimes()
Expand Down Expand Up @@ -172,7 +172,7 @@ func FuzzSyncFinalityProviderStatus(f *testing.F) {

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

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

Expand Down Expand Up @@ -251,7 +251,7 @@ func FuzzUnjailFinalityProvider(f *testing.F) {

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

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

Expand Down
11 changes: 10 additions & 1 deletion finality-provider/service/fastsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"go.uber.org/zap"

"github.com/babylonlabs-io/finality-provider/types"
"github.com/babylonlabs-io/finality-provider/util"
)

type FastSyncResult struct {
Expand All @@ -28,8 +29,16 @@ func (fp *FinalityProviderInstance) FastSync(startHeight, endHeight uint64) (*Fa
startHeight, endHeight)
}

var syncedHeight uint64
activationBlkHeight, err := fp.cc.QueryFinalityActivationBlockHeight()
if err != nil {
return nil, fmt.Errorf("failed to get activation height during fast sync %w", err)
}

responses := make([]*types.TxResponse, 0)
// make sure it starts at least at the finality activation height
startHeight = util.MaxUint64(startHeight, activationBlkHeight)
// the syncedHeight is at least the starting point
syncedHeight := startHeight
// we may need several rounds to catch-up as we need to limit
// the catch-up distance for each round to avoid memory overflow
for startHeight <= endHeight {
Expand Down
26 changes: 24 additions & 2 deletions finality-provider/service/fastsync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package service_test
import (
"math/rand"
"testing"
"time"

"github.com/babylonlabs-io/babylon/testutil/datagen"
ftypes "github.com/babylonlabs-io/babylon/x/finality/types"
Expand All @@ -25,7 +26,7 @@ func FuzzFastSync_SufficientRandomness(f *testing.F) {
randomStartingHeight := uint64(r.Int63n(100) + 1)
finalizedHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
currentHeight := finalizedHeight + uint64(r.Int63n(10)+1)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)
mockClientController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return(nil, nil).AnyTimes()
_, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight)
defer cleanUp()
Expand Down Expand Up @@ -77,7 +78,7 @@ func FuzzFastSync_NoRandomness(f *testing.F) {
randomStartingHeight := uint64(r.Int63n(100) + 100)
finalizedHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
currentHeight := finalizedHeight + uint64(r.Int63n(10)+1)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)
mockClientController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return(nil, nil).AnyTimes()
_, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight)
defer cleanUp()
Expand Down Expand Up @@ -122,3 +123,24 @@ func FuzzFastSync_NoRandomness(f *testing.F) {
require.Equal(t, lastHeightWithPubRand, fpIns.GetLastProcessedHeight())
})
}

func TestFinalityActivationBlockHeight(t *testing.T) {
r := rand.New(rand.NewSource(time.Now().Unix()))

randomStartingHeight := uint64(r.Int63n(100) + 100)
finalizedHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
currentHeight := finalizedHeight + uint64(r.Int63n(10)+1)
finalityActvationBlockHeight := randomStartingHeight + 10

mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, finalityActvationBlockHeight)
mockClientController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return(nil, nil).AnyTimes()

mockClientController.EXPECT().QueryLastCommittedPublicRand(gomock.Any(), uint64(1)).Return(make(map[uint64]*ftypes.PubRandCommitResponse), nil).AnyTimes()
mockClientController.EXPECT().CommitPubRandList(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)

_, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight)
defer cleanUp()

_, err := fpIns.CommitPubRand(randomStartingHeight)
require.NoError(t, err)
}
45 changes: 34 additions & 11 deletions finality-provider/service/fp_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/babylonlabs-io/finality-provider/finality-provider/store"
"github.com/babylonlabs-io/finality-provider/metrics"
"github.com/babylonlabs-io/finality-provider/types"
"github.com/babylonlabs-io/finality-provider/util"
)

type FinalityProviderInstance struct {
Expand Down Expand Up @@ -202,6 +203,18 @@ func (fp *FinalityProviderInstance) finalitySigSubmissionLoop() {
if fp.hasProcessed(b) {
continue
}

activationBlkHeight, err := fp.cc.QueryFinalityActivationBlockHeight()
if err != nil {
fp.reportCriticalErr(fmt.Errorf("failed to get activation height during fast sync %w", err))
continue
}

// check if it is allowed to send finality
if b.Height < activationBlkHeight {
continue
}

// check whether the finality provider has voting power
hasVp, err := fp.hasVotingPower(b)
if err != nil {
Expand Down Expand Up @@ -374,16 +387,9 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (*
return nil, nil
}

lastFinalizedHeight := lastFinalizedBlocks[0].Height
lastProcessedHeight := fp.GetLastProcessedHeight()

// get the startHeight from the maximum of the lastVotedHeight and
// the lastFinalizedHeight plus 1
var startHeight uint64
if lastFinalizedHeight < lastProcessedHeight {
startHeight = lastProcessedHeight + 1
} else {
startHeight = lastFinalizedHeight + 1
startHeight, err := fp.fastSyncStartHeight(lastFinalizedBlocks[0].Height)
if err != nil {
return nil, err
}

if startHeight > targetBlock.Height {
Expand All @@ -395,6 +401,18 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (*
return fp.FastSync(startHeight, targetBlock.Height)
}

func (fp *FinalityProviderInstance) fastSyncStartHeight(lastFinalizedHeight uint64) (uint64, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fastSyncStartHeight is called after we have known that there's finalized blocks, indicating that activation is already started, so maybe we don't need to check activation height here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fastSyncStartHeight returns the height that fast sync should start right?
I probably can remove the check inside the fastSync than

lastProcessedHeight := fp.GetLastProcessedHeight()

finalityActivationBlkHeight, err := fp.cc.QueryFinalityActivationBlockHeight()
if err != nil {
return 0, err
}

// return the max start height by checking the finality activation block height
return util.MaxUint64(lastProcessedHeight+1, lastFinalizedHeight+1, finalityActivationBlkHeight), nil
}

func (fp *FinalityProviderInstance) hasProcessed(b *types.BlockInfo) bool {
if b.Height <= fp.GetLastProcessedHeight() {
fp.logger.Debug(
Expand Down Expand Up @@ -597,11 +615,16 @@ func (fp *FinalityProviderInstance) CommitPubRand(tipHeight uint64) (*types.TxRe
return nil, nil
}

activationBlkHeight, err := fp.cc.QueryFinalityActivationBlockHeight()
if err != nil {
return nil, err
}

// generate a list of Schnorr randomness pairs
// NOTE: currently, calling this will create and save a list of randomness
// in case of failure, randomness that has been created will be overwritten
// for safety reason as the same randomness must not be used twice
pubRandList, err := fp.getPubRandList(startHeight, fp.cfg.NumPubRand)
pubRandList, err := fp.getPubRandList(util.MaxUint64(startHeight, activationBlkHeight), fp.cfg.NumPubRand)
if err != nil {
return nil, fmt.Errorf("failed to generate randomness: %w", err)
}
Expand Down
4 changes: 2 additions & 2 deletions finality-provider/service/fp_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func FuzzCommitPubRandList(f *testing.F) {
randomStartingHeight := uint64(r.Int63n(100) + 1)
currentHeight := randomStartingHeight + uint64(r.Int63n(10)+2)
startingBlock := &types.BlockInfo{Height: randomStartingHeight, Hash: testutil.GenRandomByteArray(r, 32)}
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)
mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), gomock.Any()).
Return(uint64(0), nil).AnyTimes()
_, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight)
Expand All @@ -57,7 +57,7 @@ func FuzzSubmitFinalitySig(f *testing.F) {
randomStartingHeight := uint64(r.Int63n(100) + 1)
currentHeight := randomStartingHeight + uint64(r.Int63n(10)+1)
startingBlock := &types.BlockInfo{Height: randomStartingHeight, Hash: testutil.GenRandomByteArray(r, 32)}
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight)
mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight, 0)
mockClientController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes()
_, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight)
defer cleanUp()
Expand Down
1 change: 1 addition & 0 deletions finality-provider/service/fp_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ func FuzzStatusUpdate(f *testing.F) {
mockClientController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes()
mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes()
mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes()
mockClientController.EXPECT().QueryFinalityActivationBlockHeight().Return(uint64(0), nil).AnyTimes()
mockClientController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes()
mockClientController.EXPECT().QueryLastCommittedPublicRand(gomock.Any(), uint64(1)).Return(nil, nil).AnyTimes()

Expand Down
Loading
Loading