From 4e105a318da65c2a04b90c2f3ecf3d140d74f073 Mon Sep 17 00:00:00 2001 From: bap2pecs <111917526+bap2pecs@users.noreply.github.com> Date: Mon, 4 Nov 2024 03:54:00 -0500 Subject: [PATCH 1/2] backport: rename config `ChainName` to `ChainType` (#87) --- CHANGELOG.md | 1 + clientcontroller/interface.go | 8 ++++---- finality-provider/config/config.go | 8 ++++---- finality-provider/service/app.go | 4 ++-- itest/e2e_test.go | 2 +- itest/test_manager.go | 5 +++-- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b230bb5..49cc00ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * [#114](https://github.com/babylonlabs-io/finality-provider/pull/114) Bump Babylon version to v0.15.0 * [#102](https://github.com/babylonlabs-io/finality-provider/pull/102) Improve `eotsd keys add` command * [#104](https://github.com/babylonlabs-io/finality-provider/pull/104) Print fpd binary version +* [#87](https://github.com/babylonlabs-io/finality-provider/pull/87) Rename ChainName to ChainType ## v0.9.1 diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index dbaca981..6c1d1e2d 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -17,7 +17,7 @@ import ( ) const ( - babylonConsumerChainName = "babylon" + babylonConsumerChainType = "babylon" ) type ClientController interface { @@ -82,14 +82,14 @@ type ClientController interface { Close() error } -func NewClientController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ClientController, error) { +func NewClientController(chainType string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ClientController, error) { var ( cc ClientController err error ) - switch chainName { - case babylonConsumerChainName: + switch chainType { + case babylonConsumerChainType: cc, err = NewBabylonController(bbnConfig, netParams, logger) if err != nil { return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) diff --git a/finality-provider/config/config.go b/finality-provider/config/config.go index dff97eca..cea546a7 100644 --- a/finality-provider/config/config.go +++ b/finality-provider/config/config.go @@ -18,7 +18,7 @@ import ( ) const ( - defaultChainName = "babylon" + defaultChainType = "babylon" defaultLogLevel = zapcore.InfoLevel defaultLogDirname = "logs" defaultLogFilename = "fpd.log" @@ -55,8 +55,8 @@ var ( // Config is the main config for the fpd cli command type Config struct { LogLevel string `long:"loglevel" description:"Logging level for all subsystems" choice:"trace" choice:"debug" choice:"info" choice:"warn" choice:"error" choice:"fatal"` - // ChainName and ChainID (if any) of the chain config identify a consumer chain - ChainName string `long:"chainname" description:"the name of the consumer chain" choice:"babylon"` + // ChainType and ChainID (if any) of the chain config identify a consumer chain + ChainType string `long:"chaintype" description:"the type of the consumer chain" choice:"babylon"` NumPubRand uint32 `long:"numPubRand" description:"The number of Schnorr public randomness for each commitment"` NumPubRandMax uint32 `long:"numpubrandmax" description:"The upper bound of the number of Schnorr public randomness for each commitment"` MinRandHeightGap uint32 `long:"minrandheightgap" description:"The minimum gap between the last committed rand height and the current Babylon block height"` @@ -91,7 +91,7 @@ func DefaultConfigWithHome(homePath string) Config { bbnCfg.KeyDirectory = homePath pollerCfg := DefaultChainPollerConfig() cfg := Config{ - ChainName: defaultChainName, + ChainType: defaultChainType, LogLevel: defaultLogLevel.String(), DatabaseConfig: DefaultDBConfigWithHomePath(homePath), BabylonConfig: &bbnCfg, diff --git a/finality-provider/service/app.go b/finality-provider/service/app.go index 79bd5adf..73e52c4a 100644 --- a/finality-provider/service/app.go +++ b/finality-provider/service/app.go @@ -59,9 +59,9 @@ func NewFinalityProviderAppFromConfig( db kvdb.Backend, logger *zap.Logger, ) (*FinalityProviderApp, error) { - cc, err := clientcontroller.NewClientController(cfg.ChainName, cfg.BabylonConfig, &cfg.BTCNetParams, logger) + cc, err := clientcontroller.NewClientController(cfg.ChainType, cfg.BabylonConfig, &cfg.BTCNetParams, logger) if err != nil { - return nil, fmt.Errorf("failed to create rpc client for the consumer chain %s: %v", cfg.ChainName, err) + return nil, fmt.Errorf("failed to create rpc client for the consumer chain %s: %v", cfg.ChainType, err) } // if the EOTSManagerAddress is empty, run a local EOTS manager; diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 49383832..e2587783 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -161,7 +161,7 @@ func TestFinalityProviderEditCmd(t *testing.T) { cfg := tm.Fpa.GetConfig() cfg.BabylonConfig.Key = testFpName - cc, err := clientcontroller.NewClientController(cfg.ChainName, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) + cc, err := clientcontroller.NewClientController(cfg.ChainType, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) require.NoError(t, err) tm.Fpa.UpdateClientController(cc) diff --git a/itest/test_manager.go b/itest/test_manager.go index 750b803a..5d9fd5e4 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -204,7 +204,8 @@ func StartManagerWithFinalityProvider(t *testing.T) (*TestManager, *service.Fina fpBbnKeyInfo, err := service.CreateChainKey(cfg.BabylonConfig.KeyDirectory, cfg.BabylonConfig.ChainID, cfg.BabylonConfig.Key, cfg.BabylonConfig.KeyringBackend, passphrase, hdPath, "") require.NoError(t, err) - cc, err := clientcontroller.NewClientController(cfg.ChainName, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) + cc, err := clientcontroller.NewClientController(cfg.ChainType, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) + require.NoError(t, err) app.UpdateClientController(cc) @@ -253,7 +254,7 @@ func StartManagerWithFinalityProvider(t *testing.T) (*TestManager, *service.Fina // goes back to old key in app cfg.BabylonConfig.Key = oldKey - cc, err = clientcontroller.NewClientController(cfg.ChainName, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) + cc, err = clientcontroller.NewClientController(cfg.ChainType, cfg.BabylonConfig, &cfg.BTCNetParams, zap.NewNop()) require.NoError(t, err) app.UpdateClientController(cc) From fc280b8d7b6989cd8898dfc3e49e72ffa7e74380 Mon Sep 17 00:00:00 2001 From: Cirrus Gai Date: Wed, 13 Nov 2024 14:44:18 +0800 Subject: [PATCH 2/2] fix: Ignore duplicated finality vote err (#124) [context](https://github.com/babylonlabs-io/babylon/pull/130) Closes #123 --- CHANGELOG.md | 3 +++ clientcontroller/babylon.go | 25 ++++++++++++++++---- finality-provider/service/fp_instance.go | 20 +++++++++++----- itest/e2e_test.go | 29 +++++++++++++----------- 4 files changed, 54 insertions(+), 23 deletions(-) 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 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..007e4419 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 } @@ -785,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 e2587783..10d41c68 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,13 @@ func TestDoubleSigning(t *testing.T) { finalizedBlocks := tm.WaitForNFinalizedBlocks(t, 1) + // test duplicate vote which should be ignored + 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 // to trigger the extraction of finality-provider's private key r := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -91,19 +100,13 @@ 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()) 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 providers and the slashed one 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