From 3df51e628507f8a7f9f2b7d0a8767bb18f9d1220 Mon Sep 17 00:00:00 2001 From: Fangyu Gai Date: Mon, 11 Nov 2024 11:39:15 +0800 Subject: [PATCH 1/3] ignore duplicated vote err --- clientcontroller/babylon.go | 25 ++++++++++++++++++++---- finality-provider/service/fp_instance.go | 16 +++++++++------ itest/e2e_test.go | 24 +++++++++++++++-------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go index 80f877c0..68524ec8 100644 --- a/clientcontroller/babylon.go +++ b/clientcontroller/babylon.go @@ -16,8 +16,6 @@ import ( btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" 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" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/btcutil" @@ -29,6 +27,9 @@ import ( "github.com/cosmos/relayer/v2/relayer/provider" "go.uber.org/zap" protobuf "google.golang.org/protobuf/proto" + + fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config" + "github.com/babylonlabs-io/finality-provider/types" ) var _ ClientController = &BabylonController{} @@ -207,11 +208,19 @@ func (bc *BabylonController) SubmitFinalitySig( btcstakingtypes.ErrFpAlreadySlashed, } - res, err := bc.reliablySendMsg(msg, emptyErrs, unrecoverableErrs) + expectedErrs := []*sdkErr.Error{ + finalitytypes.ErrDuplicatedFinalitySig, + } + + res, err := bc.reliablySendMsg(msg, expectedErrs, unrecoverableErrs) if err != nil { return nil, err } + if res == nil { + return &types.TxResponse{}, nil + } + return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil } @@ -252,11 +261,19 @@ func (bc *BabylonController) SubmitBatchFinalitySigs( btcstakingtypes.ErrFpAlreadySlashed, } - res, err := bc.reliablySendMsgs(msgs, emptyErrs, unrecoverableErrs) + expectedErrs := []*sdkErr.Error{ + finalitytypes.ErrDuplicatedFinalitySig, + } + + res, err := bc.reliablySendMsgs(msgs, expectedErrs, unrecoverableErrs) if err != nil { return nil, err } + if res == nil { + return &types.TxResponse{}, nil + } + return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil } diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index 30b80451..c4ce298e 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -11,12 +11,13 @@ import ( "github.com/avast/retry-go/v4" bbntypes "github.com/babylonlabs-io/babylon/types" ftypes "github.com/babylonlabs-io/babylon/x/finality/types" - fppath "github.com/babylonlabs-io/finality-provider/lib/math" "github.com/btcsuite/btcd/btcec/v2" "github.com/gogo/protobuf/jsonpb" "go.uber.org/atomic" "go.uber.org/zap" + fppath "github.com/babylonlabs-io/finality-provider/lib/math" + "github.com/babylonlabs-io/finality-provider/clientcontroller" "github.com/babylonlabs-io/finality-provider/eotsmanager" fpcfg "github.com/babylonlabs-io/finality-provider/finality-provider/config" @@ -693,12 +694,15 @@ func (fp *FinalityProviderInstance) SubmitFinalitySignature(b *types.BlockInfo) return nil, fmt.Errorf("failed to send finality signature to the consumer chain: %w", err) } - // update DB - fp.MustUpdateStateAfterFinalitySigSubmission(b.Height) + // it is possible that the vote is duplicate so the metrics do need to update + if res.TxHash != "" { + // update DB + fp.MustUpdateStateAfterFinalitySigSubmission(b.Height) - // update metrics - fp.metrics.RecordFpVoteTime(fp.GetBtcPkHex()) - fp.metrics.IncrementFpTotalVotedBlocks(fp.GetBtcPkHex()) + // update metrics + fp.metrics.RecordFpVoteTime(fp.GetBtcPkHex()) + fp.metrics.IncrementFpTotalVotedBlocks(fp.GetBtcPkHex()) + } return res, nil } diff --git a/itest/e2e_test.go b/itest/e2e_test.go index e2587783..5f8bcc33 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -4,17 +4,19 @@ package e2etest import ( + "math/rand" + "testing" + "time" + sdkmath "cosmossdk.io/math" "github.com/babylonlabs-io/babylon/testutil/datagen" - "github.com/babylonlabs-io/finality-provider/clientcontroller" - "github.com/babylonlabs-io/finality-provider/finality-provider/cmd/fpd/daemon" - "github.com/babylonlabs-io/finality-provider/types" "github.com/btcsuite/btcd/btcec/v2" "github.com/stretchr/testify/require" "go.uber.org/zap" - "math/rand" - "testing" - "time" + + "github.com/babylonlabs-io/finality-provider/clientcontroller" + "github.com/babylonlabs-io/finality-provider/finality-provider/cmd/fpd/daemon" + "github.com/babylonlabs-io/finality-provider/types" ) var ( @@ -84,6 +86,12 @@ func TestDoubleSigning(t *testing.T) { finalizedBlocks := tm.WaitForNFinalizedBlocks(t, 1) + // test duplicate vote which should be ignored + _, extractedKey, err := fpIns.TestSubmitFinalitySignatureAndExtractPrivKey(finalizedBlocks[0]) + require.NoError(t, err) + require.Nil(t, extractedKey) + t.Logf("duplicate vote for %d is sent", finalizedBlocks[0].Height) + // attack: manually submit a finality vote over a conflicting block // to trigger the extraction of finality-provider's private key r := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -91,7 +99,7 @@ func TestDoubleSigning(t *testing.T) { Height: finalizedBlocks[0].Height, Hash: datagen.GenRandomByteArray(r, 32), } - _, extractedKey, err := fpIns.TestSubmitFinalitySignatureAndExtractPrivKey(b) + _, extractedKey, err = fpIns.TestSubmitFinalitySignatureAndExtractPrivKey(b) require.NoError(t, err) require.NotNil(t, extractedKey) localKey := tm.GetFpPrivKey(t, fpIns.GetBtcPkBIP340().MustMarshal()) @@ -101,7 +109,7 @@ func TestDoubleSigning(t *testing.T) { tm.WaitForFpShutDown(t) - // try to start the finality providers and the slashed one should expect err + // try to start the finality provider and should expect err err = tm.Fpa.StartHandlingFinalityProvider(fpIns.GetBtcPkBIP340(), "") require.Error(t, err) } From 56914c671d3a6a6541c2046ad7992116561703c5 Mon Sep 17 00:00:00 2001 From: Fangyu Gai Date: Mon, 11 Nov 2024 12:47:32 +0800 Subject: [PATCH 2/3] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cc00ef..4497a85d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ## Unreleased +* [#124](https://github.com/babylonlabs-io/finality-provider/pull/124) Ignore +duplicated finality vote error + ## v0.10.0 ### Improvements From ebbd8a97e9c84cdf005fba168d4360078b9632fb Mon Sep 17 00:00:00 2001 From: Fangyu Gai Date: Mon, 11 Nov 2024 13:00:10 +0800 Subject: [PATCH 3/3] fix e2e --- finality-provider/service/fp_instance.go | 4 ++++ itest/e2e_test.go | 9 ++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index c4ce298e..007e4419 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -789,6 +789,10 @@ func (fp *FinalityProviderInstance) TestSubmitFinalitySignatureAndExtractPrivKey return nil, nil, fmt.Errorf("failed to send finality signature to the consumer chain: %w", err) } + if res.TxHash == "" { + return res, nil, nil + } + // try to extract the private key var privKey *btcec.PrivateKey for _, ev := range res.Events { diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 5f8bcc33..10d41c68 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -87,9 +87,10 @@ func TestDoubleSigning(t *testing.T) { finalizedBlocks := tm.WaitForNFinalizedBlocks(t, 1) // test duplicate vote which should be ignored - _, extractedKey, err := fpIns.TestSubmitFinalitySignatureAndExtractPrivKey(finalizedBlocks[0]) + res, extractedKey, err := fpIns.TestSubmitFinalitySignatureAndExtractPrivKey(finalizedBlocks[0]) require.NoError(t, err) require.Nil(t, extractedKey) + require.Empty(t, res) t.Logf("duplicate vote for %d is sent", finalizedBlocks[0].Height) // attack: manually submit a finality vote over a conflicting block @@ -106,12 +107,6 @@ func TestDoubleSigning(t *testing.T) { require.True(t, localKey.Key.Equals(&extractedKey.Key) || localKey.Key.Negate().Equals(&extractedKey.Key)) t.Logf("the equivocation attack is successful") - - tm.WaitForFpShutDown(t) - - // try to start the finality provider and should expect err - err = tm.Fpa.StartHandlingFinalityProvider(fpIns.GetBtcPkBIP340(), "") - require.Error(t, err) } // TestFastSync tests the fast sync process where the finality-provider is terminated and restarted with fast sync