diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go index dc3d0ef4..f7c57837 100644 --- a/clientcontroller/babylon.go +++ b/clientcontroller/babylon.go @@ -493,6 +493,15 @@ func (bc *BabylonController) QueryBtcLightClientTip() (*btclctypes.BTCHeaderInfo return res.Header, nil } +func (bc *BabylonController) QueryCurrentEpoch() (uint64, error) { + res, err := bc.bbnClient.QueryClient.CurrentEpoch() + if err != nil { + return 0, fmt.Errorf("failed to query BTC tip: %v", err) + } + + return res.CurrentEpoch, nil +} + func (bc *BabylonController) QueryVotesAtHeight(height uint64) ([]bbntypes.BIP340PubKey, error) { res, err := bc.bbnClient.QueryClient.VotesAtHeight(height) if err != nil { @@ -589,3 +598,21 @@ func (bc *BabylonController) SubmitCovenantSigs( return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil } + +func (bc *BabylonController) GetBBNClient() *bbnclient.Client { + return bc.bbnClient +} + +func (bc *BabylonController) InsertSpvProofs(submitter string, proofs []*btcctypes.BTCSpvProof) (*provider.RelayerTxResponse, error) { + msg := &btcctypes.MsgInsertBTCSpvProof{ + Submitter: submitter, + Proofs: proofs, + } + + res, err := bc.reliablySendMsg(msg, emptyErrs, emptyErrs) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index a705a3f0..a7100068 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -10,6 +10,7 @@ import ( "go.uber.org/zap" finalitytypes "github.com/babylonlabs-io/babylon/x/finality/types" + fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config" "github.com/babylonlabs-io/finality-provider/types" ) diff --git a/eotsmanager/proto/eotsmanager.pb.go b/eotsmanager/proto/eotsmanager.pb.go index 9a512e34..eaf5ac07 100644 --- a/eotsmanager/proto/eotsmanager.pb.go +++ b/eotsmanager/proto/eotsmanager.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 +// protoc-gen-go v1.31.0 // protoc (unknown) // source: eotsmanager.proto diff --git a/eotsmanager/proto/eotsmanager_grpc.pb.go b/eotsmanager/proto/eotsmanager_grpc.pb.go index 75b1e5cf..0a8814ad 100644 --- a/eotsmanager/proto/eotsmanager_grpc.pb.go +++ b/eotsmanager/proto/eotsmanager_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: eotsmanager.proto package proto @@ -14,6 +18,15 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + EOTSManager_Ping_FullMethodName = "/proto.EOTSManager/Ping" + EOTSManager_CreateKey_FullMethodName = "/proto.EOTSManager/CreateKey" + EOTSManager_CreateRandomnessPairList_FullMethodName = "/proto.EOTSManager/CreateRandomnessPairList" + EOTSManager_KeyRecord_FullMethodName = "/proto.EOTSManager/KeyRecord" + EOTSManager_SignEOTS_FullMethodName = "/proto.EOTSManager/SignEOTS" + EOTSManager_SignSchnorrSig_FullMethodName = "/proto.EOTSManager/SignSchnorrSig" +) + // EOTSManagerClient is the client API for EOTSManager service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -41,7 +54,7 @@ func NewEOTSManagerClient(cc grpc.ClientConnInterface) EOTSManagerClient { func (c *eOTSManagerClient) Ping(ctx context.Context, in *PingRequest, opts ...grpc.CallOption) (*PingResponse, error) { out := new(PingResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/Ping", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_Ping_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -50,7 +63,7 @@ func (c *eOTSManagerClient) Ping(ctx context.Context, in *PingRequest, opts ...g func (c *eOTSManagerClient) CreateKey(ctx context.Context, in *CreateKeyRequest, opts ...grpc.CallOption) (*CreateKeyResponse, error) { out := new(CreateKeyResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/CreateKey", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_CreateKey_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -59,7 +72,7 @@ func (c *eOTSManagerClient) CreateKey(ctx context.Context, in *CreateKeyRequest, func (c *eOTSManagerClient) CreateRandomnessPairList(ctx context.Context, in *CreateRandomnessPairListRequest, opts ...grpc.CallOption) (*CreateRandomnessPairListResponse, error) { out := new(CreateRandomnessPairListResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/CreateRandomnessPairList", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_CreateRandomnessPairList_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -68,7 +81,7 @@ func (c *eOTSManagerClient) CreateRandomnessPairList(ctx context.Context, in *Cr func (c *eOTSManagerClient) KeyRecord(ctx context.Context, in *KeyRecordRequest, opts ...grpc.CallOption) (*KeyRecordResponse, error) { out := new(KeyRecordResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/KeyRecord", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_KeyRecord_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -77,7 +90,7 @@ func (c *eOTSManagerClient) KeyRecord(ctx context.Context, in *KeyRecordRequest, func (c *eOTSManagerClient) SignEOTS(ctx context.Context, in *SignEOTSRequest, opts ...grpc.CallOption) (*SignEOTSResponse, error) { out := new(SignEOTSResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/SignEOTS", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_SignEOTS_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -86,7 +99,7 @@ func (c *eOTSManagerClient) SignEOTS(ctx context.Context, in *SignEOTSRequest, o func (c *eOTSManagerClient) SignSchnorrSig(ctx context.Context, in *SignSchnorrSigRequest, opts ...grpc.CallOption) (*SignSchnorrSigResponse, error) { out := new(SignSchnorrSigResponse) - err := c.cc.Invoke(ctx, "/proto.EOTSManager/SignSchnorrSig", in, out, opts...) + err := c.cc.Invoke(ctx, EOTSManager_SignSchnorrSig_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -156,7 +169,7 @@ func _EOTSManager_Ping_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/Ping", + FullMethod: EOTSManager_Ping_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).Ping(ctx, req.(*PingRequest)) @@ -174,7 +187,7 @@ func _EOTSManager_CreateKey_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/CreateKey", + FullMethod: EOTSManager_CreateKey_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).CreateKey(ctx, req.(*CreateKeyRequest)) @@ -192,7 +205,7 @@ func _EOTSManager_CreateRandomnessPairList_Handler(srv interface{}, ctx context. } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/CreateRandomnessPairList", + FullMethod: EOTSManager_CreateRandomnessPairList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).CreateRandomnessPairList(ctx, req.(*CreateRandomnessPairListRequest)) @@ -210,7 +223,7 @@ func _EOTSManager_KeyRecord_Handler(srv interface{}, ctx context.Context, dec fu } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/KeyRecord", + FullMethod: EOTSManager_KeyRecord_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).KeyRecord(ctx, req.(*KeyRecordRequest)) @@ -228,7 +241,7 @@ func _EOTSManager_SignEOTS_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/SignEOTS", + FullMethod: EOTSManager_SignEOTS_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).SignEOTS(ctx, req.(*SignEOTSRequest)) @@ -246,7 +259,7 @@ func _EOTSManager_SignSchnorrSig_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.EOTSManager/SignSchnorrSig", + FullMethod: EOTSManager_SignSchnorrSig_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(EOTSManagerServer).SignSchnorrSig(ctx, req.(*SignSchnorrSigRequest)) diff --git a/finality-provider/config/config.go b/finality-provider/config/config.go index 3fa4b51f..fabce0b1 100644 --- a/finality-provider/config/config.go +++ b/finality-provider/config/config.go @@ -25,9 +25,9 @@ const ( defaultFinalityProviderKeyName = "finality-provider" DefaultRPCPort = 12581 defaultConfigFileName = "fpd.conf" - defaultNumPubRand = 100 - defaultNumPubRandMax = 200 - defaultMinRandHeightGap = 20 + defaultNumPubRand = 70000 // support running of 1 week with block production time as 10s + defaultNumPubRandMax = 100000 + defaultMinRandHeightGap = 35000 defaultStatusUpdateInterval = 20 * time.Second defaultRandomInterval = 30 * time.Second defaultSubmitRetryInterval = 1 * time.Second diff --git a/finality-provider/proto/finality_providers.pb.go b/finality-provider/proto/finality_providers.pb.go index e36c1b1f..7aa726ad 100644 --- a/finality-provider/proto/finality_providers.pb.go +++ b/finality-provider/proto/finality_providers.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.32.0 +// protoc-gen-go v1.31.0 // protoc (unknown) // source: finality_providers.proto diff --git a/finality-provider/proto/finality_providers_grpc.pb.go b/finality-provider/proto/finality_providers_grpc.pb.go index 6480c381..e2d7bdca 100644 --- a/finality-provider/proto/finality_providers_grpc.pb.go +++ b/finality-provider/proto/finality_providers_grpc.pb.go @@ -1,4 +1,8 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: finality_providers.proto package proto @@ -14,6 +18,16 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 +const ( + FinalityProviders_GetInfo_FullMethodName = "/proto.FinalityProviders/GetInfo" + FinalityProviders_CreateFinalityProvider_FullMethodName = "/proto.FinalityProviders/CreateFinalityProvider" + FinalityProviders_RegisterFinalityProvider_FullMethodName = "/proto.FinalityProviders/RegisterFinalityProvider" + FinalityProviders_AddFinalitySignature_FullMethodName = "/proto.FinalityProviders/AddFinalitySignature" + FinalityProviders_QueryFinalityProvider_FullMethodName = "/proto.FinalityProviders/QueryFinalityProvider" + FinalityProviders_QueryFinalityProviderList_FullMethodName = "/proto.FinalityProviders/QueryFinalityProviderList" + FinalityProviders_SignMessageFromChainKey_FullMethodName = "/proto.FinalityProviders/SignMessageFromChainKey" +) + // FinalityProvidersClient is the client API for FinalityProviders service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -46,7 +60,7 @@ func NewFinalityProvidersClient(cc grpc.ClientConnInterface) FinalityProvidersCl func (c *finalityProvidersClient) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) { out := new(GetInfoResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/GetInfo", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_GetInfo_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -55,7 +69,7 @@ func (c *finalityProvidersClient) GetInfo(ctx context.Context, in *GetInfoReques func (c *finalityProvidersClient) CreateFinalityProvider(ctx context.Context, in *CreateFinalityProviderRequest, opts ...grpc.CallOption) (*CreateFinalityProviderResponse, error) { out := new(CreateFinalityProviderResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/CreateFinalityProvider", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_CreateFinalityProvider_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -64,7 +78,7 @@ func (c *finalityProvidersClient) CreateFinalityProvider(ctx context.Context, in func (c *finalityProvidersClient) RegisterFinalityProvider(ctx context.Context, in *RegisterFinalityProviderRequest, opts ...grpc.CallOption) (*RegisterFinalityProviderResponse, error) { out := new(RegisterFinalityProviderResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/RegisterFinalityProvider", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_RegisterFinalityProvider_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -73,7 +87,7 @@ func (c *finalityProvidersClient) RegisterFinalityProvider(ctx context.Context, func (c *finalityProvidersClient) AddFinalitySignature(ctx context.Context, in *AddFinalitySignatureRequest, opts ...grpc.CallOption) (*AddFinalitySignatureResponse, error) { out := new(AddFinalitySignatureResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/AddFinalitySignature", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_AddFinalitySignature_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -82,7 +96,7 @@ func (c *finalityProvidersClient) AddFinalitySignature(ctx context.Context, in * func (c *finalityProvidersClient) QueryFinalityProvider(ctx context.Context, in *QueryFinalityProviderRequest, opts ...grpc.CallOption) (*QueryFinalityProviderResponse, error) { out := new(QueryFinalityProviderResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/QueryFinalityProvider", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_QueryFinalityProvider_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -91,7 +105,7 @@ func (c *finalityProvidersClient) QueryFinalityProvider(ctx context.Context, in func (c *finalityProvidersClient) QueryFinalityProviderList(ctx context.Context, in *QueryFinalityProviderListRequest, opts ...grpc.CallOption) (*QueryFinalityProviderListResponse, error) { out := new(QueryFinalityProviderListResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/QueryFinalityProviderList", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_QueryFinalityProviderList_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -100,7 +114,7 @@ func (c *finalityProvidersClient) QueryFinalityProviderList(ctx context.Context, func (c *finalityProvidersClient) SignMessageFromChainKey(ctx context.Context, in *SignMessageFromChainKeyRequest, opts ...grpc.CallOption) (*SignMessageFromChainKeyResponse, error) { out := new(SignMessageFromChainKeyResponse) - err := c.cc.Invoke(ctx, "/proto.FinalityProviders/SignMessageFromChainKey", in, out, opts...) + err := c.cc.Invoke(ctx, FinalityProviders_SignMessageFromChainKey_FullMethodName, in, out, opts...) if err != nil { return nil, err } @@ -178,7 +192,7 @@ func _FinalityProviders_GetInfo_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/GetInfo", + FullMethod: FinalityProviders_GetInfo_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).GetInfo(ctx, req.(*GetInfoRequest)) @@ -196,7 +210,7 @@ func _FinalityProviders_CreateFinalityProvider_Handler(srv interface{}, ctx cont } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/CreateFinalityProvider", + FullMethod: FinalityProviders_CreateFinalityProvider_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).CreateFinalityProvider(ctx, req.(*CreateFinalityProviderRequest)) @@ -214,7 +228,7 @@ func _FinalityProviders_RegisterFinalityProvider_Handler(srv interface{}, ctx co } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/RegisterFinalityProvider", + FullMethod: FinalityProviders_RegisterFinalityProvider_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).RegisterFinalityProvider(ctx, req.(*RegisterFinalityProviderRequest)) @@ -232,7 +246,7 @@ func _FinalityProviders_AddFinalitySignature_Handler(srv interface{}, ctx contex } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/AddFinalitySignature", + FullMethod: FinalityProviders_AddFinalitySignature_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).AddFinalitySignature(ctx, req.(*AddFinalitySignatureRequest)) @@ -250,7 +264,7 @@ func _FinalityProviders_QueryFinalityProvider_Handler(srv interface{}, ctx conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/QueryFinalityProvider", + FullMethod: FinalityProviders_QueryFinalityProvider_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).QueryFinalityProvider(ctx, req.(*QueryFinalityProviderRequest)) @@ -268,7 +282,7 @@ func _FinalityProviders_QueryFinalityProviderList_Handler(srv interface{}, ctx c } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/QueryFinalityProviderList", + FullMethod: FinalityProviders_QueryFinalityProviderList_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).QueryFinalityProviderList(ctx, req.(*QueryFinalityProviderListRequest)) @@ -286,7 +300,7 @@ func _FinalityProviders_SignMessageFromChainKey_Handler(srv interface{}, ctx con } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/proto.FinalityProviders/SignMessageFromChainKey", + FullMethod: FinalityProviders_SignMessageFromChainKey_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(FinalityProvidersServer).SignMessageFromChainKey(ctx, req.(*SignMessageFromChainKeyRequest)) diff --git a/finality-provider/service/fastsync.go b/finality-provider/service/fastsync.go index fd2b97ab..3cf114e5 100644 --- a/finality-provider/service/fastsync.go +++ b/finality-provider/service/fastsync.go @@ -62,14 +62,6 @@ func (fp *FinalityProviderInstance) FastSync(startHeight, endHeight uint64) (*Fa fp.metrics.IncrementFpTotalBlocksWithoutVotingPower(fp.GetBtcPkHex()) continue } - // check whether the randomness has been committed - hasRand, err := fp.hasRandomness(b) - if err != nil { - return nil, err - } - if !hasRand { - break - } // all good, add the block for catching up catchUpBlocks = append(catchUpBlocks, b) } diff --git a/finality-provider/service/fastsync_test.go b/finality-provider/service/fastsync_test.go index 2ef082e8..240c1fac 100644 --- a/finality-provider/service/fastsync_test.go +++ b/finality-provider/service/fastsync_test.go @@ -88,10 +88,17 @@ func FuzzFastSync_NoRandomness(f *testing.F) { _, err := fpIns.CommitPubRand(randomStartingHeight) require.NoError(t, err) - mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). - Return(uint64(1), nil).AnyTimes() // the last height with pub rand is a random value inside [finalizedHeight+1, currentHeight] lastHeightWithPubRand := uint64(rand.Intn(int(currentHeight)-int(finalizedHeight))) + finalizedHeight + 1 + for i := randomStartingHeight; i <= currentHeight; i++ { + if i <= lastHeightWithPubRand { + mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), i). + Return(uint64(1), nil).AnyTimes() + } else { + mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), i). + Return(uint64(0), nil).AnyTimes() + } + } lastCommittedPubRandMap := make(map[uint64]*ftypes.PubRandCommitResponse) lastCommittedPubRandMap[lastHeightWithPubRand-10] = &ftypes.PubRandCommitResponse{ NumPubRand: 10 + 1, diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index 89b4933a..e5b30ba7 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -203,22 +203,6 @@ func (fp *FinalityProviderInstance) finalitySigSubmissionLoop() { fp.metrics.IncrementFpTotalBlocksWithoutVotingPower(fp.GetBtcPkHex()) continue } - // check whether the randomness has been committed - // the retry will end if max retry times is reached - // or the target block is finalized - isFinalized, err := fp.retryCheckRandomnessUntilBlockFinalized(b) - if err != nil { - if !errors.Is(err, ErrFinalityProviderShutDown) { - fp.reportCriticalErr(err) - } - break - } - // the block is finalized, no need to submit finality signature - if isFinalized { - fp.MustSetLastProcessedHeight(b.Height) - continue - } - // use the copy of the block to avoid the impact to other receivers nextBlock := *b res, err := fp.retrySubmitFinalitySignatureUntilBlockFinalized(&nextBlock) @@ -431,24 +415,6 @@ func (fp *FinalityProviderInstance) hasVotingPower(b *types.BlockInfo) (bool, er return true, nil } -func (fp *FinalityProviderInstance) hasRandomness(b *types.BlockInfo) (bool, error) { - lastCommittedHeight, err := fp.GetLastCommittedHeight() - if err != nil { - return false, err - } - if b.Height > lastCommittedHeight { - fp.logger.Debug( - "the finality provider has not committed public randomness for the height", - zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("block_height", b.Height), - zap.Uint64("last_committed_height", lastCommittedHeight), - ) - return false, nil - } - - return true, nil -} - func (fp *FinalityProviderInstance) reportCriticalErr(err error) { fp.criticalErrChan <- &CriticalError{ err: err, @@ -461,77 +427,6 @@ func (fp *FinalityProviderInstance) checkLagging(currentBlock *types.BlockInfo) return currentBlock.Height >= fp.GetLastProcessedHeight()+fp.cfg.FastSyncGap } -// retryQueryingRandomnessUntilBlockFinalized periodically checks whether -// the randomness has been committed to the target block until the block is -// finalized -// error will be returned if maximum retries have been reached or the query to -// the consumer chain fails -func (fp *FinalityProviderInstance) retryCheckRandomnessUntilBlockFinalized(targetBlock *types.BlockInfo) (bool, error) { - var numRetries uint32 - - // we break the for loop if the block is finalized or the randomness is successfully committed - // error will be returned if maximum retries have been reached or the query to the consumer chain fails - for { - fp.logger.Debug( - "checking randomness", - zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("target_block_height", targetBlock.Height), - ) - hasRand, err := fp.hasRandomness(targetBlock) - if err != nil { - fp.logger.Debug( - "failed to check last committed randomness", - zap.String("pk", fp.GetBtcPkHex()), - zap.Uint32("current_failures", numRetries), - zap.Uint64("target_block_height", targetBlock.Height), - zap.Error(err), - ) - - numRetries += 1 - if numRetries > uint32(fp.cfg.MaxSubmissionRetries) { - return false, fmt.Errorf("reached max failed cycles with err: %w", err) - } - } else if !hasRand { - fp.logger.Debug( - "randomness does not exist", - zap.String("pk", fp.GetBtcPkHex()), - zap.Uint32("current_retries", numRetries), - zap.Uint64("target_block_height", targetBlock.Height), - ) - - numRetries += 1 - if numRetries > uint32(fp.cfg.MaxSubmissionRetries) { - return false, fmt.Errorf("reached max retries but randomness still not existed") - } - } else { - // the randomness has been successfully committed - return false, nil - } - select { - case <-time.After(fp.cfg.SubmissionRetryInterval): - // periodically query the index block to be later checked whether it is Finalized - finalized, err := fp.checkBlockFinalization(targetBlock.Height) - if err != nil { - return false, fmt.Errorf("failed to query block finalization at height %v: %w", targetBlock.Height, err) - } - if finalized { - fp.logger.Debug( - "the block is already finalized, skip checking randomness", - zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("target_height", targetBlock.Height), - ) - // TODO: returning nil here is to safely break the loop - // the error still exists - return true, nil - } - - case <-fp.quit: - fp.logger.Debug("the finality-provider instance is closing", zap.String("pk", fp.GetBtcPkHex())) - return false, ErrFinalityProviderShutDown - } - } -} - // retrySubmitFinalitySignatureUntilBlockFinalized periodically tries to submit finality signature until success or the block is finalized // error will be returned if maximum retries have been reached or the query to the consumer chain fails func (fp *FinalityProviderInstance) retrySubmitFinalitySignatureUntilBlockFinalized(targetBlock *types.BlockInfo) (*types.TxResponse, error) { @@ -815,16 +710,6 @@ func (fp *FinalityProviderInstance) SubmitBatchFinalitySignatures(blocks []*type // this API is the same as SubmitFinalitySignature except that we don't constraint the voting height and update status // Note: this should not be used in the submission loop func (fp *FinalityProviderInstance) TestSubmitFinalitySignatureAndExtractPrivKey(b *types.BlockInfo) (*types.TxResponse, *btcec.PrivateKey, error) { - // check last committed height - lastCommittedHeight, err := fp.GetLastCommittedHeight() - if err != nil { - return nil, nil, err - } - if lastCommittedHeight < b.Height { - return nil, nil, fmt.Errorf("the finality-provider's last committed height %v is lower than the current block height %v", - lastCommittedHeight, b.Height) - } - // get public randomness prList, err := fp.getPubRandList(b.Height, 1) if err != nil { diff --git a/go.mod b/go.mod index 8c43992c..f1804407 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/math v1.3.0 github.com/avast/retry-go/v4 v4.5.1 - github.com/babylonlabs-io/babylon v0.9.0 + github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4 github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcutil v1.1.5 diff --git a/go.sum b/go.sum index 13ee8509..96bf4680 100644 --- a/go.sum +++ b/go.sum @@ -281,8 +281,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/babylonlabs-io/babylon v0.9.0 h1:dHZ9wUrI5XLaO4UIwJRgiCdnzFdi5yv7dpibbu6TDv0= -github.com/babylonlabs-io/babylon v0.9.0/go.mod h1:t7B4e+ooD2oYvAxkegtNKDL9bXe+vU29a8xnCQh+UKo= +github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4 h1:WKR81WDZnf9tWi5sQTx9JN3k4254UjteCg6VRUEFT8w= +github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4/go.mod h1:9VUUAwVaalXiDdPZT65SPoawKWpp6ple6tBr8Vw0NI8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= diff --git a/itest/babylon_node_handler.go b/itest/babylon_node_handler.go index 57919e8b..716b117c 100644 --- a/itest/babylon_node_handler.go +++ b/itest/babylon_node_handler.go @@ -133,6 +133,7 @@ func NewBabylonNodeHandler(t *testing.T, covenantQuorum int, covenantPks []*type "--keyring-backend=test", "--chain-id=chain-test", "--additional-sender-account", + fmt.Sprintf("--epoch-interval=%d", 5), fmt.Sprintf("--slashing-address=%s", slashingAddr), fmt.Sprintf("--covenant-quorum=%d", covenantQuorum), fmt.Sprintf("--covenant-pks=%s", strings.Join(covenantPksStr, ",")), diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 0dec0dc1..257705ee 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -13,12 +13,11 @@ import ( "github.com/stretchr/testify/require" "github.com/babylonlabs-io/finality-provider/finality-provider/proto" - "github.com/babylonlabs-io/finality-provider/finality-provider/service" "github.com/babylonlabs-io/finality-provider/types" ) var ( - stakingTime = uint16(100) + stakingTime = uint16(1000) stakingAmount = int64(20000) ) @@ -33,7 +32,7 @@ func TestFinalityProviderLifeCycle(t *testing.T) { fpIns := fpInsList[0] // check the public randomness is committed - tm.WaitForFpPubRandCommitted(t, fpIns) + tm.WaitForFpPubRandTimestamped(t, fpIns) // send a BTC delegation _ = tm.InsertBTCDelegation(t, []*btcec.PublicKey{fpIns.GetBtcPk()}, stakingTime, stakingAmount) @@ -65,7 +64,7 @@ func TestDoubleSigning(t *testing.T) { fpIns := fpInsList[0] // check the public randomness is committed - tm.WaitForFpPubRandCommitted(t, fpIns) + tm.WaitForFpPubRandTimestamped(t, fpIns) // send a BTC delegation _ = tm.InsertBTCDelegation(t, []*btcec.PublicKey{fpIns.GetBtcPk()}, stakingTime, stakingAmount) @@ -115,44 +114,6 @@ func TestDoubleSigning(t *testing.T) { require.Equal(t, false, fps[0].IsRunning) } -// TestMultipleFinalityProviders tests starting with multiple finality providers -func TestMultipleFinalityProviders(t *testing.T) { - n := 3 - tm, fpInstances := StartManagerWithFinalityProvider(t, n) - defer tm.Stop(t) - - // submit BTC delegations for each finality-provider - for _, fpIns := range fpInstances { - tm.Wg.Add(1) - go func(fpi *service.FinalityProviderInstance) { - defer tm.Wg.Done() - // check the public randomness is committed - tm.WaitForFpPubRandCommitted(t, fpi) - // send a BTC delegation - _ = tm.InsertBTCDelegation(t, []*btcec.PublicKey{fpi.GetBtcPk()}, stakingTime, stakingAmount) - }(fpIns) - } - tm.Wg.Wait() - - // check the BTC delegations are pending - delsResp := tm.WaitForNPendingDels(t, n) - require.Equal(t, n, len(delsResp)) - - // send covenant sigs to each of the delegations - for _, delResp := range delsResp { - d, err := ParseRespBTCDelToBTCDel(delResp) - require.NoError(t, err) - // send covenant sigs - tm.InsertCovenantSigForDelegation(t, d) - } - - // check the BTC delegations are active - _ = tm.WaitForNActiveDels(t, n) - - // check if there's a block finalized - _ = tm.WaitForNFinalizedBlocks(t, 1) -} - // TestFastSync tests the fast sync process where the finality-provider is terminated and restarted with fast sync func TestFastSync(t *testing.T) { tm, fpInsList := StartManagerWithFinalityProvider(t, 1) @@ -161,7 +122,7 @@ func TestFastSync(t *testing.T) { fpIns := fpInsList[0] // check the public randomness is committed - tm.WaitForFpPubRandCommitted(t, fpIns) + tm.WaitForFpPubRandTimestamped(t, fpIns) // send a BTC delegation _ = tm.InsertBTCDelegation(t, []*btcec.PublicKey{fpIns.GetBtcPk()}, stakingTime, stakingAmount) diff --git a/itest/test_manager.go b/itest/test_manager.go index 984d547d..3ddee10c 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -13,22 +13,26 @@ import ( sdkmath "cosmossdk.io/math" "github.com/babylonlabs-io/babylon/btcstaking" + txformat "github.com/babylonlabs-io/babylon/btctxformatter" asig "github.com/babylonlabs-io/babylon/crypto/schnorr-adaptor-signature" "github.com/babylonlabs-io/babylon/testutil/datagen" bbntypes "github.com/babylonlabs-io/babylon/types" btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" - "github.com/babylonlabs-io/finality-provider/clientcontroller" + ckpttypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/wire" sdk "github.com/cosmos/cosmos-sdk/types" + sdkquerytypes "github.com/cosmos/cosmos-sdk/types/query" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/stretchr/testify/require" "go.uber.org/zap" + "github.com/babylonlabs-io/finality-provider/clientcontroller" + fpcc "github.com/babylonlabs-io/finality-provider/clientcontroller" "github.com/babylonlabs-io/finality-provider/eotsmanager/client" eotsconfig "github.com/babylonlabs-io/finality-provider/eotsmanager/config" @@ -100,6 +104,16 @@ func StartManager(t *testing.T) *TestManager { bc, err := fpcc.NewBabylonController(cfg.BabylonConfig, &cfg.BTCNetParams, logger) require.NoError(t, err) + var currentEpoch uint64 + require.Eventually(t, func() bool { + currentEpoch, err = bc.QueryCurrentEpoch() + if err != nil { + return false + } + return currentEpoch > 0 + }, eventuallyWaitTimeOut, eventuallyPollTime) + t.Logf("current epoch is %d", currentEpoch) + // 3. prepare EOTS manager eotsHomeDir := filepath.Join(testDir, "eots-home") eotsCfg := eotsconfig.DefaultConfigWithHomePath(eotsHomeDir) @@ -236,16 +250,31 @@ func (tm *TestManager) Stop(t *testing.T) { tm.EOTSServerHandler.Stop() } -func (tm *TestManager) WaitForFpPubRandCommitted(t *testing.T, fpIns *service.FinalityProviderInstance) { +func (tm *TestManager) WaitForFpPubRandTimestamped(t *testing.T, fpIns *service.FinalityProviderInstance) { + var lastCommittedHeight uint64 + var err error + require.Eventually(t, func() bool { - lastCommittedHeight, err := fpIns.GetLastCommittedHeight() + lastCommittedHeight, err = fpIns.GetLastCommittedHeight() if err != nil { return false } return lastCommittedHeight > 0 }, eventuallyWaitTimeOut, eventuallyPollTime) - t.Logf("public randomness is successfully committed") + t.Logf("public randomness is successfully committed, last committed height: %d", lastCommittedHeight) + + // wait until the last registered epoch is finalised + currentEpoch, err := tm.BBNClient.QueryCurrentEpoch() + require.NoError(t, err) + + tm.FinalizeUntilEpoch(t, currentEpoch) + + res, err := tm.BBNClient.GetBBNClient().LatestEpochFromStatus(ckpttypes.Finalized) + require.NoError(t, err) + t.Logf("last finalized epoch: %d", res.RawCheckpoint.EpochNum) + + t.Logf("public randomness is successfully timestamped, last finalized epoch: %d", currentEpoch) } func (tm *TestManager) WaitForNPendingDels(t *testing.T, n int) []*bstypes.BTCDelegationResponse { @@ -518,6 +547,117 @@ func (tm *TestManager) InsertCovenantSigForDelegation(t *testing.T, btcDel *bsty require.NoError(t, err) } +func (tm *TestManager) InsertWBTCHeaders(t *testing.T, r *rand.Rand) { + params, err := tm.BBNClient.QueryStakingParams() + require.NoError(t, err) + btcTipResp, err := tm.BBNClient.QueryBtcLightClientTip() + require.NoError(t, err) + tipHeader, err := bbntypes.NewBTCHeaderBytesFromHex(btcTipResp.HeaderHex) + require.NoError(t, err) + kHeaders := datagen.NewBTCHeaderChainFromParentInfo(r, &btclctypes.BTCHeaderInfo{ + Header: &tipHeader, + Hash: tipHeader.Hash(), + Height: btcTipResp.Height, + Work: &btcTipResp.Work, + }, uint32(params.FinalizationTimeoutBlocks)) + _, err = tm.BBNClient.InsertBtcBlockHeaders(kHeaders.ChainToBytes()) + require.NoError(t, err) +} + +func (tm *TestManager) FinalizeUntilEpoch(t *testing.T, epoch uint64) { + bbnClient := tm.BBNClient.GetBBNClient() + + // wait until the checkpoint of this epoch is sealed + require.Eventually(t, func() bool { + lastSealedCkpt, err := bbnClient.LatestEpochFromStatus(ckpttypes.Sealed) + if err != nil { + return false + } + return epoch <= lastSealedCkpt.RawCheckpoint.EpochNum + }, eventuallyWaitTimeOut, 1*time.Second) + + t.Logf("start finalizing epochs till %d", epoch) + // Random source for the generation of BTC data + r := rand.New(rand.NewSource(time.Now().Unix())) + + // get all checkpoints of these epochs + pagination := &sdkquerytypes.PageRequest{ + Key: ckpttypes.CkptsObjectKey(0), + Limit: epoch, + } + resp, err := bbnClient.RawCheckpoints(pagination) + require.NoError(t, err) + require.Equal(t, int(epoch), len(resp.RawCheckpoints)) + + submitter := tm.BBNClient.GetKeyAddress() + + for _, checkpoint := range resp.RawCheckpoints { + currentBtcTipResp, err := tm.BBNClient.QueryBtcLightClientTip() + require.NoError(t, err) + tipHeader, err := bbntypes.NewBTCHeaderBytesFromHex(currentBtcTipResp.HeaderHex) + require.NoError(t, err) + + rawCheckpoint, err := checkpoint.Ckpt.ToRawCheckpoint() + require.NoError(t, err) + + btcCheckpoint, err := ckpttypes.FromRawCkptToBTCCkpt(rawCheckpoint, submitter) + require.NoError(t, err) + + babylonTagBytes, err := hex.DecodeString("01020304") + require.NoError(t, err) + + p1, p2, err := txformat.EncodeCheckpointData( + babylonTagBytes, + txformat.CurrentVersion, + btcCheckpoint, + ) + require.NoError(t, err) + + tx1 := datagen.CreatOpReturnTransaction(r, p1) + + opReturn1 := datagen.CreateBlockWithTransaction(r, tipHeader.ToBlockHeader(), tx1) + tx2 := datagen.CreatOpReturnTransaction(r, p2) + opReturn2 := datagen.CreateBlockWithTransaction(r, opReturn1.HeaderBytes.ToBlockHeader(), tx2) + + // insert headers and proofs + _, err = tm.BBNClient.InsertBtcBlockHeaders([]bbntypes.BTCHeaderBytes{ + opReturn1.HeaderBytes, + opReturn2.HeaderBytes, + }) + require.NoError(t, err) + + _, err = tm.BBNClient.InsertSpvProofs(submitter.String(), []*btcctypes.BTCSpvProof{ + opReturn1.SpvProof, + opReturn2.SpvProof, + }) + require.NoError(t, err) + + // wait until this checkpoint is submitted + require.Eventually(t, func() bool { + ckpt, err := bbnClient.RawCheckpoint(checkpoint.Ckpt.EpochNum) + if err != nil { + return false + } + return ckpt.RawCheckpoint.Status == ckpttypes.Submitted + }, eventuallyWaitTimeOut, eventuallyPollTime) + } + + // insert w BTC headers + tm.InsertWBTCHeaders(t, r) + + // wait until the checkpoint of this epoch is finalised + require.Eventually(t, func() bool { + lastFinalizedCkpt, err := bbnClient.LatestEpochFromStatus(ckpttypes.Finalized) + if err != nil { + t.Logf("failed to get last finalized epoch: %v", err) + return false + } + return epoch <= lastFinalizedCkpt.RawCheckpoint.EpochNum + }, eventuallyWaitTimeOut, 1*time.Second) + + t.Logf("epoch %d is finalised", epoch) +} + func (tm *TestManager) InsertBTCDelegation(t *testing.T, fpPks []*btcec.PublicKey, stakingTime uint16, stakingAmount int64) *TestDelegationData { params := tm.StakingParams r := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -660,6 +800,10 @@ func (tm *TestManager) InsertBTCDelegation(t *testing.T, fpPks []*btcec.PublicKe func defaultFpConfig(keyringDir, homeDir string) *fpcfg.Config { cfg := fpcfg.DefaultConfigWithHome(homeDir) + cfg.NumPubRand = 1000 + cfg.NumPubRandMax = 1000 + cfg.MinRandHeightGap = 500 + cfg.BitcoinNetwork = "simnet" cfg.BTCNetParams = chaincfg.SimNetParams diff --git a/tools/go.mod b/tools/go.mod index 30a04a46..026ccab7 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -4,7 +4,7 @@ go 1.21 toolchain go1.21.4 -require github.com/babylonlabs-io/babylon v0.9.0 +require github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4 require ( cloud.google.com/go v0.112.0 // indirect diff --git a/tools/go.sum b/tools/go.sum index 9707fffa..5f4f5bb4 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -268,8 +268,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/babylonlabs-io/babylon v0.9.0 h1:dHZ9wUrI5XLaO4UIwJRgiCdnzFdi5yv7dpibbu6TDv0= -github.com/babylonlabs-io/babylon v0.9.0/go.mod h1:t7B4e+ooD2oYvAxkegtNKDL9bXe+vU29a8xnCQh+UKo= +github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4 h1:WKR81WDZnf9tWi5sQTx9JN3k4254UjteCg6VRUEFT8w= +github.com/babylonlabs-io/babylon v0.9.3-0.20240903035004-5c732382e9a4/go.mod h1:9VUUAwVaalXiDdPZT65SPoawKWpp6ple6tBr8Vw0NI8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=