From 289bbc4235c5bbf8d58641ec814ef2d8848cd94a Mon Sep 17 00:00:00 2001 From: lesterli Date: Sat, 11 May 2024 21:46:20 +0800 Subject: [PATCH 01/26] feat: Split into ClientController and ConsumerController (#318) --- clientcontroller/babylon.go | 152 ---------- clientcontroller/babylon_consumer.go | 281 ++++++++++++++++++ clientcontroller/interface.go | 46 ++- finality-provider/service/app.go | 28 +- finality-provider/service/app_test.go | 2 +- finality-provider/service/chain_poller.go | 9 +- .../service/chain_poller_test.go | 4 +- finality-provider/service/fastsync.go | 2 +- finality-provider/service/fastsync_test.go | 2 +- finality-provider/service/fp_instance.go | 33 +- finality-provider/service/fp_instance_test.go | 8 +- finality-provider/service/fp_manager.go | 17 +- finality-provider/service/fp_manager_test.go | 6 +- itest/e2e_test.go | 2 +- itest/test_manager.go | 14 +- 15 files changed, 393 insertions(+), 213 deletions(-) create mode 100644 clientcontroller/babylon_consumer.go diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go index a2396c59..7a28467a 100644 --- a/clientcontroller/babylon.go +++ b/clientcontroller/babylon.go @@ -3,7 +3,6 @@ package clientcontroller import ( "context" "fmt" - "time" sdkErr "cosmossdk.io/errors" "github.com/btcsuite/btcd/btcec/v2" @@ -16,7 +15,6 @@ import ( btclctypes "github.com/babylonchain/babylon/x/btclightclient/types" btcstakingtypes "github.com/babylonchain/babylon/x/btcstaking/types" ckpttypes "github.com/babylonchain/babylon/x/checkpointing/types" - finalitytypes "github.com/babylonchain/babylon/x/finality/types" "github.com/btcsuite/btcd/btcec/v2/schnorr" "github.com/btcsuite/btcd/chaincfg" "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" @@ -152,62 +150,6 @@ func (bc *BabylonController) RegisterFinalityProvider( return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, registeredEpoch, nil } -// SubmitFinalitySig submits the finality signature via a MsgAddVote to Babylon -func (bc *BabylonController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { - msg := &finalitytypes.MsgAddFinalitySig{ - Signer: bc.mustGetTxSigner(), - FpBtcPk: bbntypes.NewBIP340PubKeyFromBTCPK(fpPk), - BlockHeight: blockHeight, - BlockAppHash: blockHash, - FinalitySig: bbntypes.NewSchnorrEOTSSigFromModNScalar(sig), - } - - unrecoverableErrs := []*sdkErr.Error{ - finalitytypes.ErrInvalidFinalitySig, - finalitytypes.ErrPubRandNotFound, - btcstakingtypes.ErrFpAlreadySlashed, - } - - res, err := bc.reliablySendMsg(msg, emptyErrs, unrecoverableErrs) - if err != nil { - return nil, err - } - - return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil -} - -// SubmitBatchFinalitySigs submits a batch of finality signatures to Babylon -func (bc *BabylonController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { - if len(blocks) != len(sigs) { - return nil, fmt.Errorf("the number of blocks %v should match the number of finality signatures %v", len(blocks), len(sigs)) - } - - msgs := make([]sdk.Msg, 0, len(blocks)) - for i, b := range blocks { - msg := &finalitytypes.MsgAddFinalitySig{ - Signer: bc.mustGetTxSigner(), - FpBtcPk: bbntypes.NewBIP340PubKeyFromBTCPK(fpPk), - BlockHeight: b.Height, - BlockAppHash: b.Hash, - FinalitySig: bbntypes.NewSchnorrEOTSSigFromModNScalar(sigs[i]), - } - msgs = append(msgs, msg) - } - - unrecoverableErrs := []*sdkErr.Error{ - finalitytypes.ErrInvalidFinalitySig, - finalitytypes.ErrPubRandNotFound, - btcstakingtypes.ErrFpAlreadySlashed, - } - - res, err := bc.reliablySendMsgs(msgs, emptyErrs, unrecoverableErrs) - if err != nil { - return nil, err - } - - return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil -} - func (bc *BabylonController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk) res, err := bc.bbnClient.QueryClient.FinalityProvider(fpPubKey.MarshalHex()) @@ -245,10 +187,6 @@ func (bc *BabylonController) QueryFinalityProviderRegisteredEpoch(fpPk *btcec.Pu return res.FinalityProvider.RegisteredEpoch, nil } -func (bc *BabylonController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { - return bc.queryLatestBlocks(nil, count, finalitytypes.QueriedBlockStatus_FINALIZED, true) -} - func (bc *BabylonController) QueryLastFinalizedEpoch() (uint64, error) { resp, err := bc.bbnClient.LatestEpochFromStatus(ckpttypes.Finalized) if err != nil { @@ -257,96 +195,6 @@ func (bc *BabylonController) QueryLastFinalizedEpoch() (uint64, error) { return resp.RawCheckpoint.EpochNum, nil } -func (bc *BabylonController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { - if endHeight < startHeight { - return nil, fmt.Errorf("the startHeight %v should not be higher than the endHeight %v", startHeight, endHeight) - } - count := endHeight - startHeight + 1 - if count > limit { - count = limit - } - return bc.queryLatestBlocks(sdk.Uint64ToBigEndian(startHeight), count, finalitytypes.QueriedBlockStatus_ANY, false) -} - -func (bc *BabylonController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { - var blocks []*types.BlockInfo - pagination := &sdkquery.PageRequest{ - Limit: count, - Reverse: reverse, - Key: startKey, - } - - res, err := bc.bbnClient.QueryClient.ListBlocks(status, pagination) - if err != nil { - return nil, fmt.Errorf("failed to query finalized blocks: %v", err) - } - - for _, b := range res.Blocks { - ib := &types.BlockInfo{ - Height: b.Height, - Hash: b.AppHash, - } - blocks = append(blocks, ib) - } - - return blocks, nil -} - -func getContextWithCancel(timeout time.Duration) (context.Context, context.CancelFunc) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - return ctx, cancel -} - -func (bc *BabylonController) QueryBlock(height uint64) (*types.BlockInfo, error) { - res, err := bc.bbnClient.QueryClient.Block(height) - if err != nil { - return nil, fmt.Errorf("failed to query indexed block at height %v: %w", height, err) - } - - return &types.BlockInfo{ - Height: height, - Hash: res.Block.AppHash, - Finalized: res.Block.Finalized, - }, nil -} - -func (bc *BabylonController) QueryActivatedHeight() (uint64, error) { - res, err := bc.bbnClient.QueryClient.ActivatedHeight() - if err != nil { - return 0, fmt.Errorf("failed to query activated height: %w", err) - } - - return res.Height, nil -} - -func (bc *BabylonController) QueryBestBlock() (*types.BlockInfo, error) { - blocks, err := bc.queryLatestBlocks(nil, 1, finalitytypes.QueriedBlockStatus_ANY, true) - if err != nil || len(blocks) != 1 { - // try query comet block if the index block query is not available - return bc.queryCometBestBlock() - } - - return blocks[0], nil -} - -func (bc *BabylonController) queryCometBestBlock() (*types.BlockInfo, error) { - ctx, cancel := getContextWithCancel(bc.cfg.Timeout) - // this will return 20 items at max in the descending order (highest first) - chainInfo, err := bc.bbnClient.RPCClient.BlockchainInfo(ctx, 0, 0) - defer cancel() - - if err != nil { - return nil, err - } - - // Returning response directly, if header with specified number did not exist - // at request will contain nil header - return &types.BlockInfo{ - Height: uint64(chainInfo.BlockMetas[0].Header.Height), - Hash: chainInfo.BlockMetas[0].Header.AppHash, - }, nil -} - func (bc *BabylonController) Close() error { if !bc.bbnClient.IsRunning() { return nil diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go new file mode 100644 index 00000000..ae470ee7 --- /dev/null +++ b/clientcontroller/babylon_consumer.go @@ -0,0 +1,281 @@ +package clientcontroller + +import ( + "context" + "fmt" + "time" + + sdkErr "cosmossdk.io/errors" + bbnclient "github.com/babylonchain/babylon/client/client" + bbntypes "github.com/babylonchain/babylon/types" + btcstakingtypes "github.com/babylonchain/babylon/x/btcstaking/types" + finalitytypes "github.com/babylonchain/babylon/x/finality/types" + fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" + "github.com/babylonchain/finality-provider/types" + "github.com/btcsuite/btcd/btcec/v2" + "github.com/btcsuite/btcd/chaincfg" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkquery "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/relayer/v2/relayer/provider" + "go.uber.org/zap" +) + +var _ ConsumerController = &BabylonConsumerController{} + +type BabylonConsumerController struct { + bbnClient *bbnclient.Client + cfg *fpcfg.BBNConfig + btcParams *chaincfg.Params + logger *zap.Logger +} + +func NewBabylonConsumerController( + cfg *fpcfg.BBNConfig, + btcParams *chaincfg.Params, + logger *zap.Logger, +) (*BabylonConsumerController, error) { + + bbnConfig := fpcfg.BBNConfigToBabylonConfig(cfg) + + if err := bbnConfig.Validate(); err != nil { + return nil, fmt.Errorf("invalid config for Babylon client: %w", err) + } + + bc, err := bbnclient.New( + &bbnConfig, + logger, + ) + if err != nil { + return nil, fmt.Errorf("failed to create Babylon client: %w", err) + } + + return &BabylonConsumerController{ + bc, + cfg, + btcParams, + logger, + }, nil +} + +func (bc *BabylonConsumerController) mustGetTxSigner() string { + signer := bc.GetKeyAddress() + prefix := bc.cfg.AccountPrefix + return sdk.MustBech32ifyAddressBytes(prefix, signer) +} + +func (bc *BabylonConsumerController) GetKeyAddress() sdk.AccAddress { + // get key address, retrieves address based on key name which is configured in + // cfg *stakercfg.BBNConfig. If this fails, it means we have misconfiguration problem + // and we should panic. + // This is checked at the start of BabylonConsumerController, so if it fails something is really wrong + + keyRec, err := bc.bbnClient.GetKeyring().Key(bc.cfg.Key) + + if err != nil { + panic(fmt.Sprintf("Failed to get key address: %s", err)) + } + + addr, err := keyRec.GetAddress() + + if err != nil { + panic(fmt.Sprintf("Failed to get key address: %s", err)) + } + + return addr +} + +func (bc *BabylonConsumerController) reliablySendMsg(msg sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { + return bc.reliablySendMsgs([]sdk.Msg{msg}, expectedErrs, unrecoverableErrs) +} + +func (bc *BabylonConsumerController) reliablySendMsgs(msgs []sdk.Msg, expectedErrs []*sdkErr.Error, unrecoverableErrs []*sdkErr.Error) (*provider.RelayerTxResponse, error) { + return bc.bbnClient.ReliablySendMsgs( + context.Background(), + msgs, + expectedErrs, + unrecoverableErrs, + ) +} + +// SubmitFinalitySig submits the finality signature via a MsgAddVote to Babylon +func (bc *BabylonConsumerController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { + msg := &finalitytypes.MsgAddFinalitySig{ + Signer: bc.mustGetTxSigner(), + FpBtcPk: bbntypes.NewBIP340PubKeyFromBTCPK(fpPk), + BlockHeight: blockHeight, + BlockAppHash: blockHash, + FinalitySig: bbntypes.NewSchnorrEOTSSigFromModNScalar(sig), + } + + unrecoverableErrs := []*sdkErr.Error{ + finalitytypes.ErrInvalidFinalitySig, + finalitytypes.ErrPubRandNotFound, + btcstakingtypes.ErrFpAlreadySlashed, + } + + res, err := bc.reliablySendMsg(msg, emptyErrs, unrecoverableErrs) + if err != nil { + return nil, err + } + + return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil +} + +// SubmitBatchFinalitySigs submits a batch of finality signatures to Babylon +func (bc *BabylonConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { + if len(blocks) != len(sigs) { + return nil, fmt.Errorf("the number of blocks %v should match the number of finality signatures %v", len(blocks), len(sigs)) + } + + msgs := make([]sdk.Msg, 0, len(blocks)) + for i, b := range blocks { + msg := &finalitytypes.MsgAddFinalitySig{ + Signer: bc.mustGetTxSigner(), + FpBtcPk: bbntypes.NewBIP340PubKeyFromBTCPK(fpPk), + BlockHeight: b.Height, + BlockAppHash: b.Hash, + FinalitySig: bbntypes.NewSchnorrEOTSSigFromModNScalar(sigs[i]), + } + msgs = append(msgs, msg) + } + + unrecoverableErrs := []*sdkErr.Error{ + finalitytypes.ErrInvalidFinalitySig, + finalitytypes.ErrPubRandNotFound, + btcstakingtypes.ErrFpAlreadySlashed, + } + + res, err := bc.reliablySendMsgs(msgs, emptyErrs, unrecoverableErrs) + if err != nil { + return nil, err + } + + return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil +} + +func (bc *BabylonConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { + fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk) + res, err := bc.bbnClient.QueryClient.FinalityProvider(fpPubKey.MarshalHex()) + if err != nil { + return false, fmt.Errorf("failed to query the finality provider %s: %v", fpPubKey.MarshalHex(), err) + } + + slashed := res.FinalityProvider.SlashedBtcHeight > 0 + + return slashed, nil +} + +// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height +func (bc *BabylonConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { + res, err := bc.bbnClient.QueryClient.FinalityProviderPowerAtHeight( + bbntypes.NewBIP340PubKeyFromBTCPK(fpPk).MarshalHex(), + blockHeight, + ) + if err != nil { + return 0, fmt.Errorf("failed to query the finality provider's voting power at height %d: %w", blockHeight, err) + } + + return res.VotingPower, nil +} + +func (bc *BabylonConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { + return bc.queryLatestBlocks(nil, count, finalitytypes.QueriedBlockStatus_FINALIZED, true) +} + +func (bc *BabylonConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { + if endHeight < startHeight { + return nil, fmt.Errorf("the startHeight %v should not be higher than the endHeight %v", startHeight, endHeight) + } + count := endHeight - startHeight + 1 + if count > limit { + count = limit + } + return bc.queryLatestBlocks(sdk.Uint64ToBigEndian(startHeight), count, finalitytypes.QueriedBlockStatus_ANY, false) +} + +func (bc *BabylonConsumerController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { + var blocks []*types.BlockInfo + pagination := &sdkquery.PageRequest{ + Limit: count, + Reverse: reverse, + Key: startKey, + } + + res, err := bc.bbnClient.QueryClient.ListBlocks(status, pagination) + if err != nil { + return nil, fmt.Errorf("failed to query finalized blocks: %v", err) + } + + for _, b := range res.Blocks { + ib := &types.BlockInfo{ + Height: b.Height, + Hash: b.AppHash, + } + blocks = append(blocks, ib) + } + + return blocks, nil +} + +func getContextWithCancel(timeout time.Duration) (context.Context, context.CancelFunc) { + ctx, cancel := context.WithTimeout(context.Background(), timeout) + return ctx, cancel +} + +func (bc *BabylonConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + res, err := bc.bbnClient.QueryClient.Block(height) + if err != nil { + return nil, fmt.Errorf("failed to query indexed block at height %v: %w", height, err) + } + + return &types.BlockInfo{ + Height: height, + Hash: res.Block.AppHash, + Finalized: res.Block.Finalized, + }, nil +} + +func (bc *BabylonConsumerController) QueryActivatedHeight() (uint64, error) { + res, err := bc.bbnClient.QueryClient.ActivatedHeight() + if err != nil { + return 0, fmt.Errorf("failed to query activated height: %w", err) + } + + return res.Height, nil +} + +func (bc *BabylonConsumerController) QueryBestBlock() (*types.BlockInfo, error) { + blocks, err := bc.queryLatestBlocks(nil, 1, finalitytypes.QueriedBlockStatus_ANY, true) + if err != nil || len(blocks) != 1 { + // try query comet block if the index block query is not available + return bc.queryCometBestBlock() + } + + return blocks[0], nil +} + +func (bc *BabylonConsumerController) queryCometBestBlock() (*types.BlockInfo, error) { + ctx, cancel := getContextWithCancel(bc.cfg.Timeout) + // this will return 20 items at max in the descending order (highest first) + chainInfo, err := bc.bbnClient.RPCClient.BlockchainInfo(ctx, 0, 0) + defer cancel() + + if err != nil { + return nil, err + } + + // Returning response directly, if header with specified number did not exist + // at request will contain nil header + return &types.BlockInfo{ + Height: uint64(chainInfo.BlockMetas[0].Header.Height), + Hash: chainInfo.BlockMetas[0].Header.AppHash, + }, nil +} + +func (bc *BabylonConsumerController) Close() error { + if !bc.bbnClient.IsRunning() { + return nil + } + + return bc.bbnClient.Stop() +} diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index f6597c21..c29a11de 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -14,6 +14,7 @@ import ( const ( babylonConsumerChainName = "babylon" + evmConsumerChainName = "evm" ) type ClientController interface { @@ -29,6 +30,40 @@ type ClientController interface { masterPubRand string, ) (*types.TxResponse, uint64, error) + // Note: the following queries are only for PoC + + // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height + QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) + + // QueryFinalityProviderSlashed queries if the finality provider is slashed + QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) + + // QueryLastFinalizedEpoch returns the last finalised epoch of Babylon + QueryLastFinalizedEpoch() (uint64, error) + + Close() error +} + +func NewClientController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ClientController, error) { + var ( + cc ClientController + err error + ) + switch chainName { + case babylonConsumerChainName: + cc, err = NewBabylonController(bbnConfig, netParams, logger) + if err != nil { + return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) + } + default: + return nil, fmt.Errorf("unsupported consumer chain") + } + + return cc, err +} + +type ConsumerController interface { + // SubmitFinalitySig submits the finality signature to the consumer chain SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) @@ -59,20 +94,17 @@ type ClientController interface { // error will be returned if the consumer chain has not been activated QueryActivatedHeight() (uint64, error) - // QueryLastFinalizedEpoch returns the last finalised epoch of Babylon - QueryLastFinalizedEpoch() (uint64, error) - Close() error } -func NewClientController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ClientController, error) { +func NewConsumerController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ConsumerController, error) { var ( - cc ClientController + ccc ConsumerController err error ) switch chainName { case babylonConsumerChainName: - cc, err = NewBabylonController(bbnConfig, netParams, logger) + ccc, err = NewBabylonConsumerController(bbnConfig, netParams, logger) if err != nil { return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) } @@ -80,5 +112,5 @@ func NewClientController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams return nil, fmt.Errorf("unsupported consumer chain") } - return cc, err + return ccc, err } diff --git a/finality-provider/service/app.go b/finality-provider/service/app.go index 65a2072d..fc46efb9 100644 --- a/finality-provider/service/app.go +++ b/finality-provider/service/app.go @@ -35,12 +35,13 @@ type FinalityProviderApp struct { wg sync.WaitGroup quit chan struct{} - cc clientcontroller.ClientController - kr keyring.Keyring - fps *store.FinalityProviderStore - config *fpcfg.Config - logger *zap.Logger - input *strings.Reader + cc clientcontroller.ClientController + consumerCon clientcontroller.ConsumerController + kr keyring.Keyring + fps *store.FinalityProviderStore + config *fpcfg.Config + logger *zap.Logger + input *strings.Reader fpManager *FinalityProviderManager eotsManager eotsmanager.EOTSManager @@ -61,7 +62,10 @@ func NewFinalityProviderAppFromConfig( if err != nil { return nil, fmt.Errorf("failed to create rpc client for the consumer chain %s: %v", cfg.ChainName, err) } - + consumerCon, err := clientcontroller.NewConsumerController(cfg.ChainName, 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) + } // if the EOTSManagerAddress is empty, run a local EOTS manager; // otherwise connect a remote one with a gRPC client em, err := client.NewEOTSManagerGRpcClient(cfg.EOTSManagerAddress) @@ -71,12 +75,13 @@ func NewFinalityProviderAppFromConfig( logger.Info("successfully connected to a remote EOTS manager", zap.String("address", cfg.EOTSManagerAddress)) - return NewFinalityProviderApp(cfg, cc, em, db, logger) + return NewFinalityProviderApp(cfg, cc, consumerCon, em, db, logger) } func NewFinalityProviderApp( config *fpcfg.Config, cc clientcontroller.ClientController, + consumerCon clientcontroller.ConsumerController, em eotsmanager.EOTSManager, db kvdb.Backend, logger *zap.Logger, @@ -99,13 +104,14 @@ func NewFinalityProviderApp( fpMetrics := metrics.NewFpMetrics() - fpm, err := NewFinalityProviderManager(fpStore, config, cc, em, fpMetrics, logger) + fpm, err := NewFinalityProviderManager(fpStore, config, cc, consumerCon, em, fpMetrics, logger) if err != nil { return nil, fmt.Errorf("failed to create finality-provider manager: %w", err) } return &FinalityProviderApp{ cc: cc, + consumerCon: consumerCon, fps: fpStore, kr: kr, config: config, @@ -225,7 +231,7 @@ func (app *FinalityProviderApp) getFpPrivKey(fpPk []byte) (*btcec.PrivateKey, er // SyncFinalityProviderStatus syncs the status of the finality-providers func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { - latestBlock, err := app.cc.QueryBestBlock() + latestBlock, err := app.consumerCon.QueryBestBlock() if err != nil { return err } @@ -236,7 +242,7 @@ func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { } for _, fp := range fps { - vp, err := app.cc.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlock.Height) + vp, err := app.consumerCon.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlock.Height) if err != nil { // if error occured then the finality-provider is not registered in the Babylon chain yet continue diff --git a/finality-provider/service/app_test.go b/finality-provider/service/app_test.go index 69ebd01c..03d8b230 100644 --- a/finality-provider/service/app_test.go +++ b/finality-provider/service/app_test.go @@ -61,7 +61,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) { fpCfg.PollerConfig.StaticChainScanningStartHeight = randomStartingHeight fpdb, err := fpCfg.DatabaseConfig.GetDbBackend() require.NoError(t, err) - app, err := service.NewFinalityProviderApp(&fpCfg, mockClientController, em, fpdb, logger) + app, err := service.NewFinalityProviderApp(&fpCfg, mockClientController, mockClientController, em, fpdb, logger) require.NoError(t, err) defer func() { err = fpdb.Close() diff --git a/finality-provider/service/chain_poller.go b/finality-provider/service/chain_poller.go index e7fe1c40..3c40db11 100644 --- a/finality-provider/service/chain_poller.go +++ b/finality-provider/service/chain_poller.go @@ -43,6 +43,7 @@ type ChainPoller struct { quit chan struct{} cc clientcontroller.ClientController + consumerCon clientcontroller.ConsumerController cfg *cfg.ChainPollerConfig metrics *metrics.FpMetrics blockInfoChan chan *types.BlockInfo @@ -55,6 +56,7 @@ func NewChainPoller( logger *zap.Logger, cfg *cfg.ChainPollerConfig, cc clientcontroller.ClientController, + consumerCon clientcontroller.ConsumerController, metrics *metrics.FpMetrics, ) *ChainPoller { return &ChainPoller{ @@ -62,6 +64,7 @@ func NewChainPoller( logger: logger, cfg: cfg, cc: cc, + consumerCon: consumerCon, metrics: metrics, blockInfoChan: make(chan *types.BlockInfo, cfg.BufferSize), skipHeightChan: make(chan *skipHeightRequest), @@ -129,7 +132,7 @@ func (cp *ChainPoller) latestBlockWithRetry() (*types.BlockInfo, error) { ) if err := retry.Do(func() error { - latestBlock, err = cp.cc.QueryBestBlock() + latestBlock, err = cp.consumerCon.QueryBestBlock() if err != nil { return err } @@ -153,7 +156,7 @@ func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { err error ) if err := retry.Do(func() error { - block, err = cp.cc.QueryBlock(height) + block, err = cp.consumerCon.QueryBlock(height) if err != nil { return err } @@ -205,7 +208,7 @@ func (cp *ChainPoller) validateStartHeight(startHeight uint64) error { func (cp *ChainPoller) waitForActivation() { // ensure that the startHeight is no lower than the activated height for { - activatedHeight, err := cp.cc.QueryActivatedHeight() + activatedHeight, err := cp.consumerCon.QueryActivatedHeight() if err != nil { cp.logger.Debug("failed to query the consumer chain for the activated height", zap.Error(err)) } else { diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 4e899ed2..2b918540 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -50,7 +50,7 @@ func FuzzChainPoller_Start(f *testing.F) { m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 10 * time.Millisecond - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) err := poller.Start(startHeight) require.NoError(t, err) defer func() { @@ -101,7 +101,7 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 1 * time.Second - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) // should expect error if the poller is not started err := poller.SkipToHeight(skipHeight) require.Error(t, err) diff --git a/finality-provider/service/fastsync.go b/finality-provider/service/fastsync.go index 4a033378..77089faa 100644 --- a/finality-provider/service/fastsync.go +++ b/finality-provider/service/fastsync.go @@ -33,7 +33,7 @@ func (fp *FinalityProviderInstance) FastSync(startHeight, endHeight uint64) (*Fa // 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 { - blocks, err := fp.cc.QueryBlocks(startHeight, endHeight, fp.cfg.FastSyncLimit) + blocks, err := fp.consumerCon.QueryBlocks(startHeight, endHeight, fp.cfg.FastSyncLimit) if err != nil { return nil, err } diff --git a/finality-provider/service/fastsync_test.go b/finality-provider/service/fastsync_test.go index 52c0ebbb..187b1d7b 100644 --- a/finality-provider/service/fastsync_test.go +++ b/finality-provider/service/fastsync_test.go @@ -27,7 +27,7 @@ func FuzzFastSync(f *testing.F) { mockClientController := testutil.PrepareMockedClientController(t, r, randomStartingHeight, currentHeight) // mock finalised BTC timestamped mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight, randomRegiteredEpoch) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index b5f80695..c9f21a40 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -33,11 +33,12 @@ type FinalityProviderInstance struct { state *fpState cfg *fpcfg.Config - logger *zap.Logger - em eotsmanager.EOTSManager - cc clientcontroller.ClientController - poller *ChainPoller - metrics *metrics.FpMetrics + logger *zap.Logger + em eotsmanager.EOTSManager + cc clientcontroller.ClientController + consumerCon clientcontroller.ConsumerController + poller *ChainPoller + metrics *metrics.FpMetrics // passphrase is used to unlock private keys passphrase string @@ -60,6 +61,7 @@ func NewFinalityProviderInstance( cfg *fpcfg.Config, s *store.FinalityProviderStore, cc clientcontroller.ClientController, + consumerCon clientcontroller.ConsumerController, em eotsmanager.EOTSManager, metrics *metrics.FpMetrics, passphrase string, @@ -101,6 +103,7 @@ func NewFinalityProviderInstance( passphrase: passphrase, em: em, cc: cc, + consumerCon: consumerCon, metrics: metrics, }, nil } @@ -120,7 +123,7 @@ func (fp *FinalityProviderInstance) Start() error { fp.logger.Info("the finality-provider has been bootstrapped", zap.String("pk", fp.GetBtcPkHex()), zap.Uint64("height", startHeight)) - poller := NewChainPoller(fp.logger, fp.cfg.PollerConfig, fp.cc, fp.metrics) + poller := NewChainPoller(fp.logger, fp.cfg.PollerConfig, fp.cc, fp.consumerCon, fp.metrics) if err := poller.Start(startHeight + 1); err != nil { return fmt.Errorf("failed to start the poller: %w", err) @@ -322,7 +325,7 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (* } // get the last finalized height - lastFinalizedBlocks, err := fp.cc.QueryLatestFinalizedBlocks(1) + lastFinalizedBlocks, err := fp.consumerCon.QueryLatestFinalizedBlocks(1) if err != nil { return nil, err } @@ -463,7 +466,7 @@ func (fp *FinalityProviderInstance) retrySubmitFinalitySignatureUntilBlockFinali } func (fp *FinalityProviderInstance) checkBlockFinalization(height uint64) (bool, error) { - b, err := fp.cc.QueryBlock(height) + b, err := fp.consumerCon.QueryBlock(height) if err != nil { return false, err } @@ -479,7 +482,7 @@ func (fp *FinalityProviderInstance) SubmitFinalitySignature(b *types.BlockInfo) } // send finality signature to the consumer chain - res, err := fp.cc.SubmitFinalitySig(fp.GetBtcPk(), b.Height, b.Hash, eotsSig.ToModNScalar()) + res, err := fp.consumerCon.SubmitFinalitySig(fp.GetBtcPk(), b.Height, b.Hash, eotsSig.ToModNScalar()) if err != nil { return nil, fmt.Errorf("failed to send finality signature to the consumer chain: %w", err) } @@ -511,7 +514,7 @@ func (fp *FinalityProviderInstance) SubmitBatchFinalitySignatures(blocks []*type } // send finality signature to the consumer chain - res, err := fp.cc.SubmitBatchFinalitySigs(fp.GetBtcPk(), blocks, sigs) + res, err := fp.consumerCon.SubmitBatchFinalitySigs(fp.GetBtcPk(), blocks, sigs) if err != nil { return nil, fmt.Errorf("failed to send a batch of finality signatures to the consumer chain: %w", err) } @@ -549,7 +552,7 @@ func (fp *FinalityProviderInstance) TestSubmitFinalitySignatureAndExtractPrivKey } // send finality signature to the consumer chain - res, err := fp.cc.SubmitFinalitySig(fp.GetBtcPk(), b.Height, b.Hash, eotsSig.ToModNScalar()) + res, err := fp.consumerCon.SubmitFinalitySig(fp.GetBtcPk(), b.Height, b.Hash, eotsSig.ToModNScalar()) if err != nil { return nil, nil, fmt.Errorf("failed to send finality signature to the consumer chain: %w", err) } @@ -610,7 +613,7 @@ func (fp *FinalityProviderInstance) getPollerStartingHeight() (uint64, error) { func (fp *FinalityProviderInstance) latestFinalizedBlocksWithRetry(count uint64) ([]*types.BlockInfo, error) { var response []*types.BlockInfo if err := retry.Do(func() error { - latestFinalisedBlock, err := fp.cc.QueryLatestFinalizedBlocks(count) + latestFinalisedBlock, err := fp.consumerCon.QueryLatestFinalizedBlocks(count) if err != nil { return err } @@ -636,7 +639,7 @@ func (fp *FinalityProviderInstance) getLatestBlockWithRetry() (*types.BlockInfo, ) if err := retry.Do(func() error { - latestBlock, err = fp.cc.QueryBestBlock() + latestBlock, err = fp.consumerCon.QueryBestBlock() if err != nil { return err } @@ -663,7 +666,7 @@ func (fp *FinalityProviderInstance) GetVotingPowerWithRetry(height uint64) (uint ) if err := retry.Do(func() error { - power, err = fp.cc.QueryFinalityProviderVotingPower(fp.GetBtcPk(), height) + power, err = fp.consumerCon.QueryFinalityProviderVotingPower(fp.GetBtcPk(), height) if err != nil { return err } @@ -689,7 +692,7 @@ func (fp *FinalityProviderInstance) GetFinalityProviderSlashedWithRetry() (bool, ) if err := retry.Do(func() error { - slashed, err = fp.cc.QueryFinalityProviderSlashed(fp.GetBtcPk()) + slashed, err = fp.consumerCon.QueryFinalityProviderSlashed(fp.GetBtcPk()) if err != nil { return err } diff --git a/finality-provider/service/fp_instance_test.go b/finality-provider/service/fp_instance_test.go index 9cc2c696..a139635f 100644 --- a/finality-provider/service/fp_instance_test.go +++ b/finality-provider/service/fp_instance_test.go @@ -34,7 +34,7 @@ func FuzzSubmitFinalitySig(f *testing.F) { // mock finalised BTC timestamped mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, randomStartingHeight, randomRegiteredEpoch) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power @@ -60,7 +60,7 @@ func FuzzSubmitFinalitySig(f *testing.F) { }) } -func startFinalityProviderAppWithRegisteredFp(t *testing.T, r *rand.Rand, cc clientcontroller.ClientController, startingHeight uint64, registeredEpoch uint64) (*service.FinalityProviderApp, *service.FinalityProviderInstance, func()) { +func startFinalityProviderAppWithRegisteredFp(t *testing.T, r *rand.Rand, cc clientcontroller.ClientController, consumerCon clientcontroller.ConsumerController, startingHeight uint64, registeredEpoch uint64) (*service.FinalityProviderApp, *service.FinalityProviderInstance, func()) { logger := zap.NewNop() // create an EOTS manager eotsHomeDir := filepath.Join(t.TempDir(), "eots-home") @@ -78,7 +78,7 @@ func startFinalityProviderAppWithRegisteredFp(t *testing.T, r *rand.Rand, cc cli fpCfg.PollerConfig.StaticChainScanningStartHeight = startingHeight fpdb, err := fpCfg.DatabaseConfig.GetDbBackend() require.NoError(t, err) - app, err := service.NewFinalityProviderApp(&fpCfg, cc, em, fpdb, logger) + app, err := service.NewFinalityProviderApp(&fpCfg, cc, consumerCon, em, fpdb, logger) require.NoError(t, err) err = app.Start() require.NoError(t, err) @@ -95,7 +95,7 @@ func startFinalityProviderAppWithRegisteredFp(t *testing.T, r *rand.Rand, cc cli // TODO: use mock metrics m := metrics.NewFpMetrics() - fpIns, err := service.NewFinalityProviderInstance(fp.GetBIP340BTCPK(), &fpCfg, app.GetFinalityProviderStore(), cc, em, m, passphrase, make(chan *service.CriticalError), logger) + fpIns, err := service.NewFinalityProviderInstance(fp.GetBIP340BTCPK(), &fpCfg, app.GetFinalityProviderStore(), cc, consumerCon, em, m, passphrase, make(chan *service.CriticalError), logger) require.NoError(t, err) cleanUp := func() { diff --git a/finality-provider/service/fp_manager.go b/finality-provider/service/fp_manager.go index 03fef45c..833ba088 100644 --- a/finality-provider/service/fp_manager.go +++ b/finality-provider/service/fp_manager.go @@ -42,11 +42,12 @@ type FinalityProviderManager struct { fpis map[string]*FinalityProviderInstance // needed for initiating finality-provider instances - fps *store.FinalityProviderStore - config *fpcfg.Config - cc clientcontroller.ClientController - em eotsmanager.EOTSManager - logger *zap.Logger + fps *store.FinalityProviderStore + config *fpcfg.Config + cc clientcontroller.ClientController + consumerCon clientcontroller.ConsumerController + em eotsmanager.EOTSManager + logger *zap.Logger metrics *metrics.FpMetrics @@ -59,6 +60,7 @@ func NewFinalityProviderManager( fps *store.FinalityProviderStore, config *fpcfg.Config, cc clientcontroller.ClientController, + consumerCon clientcontroller.ConsumerController, em eotsmanager.EOTSManager, metrics *metrics.FpMetrics, logger *zap.Logger, @@ -70,6 +72,7 @@ func NewFinalityProviderManager( fps: fps, config: config, cc: cc, + consumerCon: consumerCon, em: em, metrics: metrics, logger: logger, @@ -389,7 +392,7 @@ func (fpm *FinalityProviderManager) addFinalityProviderInstance( return fmt.Errorf("finality-provider instance already exists") } - fpIns, err := NewFinalityProviderInstance(pk, fpm.config, fpm.fps, fpm.cc, fpm.em, fpm.metrics, passphrase, fpm.criticalErrChan, fpm.logger) + fpIns, err := NewFinalityProviderInstance(pk, fpm.config, fpm.fps, fpm.cc, fpm.consumerCon, fpm.em, fpm.metrics, passphrase, fpm.criticalErrChan, fpm.logger) if err != nil { return fmt.Errorf("failed to create finality-provider %s instance: %w", pkHex, err) } @@ -411,7 +414,7 @@ func (fpm *FinalityProviderManager) getLatestBlockWithRetry() (*types.BlockInfo, ) if err := retry.Do(func() error { - latestBlock, err = fpm.cc.QueryBestBlock() + latestBlock, err = fpm.consumerCon.QueryBestBlock() if err != nil { return err } diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index 486fcb73..320b6636 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -42,7 +42,7 @@ func FuzzStatusUpdate(f *testing.F) { ctl := gomock.NewController(t) mockClientController := mocks.NewMockClientController(ctl) - vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController) + vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController, mockClientController) defer cleanUp() // setup mocks @@ -93,7 +93,7 @@ func waitForStatus(t *testing.T, fpIns *service.FinalityProviderInstance, s prot }, eventuallyWaitTimeOut, eventuallyPollTime) } -func newFinalityProviderManagerWithRegisteredFp(t *testing.T, r *rand.Rand, cc clientcontroller.ClientController) (*service.FinalityProviderManager, *bbntypes.BIP340PubKey, func()) { +func newFinalityProviderManagerWithRegisteredFp(t *testing.T, r *rand.Rand, cc clientcontroller.ClientController, consumerCon clientcontroller.ConsumerController) (*service.FinalityProviderManager, *bbntypes.BIP340PubKey, func()) { logger := zap.NewNop() // create an EOTS manager eotsHomeDir := filepath.Join(t.TempDir(), "eots-home") @@ -123,7 +123,7 @@ func newFinalityProviderManagerWithRegisteredFp(t *testing.T, r *rand.Rand, cc c require.NoError(t, err) metricsCollectors := metrics.NewFpMetrics() - vm, err := service.NewFinalityProviderManager(fpStore, &fpCfg, cc, em, metricsCollectors, logger) + vm, err := service.NewFinalityProviderManager(fpStore, &fpCfg, cc, consumerCon, em, metricsCollectors, logger) require.NoError(t, err) // create registered finality-provider diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 44cde78b..91e0094e 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -181,7 +181,7 @@ func TestFastSync(t *testing.T) { t.Logf("the latest finalized block is at %v", finalizedHeight) // check if the fast sync works by checking if the gap is not more than 1 - currentHeaderRes, err := tm.BBNClient.QueryBestBlock() + currentHeaderRes, err := tm.BBNConsumerClient.QueryBestBlock() currentHeight := currentHeaderRes.Height t.Logf("the current block is at %v", currentHeight) require.NoError(t, err) diff --git a/itest/test_manager.go b/itest/test_manager.go index 63af3876..df46c714 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -62,6 +62,7 @@ type TestManager struct { Fpa *service.FinalityProviderApp EOTSClient *client.EOTSManagerGRpcClient BBNClient *fpcc.BabylonController + BBNConsumerClient *fpcc.BabylonConsumerController StakingParams *types.StakingParams CovenantPrivKeys []*btcec.PrivateKey baseDir string @@ -103,6 +104,8 @@ func StartManager(t *testing.T) *TestManager { cfg := defaultFpConfig(bh.GetNodeDataDir(), fpHomeDir) bc, err := fpcc.NewBabylonController(cfg.BabylonConfig, &cfg.BTCNetParams, logger) require.NoError(t, err) + bcc, err := fpcc.NewBabylonConsumerController(cfg.BabylonConfig, &cfg.BTCNetParams, logger) + require.NoError(t, err) // 3. prepare EOTS manager eotsHomeDir := filepath.Join(testDir, "eots-home") @@ -115,7 +118,7 @@ func StartManager(t *testing.T) *TestManager { // 4. prepare finality-provider fpdb, err := cfg.DatabaseConfig.GetDbBackend() require.NoError(t, err) - fpApp, err := service.NewFinalityProviderApp(cfg, bc, eotsCli, fpdb, logger) + fpApp, err := service.NewFinalityProviderApp(cfg, bc, bcc, eotsCli, fpdb, logger) require.NoError(t, err) err = fpApp.Start() require.NoError(t, err) @@ -128,6 +131,7 @@ func StartManager(t *testing.T) *TestManager { Fpa: fpApp, EOTSClient: eotsCli, BBNClient: bc, + BBNConsumerClient: bcc, CovenantPrivKeys: covenantPrivKeys, baseDir: testDir, } @@ -313,7 +317,7 @@ func (tm *TestManager) CheckBlockFinalization(t *testing.T, height uint64, num i // as the votes have been collected, the block should be finalized require.Eventually(t, func() bool { - b, err := tm.BBNClient.QueryBlock(height) + b, err := tm.BBNConsumerClient.QueryBlock(height) if err != nil { t.Logf("failed to query block at height %v: %s", height, err.Error()) return false @@ -342,7 +346,7 @@ func (tm *TestManager) WaitForNFinalizedBlocks(t *testing.T, n int) []*types.Blo err error ) require.Eventually(t, func() bool { - blocks, err = tm.BBNClient.QueryLatestFinalizedBlocks(uint64(n)) + blocks, err = tm.BBNConsumerClient.QueryLatestFinalizedBlocks(uint64(n)) if err != nil { t.Logf("failed to get the latest finalized block: %s", err.Error()) return false @@ -365,13 +369,13 @@ func (tm *TestManager) WaitForFpShutDown(t *testing.T, pk *bbntypes.BIP340PubKey } func (tm *TestManager) StopAndRestartFpAfterNBlocks(t *testing.T, n int, fpIns *service.FinalityProviderInstance) { - blockBeforeStop, err := tm.BBNClient.QueryBestBlock() + blockBeforeStop, err := tm.BBNConsumerClient.QueryBestBlock() require.NoError(t, err) err = fpIns.Stop() require.NoError(t, err) require.Eventually(t, func() bool { - headerAfterStop, err := tm.BBNClient.QueryBestBlock() + headerAfterStop, err := tm.BBNConsumerClient.QueryBestBlock() if err != nil { return false } From d451545587efabf543baf13b0014fcd89900d20b Mon Sep 17 00:00:00 2001 From: lesterli Date: Tue, 14 May 2024 17:39:13 +0800 Subject: [PATCH 02/26] feat: Add EVM config (#319) --- clientcontroller/evm_consumer.go | 108 +++++++++++++++++++++++++++++ clientcontroller/interface.go | 35 ++++------ finality-provider/config/config.go | 2 + finality-provider/config/evm.go | 27 ++++++++ finality-provider/service/app.go | 6 +- go.mod | 9 ++- go.sum | 6 ++ 7 files changed, 169 insertions(+), 24 deletions(-) create mode 100644 clientcontroller/evm_consumer.go create mode 100644 finality-provider/config/evm.go diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go new file mode 100644 index 00000000..f664f849 --- /dev/null +++ b/clientcontroller/evm_consumer.go @@ -0,0 +1,108 @@ +package clientcontroller + +import ( + "fmt" + + finalitytypes "github.com/babylonchain/babylon/x/finality/types" + fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" + "github.com/babylonchain/finality-provider/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/rpc" + + "github.com/btcsuite/btcd/btcec/v2" + "go.uber.org/zap" +) + +var _ ConsumerController = &EVMConsumerController{} + +type EVMConsumerController struct { + evmClient *rpc.Client + cfg *fpcfg.EVMConfig + logger *zap.Logger +} + +func NewEVMConsumerController( + evmCfg *fpcfg.EVMConfig, + logger *zap.Logger, +) (*EVMConsumerController, error) { + if err := evmCfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid config for EVM RPC client: %w", err) + } + ec, err := rpc.Dial(evmCfg.RPCAddr) + if err != nil { + return nil, fmt.Errorf("failed to connect to the EVM RPC server %s: %w", evmCfg.RPCAddr, err) + } + return &EVMConsumerController{ + ec, + evmCfg, + logger, + }, nil +} + +// SubmitFinalitySig submits the finality signature +func (ec *EVMConsumerController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { + + return &types.TxResponse{TxHash: "", Events: nil}, nil +} + +// SubmitBatchFinalitySigs submits a batch of finality signatures to Babylon +func (ec *EVMConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { + if len(blocks) != len(sigs) { + return nil, fmt.Errorf("the number of blocks %v should match the number of finality signatures %v", len(blocks), len(sigs)) + } + + return &types.TxResponse{TxHash: "", Events: nil}, nil +} + +func (ec *EVMConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { + + return false, nil +} + +// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height +func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { + + return 0, nil +} + +func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { + return ec.queryLatestBlocks(nil, count, finalitytypes.QueriedBlockStatus_FINALIZED, true) +} + +func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { + + return ec.queryLatestBlocks(sdk.Uint64ToBigEndian(startHeight), 0, finalitytypes.QueriedBlockStatus_ANY, false) +} + +func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { + var blocks []*types.BlockInfo + + return blocks, nil +} + +func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + + return &types.BlockInfo{ + Height: height, + Hash: nil, + Finalized: false, + }, nil +} + +func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { + + return 0, nil +} + +func (ec *EVMConsumerController) QueryBestBlock() (*types.BlockInfo, error) { + + return &types.BlockInfo{ + Height: uint64(0), + Hash: nil, + }, nil +} + +func (ec *EVMConsumerController) Close() error { + ec.evmClient.Close() + return nil +} diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index c29a11de..4e05ae5a 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -5,7 +5,6 @@ import ( "cosmossdk.io/math" "github.com/btcsuite/btcd/btcec/v2" - "github.com/btcsuite/btcd/chaincfg" "go.uber.org/zap" fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" @@ -13,8 +12,8 @@ import ( ) const ( - babylonConsumerChainName = "babylon" - evmConsumerChainName = "evm" + BabylonConsumerChainName = "babylon" + EVMConsumerChainName = "evm" ) type ClientController interface { @@ -44,19 +43,10 @@ type ClientController interface { Close() error } -func NewClientController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ClientController, error) { - var ( - cc ClientController - err error - ) - switch chainName { - case babylonConsumerChainName: - cc, err = NewBabylonController(bbnConfig, netParams, logger) - if err != nil { - return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) - } - default: - return nil, fmt.Errorf("unsupported consumer chain") +func NewClientController(config *fpcfg.Config, logger *zap.Logger) (ClientController, error) { + cc, err := NewBabylonController(config.BabylonConfig, &config.BTCNetParams, logger) + if err != nil { + return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) } return cc, err @@ -97,17 +87,22 @@ type ConsumerController interface { Close() error } -func NewConsumerController(chainName string, bbnConfig *fpcfg.BBNConfig, netParams *chaincfg.Params, logger *zap.Logger) (ConsumerController, error) { +func NewConsumerController(config *fpcfg.Config, logger *zap.Logger) (ConsumerController, error) { var ( ccc ConsumerController err error ) - switch chainName { - case babylonConsumerChainName: - ccc, err = NewBabylonConsumerController(bbnConfig, netParams, logger) + switch config.ChainName { + case BabylonConsumerChainName: + ccc, err = NewBabylonConsumerController(config.BabylonConfig, &config.BTCNetParams, logger) if err != nil { return nil, fmt.Errorf("failed to create Babylon rpc client: %w", err) } + case EVMConsumerChainName: + ccc, err = NewEVMConsumerController(config.EVMConfig, logger) + if err != nil { + return nil, fmt.Errorf("failed to create EVM rpc client: %w", err) + } default: return nil, fmt.Errorf("unsupported consumer chain") } diff --git a/finality-provider/config/config.go b/finality-provider/config/config.go index de2e4b84..395f0827 100644 --- a/finality-provider/config/config.go +++ b/finality-provider/config/config.go @@ -79,6 +79,8 @@ type Config struct { BabylonConfig *BBNConfig `group:"babylon" namespace:"babylon"` + EVMConfig *EVMConfig `group:"evm" namespace:"evm"` + RpcListener string `long:"rpclistener" description:"the listener for RPC connections, e.g., 127.0.0.1:1234"` Metrics *metrics.Config `group:"metrics" namespace:"metrics"` diff --git a/finality-provider/config/evm.go b/finality-provider/config/evm.go new file mode 100644 index 00000000..68f9714a --- /dev/null +++ b/finality-provider/config/evm.go @@ -0,0 +1,27 @@ +package config + +import ( + "fmt" + "net/url" +) + +const ( + defaultEVMRPCAddr = "http://127.0.0.1:8545" +) + +type EVMConfig struct { + RPCAddr string `long:"rpc-address" description:"address of the rpc server to connect to"` +} + +func DefaultEVMConfig() EVMConfig { + return EVMConfig{ + RPCAddr: defaultEVMRPCAddr, + } +} + +func (cfg *EVMConfig) Validate() error { + if _, err := url.Parse(cfg.RPCAddr); err != nil { + return fmt.Errorf("rpc-addr is not correctly formatted: %w", err) + } + return nil +} diff --git a/finality-provider/service/app.go b/finality-provider/service/app.go index fc46efb9..ae870645 100644 --- a/finality-provider/service/app.go +++ b/finality-provider/service/app.go @@ -58,11 +58,11 @@ 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, 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 Babylon chain: %v", err) } - consumerCon, err := clientcontroller.NewConsumerController(cfg.ChainName, cfg.BabylonConfig, &cfg.BTCNetParams, logger) + consumerCon, err := clientcontroller.NewConsumerController(cfg, logger) if err != nil { return nil, fmt.Errorf("failed to create rpc client for the consumer chain %s: %v", cfg.ChainName, err) } diff --git a/go.mod b/go.mod index 46201905..80c419eb 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/cosmos/go-bip39 v1.0.0 github.com/cosmos/gogoproto v1.4.11 github.com/cosmos/relayer/v2 v2.5.2 + github.com/ethereum/go-ethereum v1.13.15 github.com/gogo/protobuf v1.3.3 github.com/golang/mock v1.6.0 github.com/jessevdk/go-flags v1.5.0 @@ -59,6 +60,8 @@ require ( github.com/CosmWasm/wasmvm v1.5.2 // indirect github.com/DataDog/datadog-go v3.2.0+incompatible // indirect github.com/DataDog/zstd v1.5.5 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/aead/siphash v1.0.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/aws/aws-sdk-go v1.44.312 // indirect @@ -98,6 +101,7 @@ require ( github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect github.com/danieljoos/wincred v1.1.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/deckarep/golang-set/v2 v2.1.0 // indirect github.com/decred/dcrd/crypto/blake256 v1.0.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect @@ -111,7 +115,6 @@ require ( github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/emicklei/dot v1.6.1 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect - github.com/ethereum/go-ethereum v1.13.15 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fergusstrange/embedded-postgres v1.10.0 // indirect @@ -122,6 +125,7 @@ require ( github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect @@ -222,6 +226,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -236,6 +241,8 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/ulikunitz/xz v0.5.11 // indirect diff --git a/go.sum b/go.sum index 4fbc1398..e46b4050 100644 --- a/go.sum +++ b/go.sum @@ -453,6 +453,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI= +github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= @@ -562,6 +564,7 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -1562,6 +1565,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1639,6 +1643,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= From 9aa678e64339969bbe02c790011e38033c665c4d Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sat, 18 May 2024 15:13:51 -0400 Subject: [PATCH 03/26] fix tests & more split --- Makefile | 2 +- clientcontroller/babylon.go | 13 -- clientcontroller/babylon_consumer.go | 12 -- clientcontroller/evm_consumer.go | 9 +- clientcontroller/interface.go | 6 - finality-provider/service/app_test.go | 12 +- .../service/chain_poller_test.go | 26 +-- finality-provider/service/fastsync_test.go | 15 +- finality-provider/service/fp_instance.go | 2 +- finality-provider/service/fp_instance_test.go | 11 +- finality-provider/service/fp_manager_test.go | 21 +-- .../mocks/{babylon.go => clientcontroller.go} | 177 +++++++++++------- testutil/utils.go | 24 ++- 13 files changed, 172 insertions(+), 158 deletions(-) rename testutil/mocks/{babylon.go => clientcontroller.go} (64%) diff --git a/Makefile b/Makefile index c8d6b32c..4877fd83 100644 --- a/Makefile +++ b/Makefile @@ -75,7 +75,7 @@ proto-gen: mock-gen: mkdir -p $(MOCKS_DIR) - $(MOCKGEN_CMD) -source=clientcontroller/interface.go -package mocks -destination $(MOCKS_DIR)/babylon.go + $(MOCKGEN_CMD) -source=clientcontroller/interface.go -package mocks -destination $(MOCKS_DIR)/clientcontroller.go .PHONY: mock-gen diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go index 7a28467a..703d5c68 100644 --- a/clientcontroller/babylon.go +++ b/clientcontroller/babylon.go @@ -162,19 +162,6 @@ func (bc *BabylonController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) return slashed, nil } -// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height -func (bc *BabylonController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { - res, err := bc.bbnClient.QueryClient.FinalityProviderPowerAtHeight( - bbntypes.NewBIP340PubKeyFromBTCPK(fpPk).MarshalHex(), - blockHeight, - ) - if err != nil { - return 0, fmt.Errorf("failed to query the finality provider's voting power at height %d: %w", blockHeight, err) - } - - return res.VotingPower, nil -} - // QueryFinalityProviderRegisteredEpoch queries the registered epoch of the finality provider func (bc *BabylonController) QueryFinalityProviderRegisteredEpoch(fpPk *btcec.PublicKey) (uint64, error) { res, err := bc.bbnClient.QueryClient.FinalityProvider( diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index ae470ee7..8060942f 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -153,18 +153,6 @@ func (bc *BabylonConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicK return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil } -func (bc *BabylonConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk) - res, err := bc.bbnClient.QueryClient.FinalityProvider(fpPubKey.MarshalHex()) - if err != nil { - return false, fmt.Errorf("failed to query the finality provider %s: %v", fpPubKey.MarshalHex(), err) - } - - slashed := res.FinalityProvider.SlashedBtcHeight > 0 - - return slashed, nil -} - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height func (bc *BabylonConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { res, err := bc.bbnClient.QueryClient.FinalityProviderPowerAtHeight( diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index f664f849..3e73aab2 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -13,6 +13,10 @@ import ( "go.uber.org/zap" ) +// TODO: rename the file name, class name and etc +// This is not a simple EVM chain. It's a OP Stack L2 chain, which has many +// implications. So we should rename to sth like e.g. OPStackL2Consumer +// This helps distinguish from pure EVM sidechains e.g. Binance Chain var _ ConsumerController = &EVMConsumerController{} type EVMConsumerController struct { @@ -54,11 +58,6 @@ func (ec *EVMConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, return &types.TxResponse{TxHash: "", Events: nil}, nil } -func (ec *EVMConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - - return false, nil -} - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index 4e05ae5a..d381bc6d 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -31,9 +31,6 @@ type ClientController interface { // Note: the following queries are only for PoC - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height - QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) - // QueryFinalityProviderSlashed queries if the finality provider is slashed QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) @@ -65,9 +62,6 @@ type ConsumerController interface { // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) - // QueryFinalityProviderSlashed queries if the finality provider is slashed - QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) - // QueryLatestFinalizedBlocks returns the latest finalized blocks QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) diff --git a/finality-provider/service/app_test.go b/finality-provider/service/app_test.go index 03d8b230..040378e1 100644 --- a/finality-provider/service/app_test.go +++ b/finality-provider/service/app_test.go @@ -48,11 +48,11 @@ 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.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() - mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), gomock.Any()).Return(uint64(0), nil).AnyTimes() - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(uint64(0), nil).AnyTimes() + mockBabylonController := testutil.PrepareMockedBabylonController(t, uint64(0)) // Create randomized config fpHomeDir := filepath.Join(t.TempDir(), "fp-home") @@ -61,7 +61,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) { fpCfg.PollerConfig.StaticChainScanningStartHeight = randomStartingHeight fpdb, err := fpCfg.DatabaseConfig.GetDbBackend() require.NoError(t, err) - app, err := service.NewFinalityProviderApp(&fpCfg, mockClientController, mockClientController, em, fpdb, logger) + app, err := service.NewFinalityProviderApp(&fpCfg, mockBabylonController, mockConsumerController, em, fpdb, logger) require.NoError(t, err) defer func() { err = fpdb.Close() @@ -98,7 +98,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) { require.Equal(t, fpInfo.BtcPkHex, fpListInfo[0].BtcPkHex) txHash := testutil.GenRandomHexStr(r, 32) - mockClientController.EXPECT(). + mockBabylonController.EXPECT(). RegisterFinalityProvider( fp.ChainPk.Key, fp.BtcPk, diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 2b918540..7bd71ee7 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -30,27 +30,28 @@ func FuzzChainPoller_Start(f *testing.F) { endHeight := startHeight + uint64(r.Int63n(10)+1) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockBabylonController := mocks.NewMockClientController(ctl) + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController := mocks.NewMockConsumerController(ctl) + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() currentBlockRes := &types.BlockInfo{ Height: currentHeight, } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() for i := startHeight; i <= endHeight; i++ { resBlock := &types.BlockInfo{ Height: i, } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } // TODO: use mock metrics m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 10 * time.Millisecond - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockBabylonController, mockConsumerController, m) err := poller.Start(startHeight) require.NoError(t, err) defer func() { @@ -81,27 +82,28 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { skipHeight := endHeight + uint64(r.Int63n(10)+1) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockBabylonController := mocks.NewMockClientController(ctl) + mockConsumerController := mocks.NewMockConsumerController(ctl) + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() currentBlockRes := &types.BlockInfo{ Height: currentHeight, } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() for i := startHeight; i <= skipHeight; i++ { resBlock := &types.BlockInfo{ Height: i, } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } // TODO: use mock metrics m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 1 * time.Second - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockBabylonController, mockConsumerController, m) // should expect error if the poller is not started err := poller.SkipToHeight(skipHeight) require.Error(t, err) diff --git a/finality-provider/service/fastsync_test.go b/finality-provider/service/fastsync_test.go index 187b1d7b..51f0dd43 100644 --- a/finality-provider/service/fastsync_test.go +++ b/finality-provider/service/fastsync_test.go @@ -24,23 +24,22 @@ func FuzzFastSync(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) - // mock finalised BTC timestamped - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) + mockBabylonController := testutil.PrepareMockedBabylonController(t, randomRegiteredEpoch) + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockBabylonController, mockConsumerController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power - mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). Return(uint64(1), nil).AnyTimes() catchUpBlocks := testutil.GenBlocks(r, finalizedHeight+1, currentHeight) expectedTxHash := testutil.GenRandomHexStr(r, 32) finalizedBlock := &types.BlockInfo{Height: finalizedHeight, Hash: testutil.GenRandomByteArray(r, 32)} - mockClientController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return([]*types.BlockInfo{finalizedBlock}, nil).AnyTimes() - mockClientController.EXPECT().QueryBlocks(finalizedHeight+1, currentHeight, uint64(10)). + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return([]*types.BlockInfo{finalizedBlock}, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(finalizedHeight+1, currentHeight, uint64(10)). Return(catchUpBlocks, nil) - mockClientController.EXPECT().SubmitBatchFinalitySigs(fpIns.GetBtcPk(), catchUpBlocks, gomock.Any()). + mockConsumerController.EXPECT().SubmitBatchFinalitySigs(fpIns.GetBtcPk(), catchUpBlocks, gomock.Any()). Return(&types.TxResponse{TxHash: expectedTxHash}, nil).AnyTimes() result, err := fpIns.FastSync(finalizedHeight+1, currentHeight) require.NoError(t, err) diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index c9f21a40..e434fb32 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -692,7 +692,7 @@ func (fp *FinalityProviderInstance) GetFinalityProviderSlashedWithRetry() (bool, ) if err := retry.Do(func() error { - slashed, err = fp.consumerCon.QueryFinalityProviderSlashed(fp.GetBtcPk()) + slashed, err = fp.cc.QueryFinalityProviderSlashed(fp.GetBtcPk()) if err != nil { return err } diff --git a/finality-provider/service/fp_instance_test.go b/finality-provider/service/fp_instance_test.go index a139635f..9077e3e7 100644 --- a/finality-provider/service/fp_instance_test.go +++ b/finality-provider/service/fp_instance_test.go @@ -30,15 +30,14 @@ 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) - // mock finalised BTC timestamped - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + mockBabylonController := testutil.PrepareMockedBabylonController(t, randomRegiteredEpoch) - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockBabylonController, mockConsumerController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power - mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). Return(uint64(1), nil).AnyTimes() // submit finality sig @@ -47,7 +46,7 @@ func FuzzSubmitFinalitySig(f *testing.F) { Hash: testutil.GenRandomByteArray(r, 32), } expectedTxHash := testutil.GenRandomHexStr(r, 32) - mockClientController.EXPECT(). + mockConsumerController.EXPECT(). SubmitFinalitySig(fpIns.GetBtcPk(), nextBlock.Height, nextBlock.Hash, gomock.Any()). Return(&types.TxResponse{TxHash: expectedTxHash}, nil).AnyTimes() providerRes, err := fpIns.SubmitFinalitySignature(nextBlock) diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index 320b6636..eb2a0122 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -41,8 +41,9 @@ func FuzzStatusUpdate(f *testing.F) { r := rand.New(rand.NewSource(seed)) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController, mockClientController) + mockClientController := testutil.PrepareMockedBabylonController(t, uint64(0)) + mockConsumerController := mocks.NewMockConsumerController(ctl) + vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController, mockConsumerController) defer cleanUp() // setup mocks @@ -51,17 +52,15 @@ func FuzzStatusUpdate(f *testing.F) { Height: currentHeight, Hash: datagen.GenRandomByteArray(r, 32), } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - 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().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(uint64(0), nil).AnyTimes() + mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() votingPower := uint64(r.Intn(2)) - mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes() - mockClientController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes() + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes() + mockConsumerController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes() var slashedHeight uint64 if votingPower == 0 { mockClientController.EXPECT().QueryFinalityProviderSlashed(gomock.Any()).Return(true, nil).AnyTimes() diff --git a/testutil/mocks/babylon.go b/testutil/mocks/clientcontroller.go similarity index 64% rename from testutil/mocks/babylon.go rename to testutil/mocks/clientcontroller.go index bf9cc8bb..b9b754ca 100644 --- a/testutil/mocks/babylon.go +++ b/testutil/mocks/clientcontroller.go @@ -50,8 +50,91 @@ func (mr *MockClientControllerMockRecorder) Close() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockClientController)(nil).Close)) } +// QueryFinalityProviderSlashed mocks base method. +func (m *MockClientController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryFinalityProviderSlashed", fpPk) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryFinalityProviderSlashed indicates an expected call of QueryFinalityProviderSlashed. +func (mr *MockClientControllerMockRecorder) QueryFinalityProviderSlashed(fpPk interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderSlashed", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderSlashed), fpPk) +} + +// QueryLastFinalizedEpoch mocks base method. +func (m *MockClientController) QueryLastFinalizedEpoch() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryLastFinalizedEpoch") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryLastFinalizedEpoch indicates an expected call of QueryLastFinalizedEpoch. +func (mr *MockClientControllerMockRecorder) QueryLastFinalizedEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLastFinalizedEpoch", reflect.TypeOf((*MockClientController)(nil).QueryLastFinalizedEpoch)) +} + +// RegisterFinalityProvider mocks base method. +func (m *MockClientController) RegisterFinalityProvider(chainPk []byte, fpPk *btcec.PublicKey, pop []byte, commission *math.LegacyDec, description []byte, masterPubRand string) (*types.TxResponse, uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegisterFinalityProvider", chainPk, fpPk, pop, commission, description, masterPubRand) + ret0, _ := ret[0].(*types.TxResponse) + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// RegisterFinalityProvider indicates an expected call of RegisterFinalityProvider. +func (mr *MockClientControllerMockRecorder) RegisterFinalityProvider(chainPk, fpPk, pop, commission, description, masterPubRand interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterFinalityProvider", reflect.TypeOf((*MockClientController)(nil).RegisterFinalityProvider), chainPk, fpPk, pop, commission, description, masterPubRand) +} + +// MockConsumerController is a mock of ConsumerController interface. +type MockConsumerController struct { + ctrl *gomock.Controller + recorder *MockConsumerControllerMockRecorder +} + +// MockConsumerControllerMockRecorder is the mock recorder for MockConsumerController. +type MockConsumerControllerMockRecorder struct { + mock *MockConsumerController +} + +// NewMockConsumerController creates a new mock instance. +func NewMockConsumerController(ctrl *gomock.Controller) *MockConsumerController { + mock := &MockConsumerController{ctrl: ctrl} + mock.recorder = &MockConsumerControllerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConsumerController) EXPECT() *MockConsumerControllerMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockConsumerController) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockConsumerControllerMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConsumerController)(nil).Close)) +} + // QueryActivatedHeight mocks base method. -func (m *MockClientController) QueryActivatedHeight() (uint64, error) { +func (m *MockConsumerController) QueryActivatedHeight() (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryActivatedHeight") ret0, _ := ret[0].(uint64) @@ -60,13 +143,13 @@ func (m *MockClientController) QueryActivatedHeight() (uint64, error) { } // QueryActivatedHeight indicates an expected call of QueryActivatedHeight. -func (mr *MockClientControllerMockRecorder) QueryActivatedHeight() *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockClientController)(nil).QueryActivatedHeight)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } // QueryBestBlock mocks base method. -func (m *MockClientController) QueryBestBlock() (*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBestBlock() (*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBestBlock") ret0, _ := ret[0].(*types.BlockInfo) @@ -75,13 +158,13 @@ func (m *MockClientController) QueryBestBlock() (*types.BlockInfo, error) { } // QueryBestBlock indicates an expected call of QueryBestBlock. -func (mr *MockClientControllerMockRecorder) QueryBestBlock() *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBestBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockClientController)(nil).QueryBestBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBestBlock)) } // QueryBlock mocks base method. -func (m *MockClientController) QueryBlock(height uint64) (*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBlock", height) ret0, _ := ret[0].(*types.BlockInfo) @@ -90,13 +173,13 @@ func (m *MockClientController) QueryBlock(height uint64) (*types.BlockInfo, erro } // QueryBlock indicates an expected call of QueryBlock. -func (mr *MockClientControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockClientController)(nil).QueryBlock), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBlock), height) } // QueryBlocks mocks base method. -func (m *MockClientController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBlocks", startHeight, endHeight, limit) ret0, _ := ret[0].([]*types.BlockInfo) @@ -105,28 +188,13 @@ func (m *MockClientController) QueryBlocks(startHeight, endHeight, limit uint64) } // QueryBlocks indicates an expected call of QueryBlocks. -func (mr *MockClientControllerMockRecorder) QueryBlocks(startHeight, endHeight, limit interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBlocks(startHeight, endHeight, limit interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlocks", reflect.TypeOf((*MockClientController)(nil).QueryBlocks), startHeight, endHeight, limit) -} - -// QueryFinalityProviderSlashed mocks base method. -func (m *MockClientController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryFinalityProviderSlashed", fpPk) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryFinalityProviderSlashed indicates an expected call of QueryFinalityProviderSlashed. -func (mr *MockClientControllerMockRecorder) QueryFinalityProviderSlashed(fpPk interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderSlashed", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderSlashed), fpPk) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryBlocks), startHeight, endHeight, limit) } // QueryFinalityProviderVotingPower mocks base method. -func (m *MockClientController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { +func (m *MockConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryFinalityProviderVotingPower", fpPk, blockHeight) ret0, _ := ret[0].(uint64) @@ -135,28 +203,13 @@ func (m *MockClientController) QueryFinalityProviderVotingPower(fpPk *btcec.Publ } // QueryFinalityProviderVotingPower indicates an expected call of QueryFinalityProviderVotingPower. -func (mr *MockClientControllerMockRecorder) QueryFinalityProviderVotingPower(fpPk, blockHeight interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(fpPk, blockHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) -} - -// QueryLastFinalizedEpoch mocks base method. -func (m *MockClientController) QueryLastFinalizedEpoch() (uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryLastFinalizedEpoch") - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryLastFinalizedEpoch indicates an expected call of QueryLastFinalizedEpoch. -func (mr *MockClientControllerMockRecorder) QueryLastFinalizedEpoch() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLastFinalizedEpoch", reflect.TypeOf((*MockClientController)(nil).QueryLastFinalizedEpoch)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) } // QueryLatestFinalizedBlocks mocks base method. -func (m *MockClientController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { +func (m *MockConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryLatestFinalizedBlocks", count) ret0, _ := ret[0].([]*types.BlockInfo) @@ -165,29 +218,13 @@ func (m *MockClientController) QueryLatestFinalizedBlocks(count uint64) ([]*type } // QueryLatestFinalizedBlocks indicates an expected call of QueryLatestFinalizedBlocks. -func (mr *MockClientControllerMockRecorder) QueryLatestFinalizedBlocks(count interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlocks", reflect.TypeOf((*MockClientController)(nil).QueryLatestFinalizedBlocks), count) -} - -// RegisterFinalityProvider mocks base method. -func (m *MockClientController) RegisterFinalityProvider(chainPk []byte, fpPk *btcec.PublicKey, pop []byte, commission *math.LegacyDec, description []byte, masterPubRand string) (*types.TxResponse, uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RegisterFinalityProvider", chainPk, fpPk, pop, commission, description, masterPubRand) - ret0, _ := ret[0].(*types.TxResponse) - ret1, _ := ret[1].(uint64) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// RegisterFinalityProvider indicates an expected call of RegisterFinalityProvider. -func (mr *MockClientControllerMockRecorder) RegisterFinalityProvider(chainPk, fpPk, pop, commission, description, masterPubRand interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryLatestFinalizedBlocks(count interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterFinalityProvider", reflect.TypeOf((*MockClientController)(nil).RegisterFinalityProvider), chainPk, fpPk, pop, commission, description, masterPubRand) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestFinalizedBlocks), count) } // SubmitBatchFinalitySigs mocks base method. -func (m *MockClientController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { +func (m *MockConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SubmitBatchFinalitySigs", fpPk, blocks, sigs) ret0, _ := ret[0].(*types.TxResponse) @@ -196,13 +233,13 @@ func (m *MockClientController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, bl } // SubmitBatchFinalitySigs indicates an expected call of SubmitBatchFinalitySigs. -func (mr *MockClientControllerMockRecorder) SubmitBatchFinalitySigs(fpPk, blocks, sigs interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) SubmitBatchFinalitySigs(fpPk, blocks, sigs interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitBatchFinalitySigs", reflect.TypeOf((*MockClientController)(nil).SubmitBatchFinalitySigs), fpPk, blocks, sigs) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitBatchFinalitySigs", reflect.TypeOf((*MockConsumerController)(nil).SubmitBatchFinalitySigs), fpPk, blocks, sigs) } // SubmitFinalitySig mocks base method. -func (m *MockClientController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { +func (m *MockConsumerController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SubmitFinalitySig", fpPk, blockHeight, blockHash, sig) ret0, _ := ret[0].(*types.TxResponse) @@ -211,7 +248,7 @@ func (m *MockClientController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHei } // SubmitFinalitySig indicates an expected call of SubmitFinalitySig. -func (mr *MockClientControllerMockRecorder) SubmitFinalitySig(fpPk, blockHeight, blockHash, sig interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) SubmitFinalitySig(fpPk, blockHeight, blockHash, sig interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitFinalitySig", reflect.TypeOf((*MockClientController)(nil).SubmitFinalitySig), fpPk, blockHeight, blockHash, sig) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitFinalitySig", reflect.TypeOf((*MockConsumerController)(nil).SubmitFinalitySig), fpPk, blockHeight, blockHash, sig) } diff --git a/testutil/utils.go b/testutil/utils.go index 76f14af2..fc8ddadb 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -18,16 +18,16 @@ func ZeroCommissionRate() *sdkmath.LegacyDec { return &zeroCom } -func PrepareMockedClientController(t *testing.T, r *rand.Rand, startHeight, currentHeight uint64) *mocks.MockClientController { +func PrepareMockedConsumerController(t *testing.T, r *rand.Rand, startHeight, currentHeight uint64) *mocks.MockConsumerController { ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) + mockConsumerController := mocks.NewMockConsumerController(ctl) for i := startHeight + 1; i <= currentHeight; i++ { resBlock := &types.BlockInfo{ Height: currentHeight, Hash: GenRandomByteArray(r, 32), } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } currentBlockRes := &types.BlockInfo{ @@ -35,9 +35,19 @@ func PrepareMockedClientController(t *testing.T, r *rand.Rand, startHeight, curr Hash: GenRandomByteArray(r, 32), } - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - return mockClientController + return mockConsumerController +} + +func PrepareMockedBabylonController(t *testing.T, randomRegiteredEpoch uint64) *mocks.MockClientController { + ctl := gomock.NewController(t) + mockBabylonController := mocks.NewMockClientController(ctl) + // mock finalised BTC timestamped + mockBabylonController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + + return mockBabylonController } From e54e921c024d6775e7bbed51ab367c9feecb2827 Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sat, 18 May 2024 15:47:08 -0400 Subject: [PATCH 04/26] QueryFinalityProviderVotingPower pseudo code --- clientcontroller/evm_consumer.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 3e73aab2..ccd65d0c 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -60,6 +60,22 @@ func (ec *EVMConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { + /* TODO: implement + + latest_committed_l2_height = read the last element from the l2Outputs[] array in the L2OutputOracle.sol contract + + if blockHeight > latest_committed_l2_height: + + query the VP from the L1 oracle contract using "latest" as the block tag + + else: + + 1. query the L1 event `emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp, block.number);` + to find the first event where the `_l2BlockNumber` >= blockHeight + 2. get the block.number from the event + 3. query the VP from the L1 oracle contract using `block.number` as the block tag + + */ return 0, nil } From 41cd722ca3277d9f1f06655eb8b1696659bf18ef Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 11:25:14 -0400 Subject: [PATCH 05/26] add pseudo code for QueryActivatedHeight --- clientcontroller/evm_consumer.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index ccd65d0c..e12cb849 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -105,6 +105,24 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er } func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { + /* TODO: implement + + oracle_event = query the event in the L1 oracle contract where the FP's voting power is firstly set + + l1_activated_height = get the L1 block number from the `oracle_event` + + output_event = query the L1 event `emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp, block.number);` + to find the first event where the `block.number` >= l1_activated_height + + if output_event == nil: + + read `nextBlockNumber()` from the L1 L2OutputOracle contract and return the result + + else: + + return output_event._l2BlockNumber + 1 + + */ return 0, nil } From caec9978e01deea44a55093814179b805c9b78ca Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 11:58:09 -0400 Subject: [PATCH 06/26] nit --- clientcontroller/evm_consumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index e12cb849..0be5c408 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -120,7 +120,7 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { else: - return output_event._l2BlockNumber + 1 + return output_event._l2BlockNumber */ From c5c3c01e1ecf3302310cd838403dd514fd546e1e Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 14:39:14 -0400 Subject: [PATCH 07/26] enforce `mock-gen` before testing --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 4877fd83..47f9b1b3 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ build-docker: .PHONY: build build-docker test: + make mock-gen go test ./... test-e2e: From 22873abd6a4865d03a53aea835f976d85ffbe703 Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 14:49:52 -0400 Subject: [PATCH 08/26] nit --- clientcontroller/evm_consumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 0be5c408..caff96b2 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -62,7 +62,7 @@ func (ec *EVMConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { /* TODO: implement - latest_committed_l2_height = read the last element from the l2Outputs[] array in the L2OutputOracle.sol contract + latest_committed_l2_height = read `latestBlockNumber()` from the L1 L2OutputOracle contract and return the result if blockHeight > latest_committed_l2_height: From e8398f75832015af50b4296c3c5a3f43725cec9e Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 14:59:56 -0400 Subject: [PATCH 09/26] QueryBestBlock pseudo code --- clientcontroller/evm_consumer.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index caff96b2..c55a091a 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -128,6 +128,9 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { } func (ec *EVMConsumerController) QueryBestBlock() (*types.BlockInfo, error) { + /* TODO: implement + get the latest L2 block number from a RPC call + */ return &types.BlockInfo{ Height: uint64(0), From 3fa7927ad60a58586ab065efffcfd86733c0ded5 Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 15:36:22 -0400 Subject: [PATCH 10/26] refactor --- clientcontroller/babylon_consumer.go | 7 +-- clientcontroller/evm_consumer.go | 7 +-- clientcontroller/interface.go | 4 +- finality-provider/service/app.go | 4 +- finality-provider/service/chain_poller.go | 16 +++---- .../service/chain_poller_test.go | 11 +---- finality-provider/service/fp_instance.go | 44 +++++++++---------- finality-provider/service/fp_manager.go | 19 ++++---- finality-provider/service/fp_manager_test.go | 2 +- itest/e2e_test.go | 3 +- itest/test_manager.go | 6 +-- testutil/mocks/clientcontroller.go | 30 ++++++------- testutil/utils.go | 7 +-- 13 files changed, 72 insertions(+), 88 deletions(-) diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index 8060942f..5eb3c476 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -232,14 +232,15 @@ func (bc *BabylonConsumerController) QueryActivatedHeight() (uint64, error) { return res.Height, nil } -func (bc *BabylonConsumerController) QueryBestBlock() (*types.BlockInfo, error) { +func (bc *BabylonConsumerController) QueryLatestBlockHeight() (uint64, error) { blocks, err := bc.queryLatestBlocks(nil, 1, finalitytypes.QueriedBlockStatus_ANY, true) if err != nil || len(blocks) != 1 { // try query comet block if the index block query is not available - return bc.queryCometBestBlock() + block, err := bc.queryCometBestBlock() + return block.Height, err } - return blocks[0], nil + return blocks[0].Height, nil } func (bc *BabylonConsumerController) queryCometBestBlock() (*types.BlockInfo, error) { diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index c55a091a..b3450df2 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -127,15 +127,12 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { return 0, nil } -func (ec *EVMConsumerController) QueryBestBlock() (*types.BlockInfo, error) { +func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { /* TODO: implement get the latest L2 block number from a RPC call */ - return &types.BlockInfo{ - Height: uint64(0), - Hash: nil, - }, nil + return uint64(0), nil } func (ec *EVMConsumerController) Close() error { diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index d381bc6d..feb35af4 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -71,8 +71,8 @@ type ConsumerController interface { // QueryBlocks returns a list of blocks from startHeight to endHeight QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) - // QueryBestBlock queries the tip block of the consumer chain - QueryBestBlock() (*types.BlockInfo, error) + // QueryBestBlock queries the tip block height of the consumer chain + QueryLatestBlockHeight() (uint64, error) // QueryActivatedHeight returns the activated height of the consumer chain // error will be returned if the consumer chain has not been activated diff --git a/finality-provider/service/app.go b/finality-provider/service/app.go index ae870645..5baaf8e3 100644 --- a/finality-provider/service/app.go +++ b/finality-provider/service/app.go @@ -231,7 +231,7 @@ func (app *FinalityProviderApp) getFpPrivKey(fpPk []byte) (*btcec.PrivateKey, er // SyncFinalityProviderStatus syncs the status of the finality-providers func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { - latestBlock, err := app.consumerCon.QueryBestBlock() + latestBlockHeight, err := app.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -242,7 +242,7 @@ func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { } for _, fp := range fps { - vp, err := app.consumerCon.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlock.Height) + vp, err := app.consumerCon.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlockHeight) if err != nil { // if error occured then the finality-provider is not registered in the Babylon chain yet continue diff --git a/finality-provider/service/chain_poller.go b/finality-provider/service/chain_poller.go index 3c40db11..6ea2979b 100644 --- a/finality-provider/service/chain_poller.go +++ b/finality-provider/service/chain_poller.go @@ -125,14 +125,14 @@ func (cp *ChainPoller) GetBlockInfoChan() <-chan *types.BlockInfo { return cp.blockInfoChan } -func (cp *ChainPoller) latestBlockWithRetry() (*types.BlockInfo, error) { +func (cp *ChainPoller) latestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = cp.consumerCon.QueryBestBlock() + latestBlockHeight, err = cp.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -145,9 +145,9 @@ func (cp *ChainPoller) latestBlockWithRetry() (*types.BlockInfo, error) { zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - return latestBlock, nil + return latestBlockHeight, nil } func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { @@ -186,13 +186,13 @@ func (cp *ChainPoller) validateStartHeight(startHeight uint64) error { var currentBestChainHeight uint64 for { - lastestBlock, err := cp.latestBlockWithRetry() + lastestBlockHeight, err := cp.latestBlockHeightWithRetry() if err != nil { cp.logger.Debug("failed to query babylon for the latest status", zap.Error(err)) continue } - currentBestChainHeight = lastestBlock.Height + currentBestChainHeight = lastestBlockHeight break } diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 7bd71ee7..6d777f2d 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -35,10 +35,7 @@ func FuzzChainPoller_Start(f *testing.F) { mockConsumerController := mocks.NewMockConsumerController(ctl) mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - } - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() for i := startHeight; i <= endHeight; i++ { resBlock := &types.BlockInfo{ @@ -86,11 +83,7 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { mockConsumerController := mocks.NewMockConsumerController(ctl) mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - } - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() for i := startHeight; i <= skipHeight; i++ { resBlock := &types.BlockInfo{ diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index e434fb32..00a5ba16 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -43,7 +43,7 @@ type FinalityProviderInstance struct { // passphrase is used to unlock private keys passphrase string - laggingTargetChan chan *types.BlockInfo + laggingTargetChan chan uint64 criticalErrChan chan<- *CriticalError isStarted *atomic.Bool @@ -131,7 +131,7 @@ func (fp *FinalityProviderInstance) Start() error { fp.poller = poller - fp.laggingTargetChan = make(chan *types.BlockInfo, 1) + fp.laggingTargetChan = make(chan uint64, 1) fp.quit = make(chan struct{}) @@ -144,13 +144,13 @@ func (fp *FinalityProviderInstance) Start() error { } func (fp *FinalityProviderInstance) bootstrap() (uint64, error) { - latestBlock, err := fp.getLatestBlockWithRetry() + latestBlockHeight, err := fp.getLatestBlockHeightWithRetry() if err != nil { return 0, err } - if fp.checkLagging(latestBlock) { - _, err := fp.tryFastSync(latestBlock) + if fp.checkLagging(latestBlockHeight) { + _, err := fp.tryFastSync(latestBlockHeight) if err != nil && !clientcontroller.IsExpected(err) { return 0, err } @@ -298,7 +298,7 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { continue } - latestBlock, err := fp.getLatestBlockWithRetry() + latestBlockHeight, err := fp.getLatestBlockHeightWithRetry() if err != nil { fp.logger.Debug( "failed to get the latest block of the consumer chain", @@ -308,9 +308,9 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { continue } - if fp.checkLagging(latestBlock) { + if fp.checkLagging(latestBlockHeight) { fp.isLagging.Store(true) - fp.laggingTargetChan <- latestBlock + fp.laggingTargetChan <- latestBlockHeight } case <-fp.quit: fp.logger.Debug("the fast sync loop is closing") @@ -319,7 +319,7 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { } } -func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (*FastSyncResult, error) { +func (fp *FinalityProviderInstance) tryFastSync(targetBlockHeight uint64) (*FastSyncResult, error) { if fp.inSync.Load() { return nil, fmt.Errorf("the finality-provider %s is already in sync", fp.GetBtcPkHex()) } @@ -333,7 +333,7 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (* fp.logger.Debug( "no finalized blocks yet, no need to catch up", zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("height", targetBlock.Height), + zap.Uint64("height", targetBlockHeight), ) return nil, nil } @@ -350,13 +350,13 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (* startHeight = lastFinalizedHeight + 1 } - if startHeight > targetBlock.Height { - return nil, fmt.Errorf("the start height %v should not be higher than the current block %v", startHeight, targetBlock.Height) + if startHeight > targetBlockHeight { + return nil, fmt.Errorf("the start height %v should not be higher than the current block %v", startHeight, targetBlockHeight) } fp.logger.Debug("the finality-provider is entering fast sync") - return fp.FastSync(startHeight, targetBlock.Height) + return fp.FastSync(startHeight, targetBlockHeight) } func (fp *FinalityProviderInstance) hasProcessed(b *types.BlockInfo) bool { @@ -400,8 +400,8 @@ func (fp *FinalityProviderInstance) reportCriticalErr(err error) { } // checkLagging returns true if the lasted voted height is behind by a configured gap -func (fp *FinalityProviderInstance) checkLagging(currentBlock *types.BlockInfo) bool { - return currentBlock.Height >= fp.GetLastProcessedHeight()+fp.cfg.FastSyncGap +func (fp *FinalityProviderInstance) checkLagging(currentBlockHeight uint64) bool { + return currentBlockHeight >= fp.GetLastProcessedHeight()+fp.cfg.FastSyncGap } // retrySubmitFinalitySignatureUntilBlockFinalized periodically tries to submit finality signature until success or the block is finalized @@ -632,14 +632,14 @@ func (fp *FinalityProviderInstance) latestFinalizedBlocksWithRetry(count uint64) return response, nil } -func (fp *FinalityProviderInstance) getLatestBlockWithRetry() (*types.BlockInfo, error) { +func (fp *FinalityProviderInstance) getLatestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = fp.consumerCon.QueryBestBlock() + latestBlockHeight, err = fp.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -652,11 +652,11 @@ func (fp *FinalityProviderInstance) getLatestBlockWithRetry() (*types.BlockInfo, zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - fp.metrics.RecordBabylonTipHeight(latestBlock.Height) + fp.metrics.RecordBabylonTipHeight(latestBlockHeight) - return latestBlock, nil + return latestBlockHeight, nil } func (fp *FinalityProviderInstance) GetVotingPowerWithRetry(height uint64) (uint64, error) { diff --git a/finality-provider/service/fp_manager.go b/finality-provider/service/fp_manager.go index 833ba088..ac517cbd 100644 --- a/finality-provider/service/fp_manager.go +++ b/finality-provider/service/fp_manager.go @@ -18,7 +18,6 @@ import ( "github.com/babylonchain/finality-provider/finality-provider/proto" "github.com/babylonchain/finality-provider/finality-provider/store" "github.com/babylonchain/finality-provider/metrics" - "github.com/babylonchain/finality-provider/types" ) const instanceTerminatingMsg = "terminating the finality-provider instance due to critical error" @@ -134,7 +133,7 @@ func (fpm *FinalityProviderManager) monitorStatusUpdate() { for { select { case <-statusUpdateTicker.C: - latestBlock, err := fpm.getLatestBlockWithRetry() + latestBlockHeight, err := fpm.getLatestBlockHeightWithRetry() if err != nil { fpm.logger.Debug("failed to get the latest block", zap.Error(err)) continue @@ -142,12 +141,12 @@ func (fpm *FinalityProviderManager) monitorStatusUpdate() { fpis := fpm.ListFinalityProviderInstances() for _, fpi := range fpis { oldStatus := fpi.GetStatus() - power, err := fpi.GetVotingPowerWithRetry(latestBlock.Height) + power, err := fpi.GetVotingPowerWithRetry(latestBlockHeight) if err != nil { fpm.logger.Debug( "failed to get the voting power", zap.String("fp_btc_pk", fpi.GetBtcPkHex()), - zap.Uint64("height", latestBlock.Height), + zap.Uint64("height", latestBlockHeight), zap.Error(err), ) continue @@ -407,14 +406,14 @@ func (fpm *FinalityProviderManager) addFinalityProviderInstance( return nil } -func (fpm *FinalityProviderManager) getLatestBlockWithRetry() (*types.BlockInfo, error) { +func (fpm *FinalityProviderManager) getLatestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = fpm.consumerCon.QueryBestBlock() + latestBlockHeight, err = fpm.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -427,8 +426,8 @@ func (fpm *FinalityProviderManager) getLatestBlockWithRetry() (*types.BlockInfo, zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - return latestBlock, nil + return latestBlockHeight, nil } diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index eb2a0122..3c16e833 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -54,7 +54,7 @@ func FuzzStatusUpdate(f *testing.F) { } mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() mockConsumerController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 91e0094e..7e0e2010 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -181,8 +181,7 @@ func TestFastSync(t *testing.T) { t.Logf("the latest finalized block is at %v", finalizedHeight) // check if the fast sync works by checking if the gap is not more than 1 - currentHeaderRes, err := tm.BBNConsumerClient.QueryBestBlock() - currentHeight := currentHeaderRes.Height + currentHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() t.Logf("the current block is at %v", currentHeight) require.NoError(t, err) require.True(t, currentHeight < finalizedHeight+uint64(n)) diff --git a/itest/test_manager.go b/itest/test_manager.go index df46c714..98caf53c 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -369,18 +369,18 @@ func (tm *TestManager) WaitForFpShutDown(t *testing.T, pk *bbntypes.BIP340PubKey } func (tm *TestManager) StopAndRestartFpAfterNBlocks(t *testing.T, n int, fpIns *service.FinalityProviderInstance) { - blockBeforeStop, err := tm.BBNConsumerClient.QueryBestBlock() + blockBeforeStopHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() require.NoError(t, err) err = fpIns.Stop() require.NoError(t, err) require.Eventually(t, func() bool { - headerAfterStop, err := tm.BBNConsumerClient.QueryBestBlock() + headerAfterStopHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() if err != nil { return false } - return headerAfterStop.Height >= uint64(n)+blockBeforeStop.Height + return headerAfterStopHeight >= uint64(n)+blockBeforeStopHeight }, eventuallyWaitTimeOut, eventuallyPollTime) t.Log("restarting the finality-provider instance") diff --git a/testutil/mocks/clientcontroller.go b/testutil/mocks/clientcontroller.go index b9b754ca..65ceafa1 100644 --- a/testutil/mocks/clientcontroller.go +++ b/testutil/mocks/clientcontroller.go @@ -148,21 +148,6 @@ func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } -// QueryBestBlock mocks base method. -func (m *MockConsumerController) QueryBestBlock() (*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryBestBlock") - ret0, _ := ret[0].(*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryBestBlock indicates an expected call of QueryBestBlock. -func (mr *MockConsumerControllerMockRecorder) QueryBestBlock() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBestBlock)) -} - // QueryBlock mocks base method. func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { m.ctrl.T.Helper() @@ -208,6 +193,21 @@ func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(f return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) } +// QueryLatestBlockHeight mocks base method. +func (m *MockConsumerController) QueryLatestBlockHeight() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryLatestBlockHeight") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryLatestBlockHeight indicates an expected call of QueryLatestBlockHeight. +func (mr *MockConsumerControllerMockRecorder) QueryLatestBlockHeight() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestBlockHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestBlockHeight)) +} + // QueryLatestFinalizedBlocks mocks base method. func (m *MockConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() diff --git a/testutil/utils.go b/testutil/utils.go index fc8ddadb..05bc4c25 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -30,13 +30,8 @@ func PrepareMockedConsumerController(t *testing.T, r *rand.Rand, startHeight, cu mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - Hash: GenRandomByteArray(r, 32), - } - mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() return mockConsumerController From feecc8f4ef153a146425c7cd27e09135d9326c32 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Sun, 19 May 2024 23:50:12 +0200 Subject: [PATCH 11/26] evm_consumer update --- clientcontroller/evm_consumer.go | 216 ++++++++++++++++++++++++++++--- finality-provider/config/evm.go | 11 +- go.mod | 4 +- go.sum | 7 + 4 files changed, 218 insertions(+), 20 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index b3450df2..03faeab0 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -2,11 +2,16 @@ package clientcontroller import ( "fmt" + "math/big" + "strconv" + "strings" finalitytypes "github.com/babylonchain/babylon/x/finality/types" fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" "github.com/babylonchain/finality-provider/types" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum-optimism/optimism/op-bindings/bindings" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/btcsuite/btcd/btcec/v2" @@ -32,9 +37,9 @@ func NewEVMConsumerController( if err := evmCfg.Validate(); err != nil { return nil, fmt.Errorf("invalid config for EVM RPC client: %w", err) } - ec, err := rpc.Dial(evmCfg.RPCAddr) + ec, err := rpc.Dial(evmCfg.RPCL2Addr) if err != nil { - return nil, fmt.Errorf("failed to connect to the EVM RPC server %s: %w", evmCfg.RPCAddr, err) + return nil, fmt.Errorf("failed to connect to the EVM RPC server %s: %w", evmCfg.RPCL2Addr, err) } return &EVMConsumerController{ ec, @@ -81,27 +86,167 @@ func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.Pu } func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { - return ec.queryLatestBlocks(nil, count, finalitytypes.QueriedBlockStatus_FINALIZED, true) + + lastnumber, err := ec.GetLatestFinalizedNumber() + if err != nil { + return nil, fmt.Errorf("can't get latest finalized block:%s", err) + + } + type Block struct { + Number string + Hash string + } + + var B []rpc.BatchElem + + for i := 0; i < int(count); i++ { + + hexStr := Transform(lastnumber) + ib := rpc.BatchElem{ + Method: "eth_getBlockByNumber", + Args: []interface{}{hexStr, true}, + Result: new(Block), + } + B = append(B, ib) + lastnumber.Sub(lastnumber, big.NewInt(1)) + } + + err = ec.evmClient.BatchCall(B) + if err != nil { + return nil, fmt.Errorf("can't get latest block:%s", err) + + } + var blocks []*types.BlockInfo + + for _, b := range B { + nb := b.Result.(*Block) + num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) + if err != nil { + fmt.Println("Error:", err) + } + ib := &types.BlockInfo{ + Height: num, + Hash: []byte(nb.Hash), + Finalized: true, + } + blocks = append(blocks, ib) + } + return blocks, nil + } func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { - return ec.queryLatestBlocks(sdk.Uint64ToBigEndian(startHeight), 0, finalitytypes.QueriedBlockStatus_ANY, false) + if endHeight < startHeight { + return nil, fmt.Errorf("the startHeight %v should not be higher than the endHeight %v", startHeight, endHeight) + } + count := endHeight - startHeight + if count > limit { + count = limit + } + + lastnumber, err := ec.GetLatestFinalizedNumber() + if err != nil { + return nil, fmt.Errorf("can't get latest finalized block:%s", err) + + } + type Block struct { + Number string + Hash string + } + + startnumber := new(big.Int).SetUint64(startHeight) + + var B []rpc.BatchElem + + for i := 0; i < int(count); i++ { + + hexStr := Transform(startnumber) + ib := rpc.BatchElem{ + Method: "eth_getBlockByNumber", + Args: []interface{}{hexStr, true}, + Result: new(Block), + } + B = append(B, ib) + startnumber.Add(startnumber, big.NewInt(1)) + } + + err = ec.evmClient.BatchCall(B) + if err != nil { + return nil, fmt.Errorf("can't get blocks") + + } + var blocks []*types.BlockInfo + + for _, b := range B { + nb := b.Result.(*Block) + num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) + if err != nil { + return nil, fmt.Errorf("error:%s", err) + } + + number := new(big.Int).SetUint64(num) + var finalized bool = false + if number.Cmp(lastnumber) <= 0 { + finalized = true + } + + ib := &types.BlockInfo{ + Height: num, + Hash: []byte(nb.Hash), + Finalized: finalized, + } + blocks = append(blocks, ib) + } + return blocks, nil + } func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { var blocks []*types.BlockInfo - + // Can be deleted for never using return blocks, nil } func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { - return &types.BlockInfo{ - Height: height, - Hash: nil, - Finalized: false, - }, nil + number := new(big.Int).SetUint64(height) + + hexStr := Transform(number) + + type Block struct { + Number string + Hash string + } + + var block Block + err := ec.evmClient.Call(&block, "eth_getBlockByNumber", hexStr, true) + if err != nil { + return nil, fmt.Errorf("can't get block by number:%s", err) + } + + num, err := strconv.ParseUint(strings.TrimPrefix(block.Number, "0x"), 16, 64) + if err != nil { + return nil, fmt.Errorf("error:%s", err) + } + + lastnumber, err := ec.GetLatestFinalizedNumber() + if err != nil { + return nil, fmt.Errorf("can't get latest finalized block:%s", err) + } + + var finalized bool = false + if number.Cmp(lastnumber) <= 0 { + finalized = true + } + + b := &types.BlockInfo{ + Height: num, + Hash: []byte(block.Hash), + Finalized: finalized, + } + + return b, nil } func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { @@ -128,14 +273,55 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { } func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { - /* TODO: implement - get the latest L2 block number from a RPC call - */ - return uint64(0), nil + type Block struct { + Number string + } + + var block Block + err := ec.evmClient.Call(&block, "eth_getBlockByNumber", "latest", true) + if err != nil { + return 0, fmt.Errorf("failed to get latest block:%s", err) + } + + num, err := strconv.ParseUint(strings.TrimPrefix(block.Number, "0x"), 16, 64) + if err != nil { + fmt.Println("Error:%s", err) + } + + return num, nil + } func (ec *EVMConsumerController) Close() error { ec.evmClient.Close() return nil } + +func Transform(number *big.Int) string { + + hexStr := fmt.Sprintf("%x", number) + if len(hexStr) >= 2 && hexStr[:2] != "0x" { + hexStr = "0x" + hexStr + } + return hexStr + +} +func (ec *EVMConsumerController) GetLatestFinalizedNumber() (*big.Int, error) { + + conn, err := ethclient.Dial(ec.cfg.RPCL1Addr) + if err != nil { + return nil, fmt.Errorf("failed to connect to the Ethereum client:%s", err) + } + output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleContractAddress), conn) + if err != nil { + return nil, fmt.Errorf("failed to instantiate L2OutputOracle contract:%s ", err) + } + + lastnumber, err := output.LatestBlockNumber(nil) + if err != nil { + return nil, fmt.Errorf("failed to get latest finalize block number:%s ", err) + } + return lastnumber, err + +} diff --git a/finality-provider/config/evm.go b/finality-provider/config/evm.go index 68f9714a..1fd6ab38 100644 --- a/finality-provider/config/evm.go +++ b/finality-provider/config/evm.go @@ -10,18 +10,21 @@ const ( ) type EVMConfig struct { - RPCAddr string `long:"rpc-address" description:"address of the rpc server to connect to"` + RPCL1Addr string `long:"rpc-address" description:"address of the L2rpc server to connect to"` + RPCL2Addr string `long:"rpc-address" description:"address of the L1rpc server to connect to"` + L2OutputOracleContractAddress string `long:"sol-address" description:"address of the L2output smart contract"` + BitcoinStackingContractAddress string `long:"sol-address" description:"address of the Bitcoinstaking smart contract"` } func DefaultEVMConfig() EVMConfig { return EVMConfig{ - RPCAddr: defaultEVMRPCAddr, + RPCL2Addr: defaultEVMRPCAddr, } } func (cfg *EVMConfig) Validate() error { - if _, err := url.Parse(cfg.RPCAddr); err != nil { - return fmt.Errorf("rpc-addr is not correctly formatted: %w", err) + if _, err := url.Parse(cfg.RPCL2Addr); err != nil { + return fmt.Errorf("rpcl2-addr is not correctly formatted: %w", err) } return nil } diff --git a/go.mod b/go.mod index 80c419eb..d062f97c 100644 --- a/go.mod +++ b/go.mod @@ -114,6 +114,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect github.com/emicklei/dot v1.6.1 // indirect + github.com/ethereum-optimism/optimism/op-bindings v0.10.14 // indirect github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -226,7 +227,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect @@ -248,6 +249,7 @@ require ( github.com/ulikunitz/xz v0.5.11 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect go.etcd.io/bbolt v1.3.8 // indirect diff --git a/go.sum b/go.sum index e46b4050..6fbe5593 100644 --- a/go.sum +++ b/go.sum @@ -509,6 +509,8 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/ethereum-optimism/optimism/op-bindings v0.10.14 h1:SMMnMdNb1QIhJDyvk7QMUv+crAP4UHHoSYBOASBDIjM= +github.com/ethereum-optimism/optimism/op-bindings v0.10.14/go.mod h1:9ZSUq/rjlzp3uYyBN4sZmhTc3oZgDVqJ4wrUja7vj6c= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/go-ethereum v1.13.15 h1:U7sSGYGo4SPjP6iNIifNoyIAiNjrmQkz6EwQG+/EZWo= @@ -565,6 +567,7 @@ github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -1180,6 +1183,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= @@ -1293,6 +1298,8 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= +github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= From aa9041aca96fdd79dfe0a354762d9070bf5645ed Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Sun, 19 May 2024 19:31:00 -0400 Subject: [PATCH 12/26] refactor --- clientcontroller/babylon_consumer.go | 10 ++----- clientcontroller/evm_consumer.go | 13 ++++---- clientcontroller/interface.go | 4 +-- finality-provider/service/chain_poller.go | 8 ++--- .../service/chain_poller_test.go | 6 ++-- finality-provider/service/fastsync.go | 4 +-- finality-provider/service/fp_instance.go | 20 ++++++------- finality-provider/service/fp_manager_test.go | 2 +- itest/test_manager.go | 4 +-- testutil/mocks/clientcontroller.go | 30 +++++++++---------- testutil/utils.go | 3 +- types/blockinfo.go | 5 ++-- 12 files changed, 53 insertions(+), 56 deletions(-) diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index 5eb3c476..7778abf3 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -210,17 +210,13 @@ func getContextWithCancel(timeout time.Duration) (context.Context, context.Cance return ctx, cancel } -func (bc *BabylonConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { +func (bc *BabylonConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { res, err := bc.bbnClient.QueryClient.Block(height) if err != nil { - return nil, fmt.Errorf("failed to query indexed block at height %v: %w", height, err) + return false, fmt.Errorf("failed to query indexed block at height %v: %w", height, err) } - return &types.BlockInfo{ - Height: height, - Hash: res.Block.AppHash, - Finalized: res.Block.Finalized, - }, nil + return res.Block.Finalized, nil } func (bc *BabylonConsumerController) QueryActivatedHeight() (uint64, error) { diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index b3450df2..73a8fc32 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -95,13 +95,12 @@ func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64 return blocks, nil } -func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { - - return &types.BlockInfo{ - Height: height, - Hash: nil, - Finalized: false, - }, nil +func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { + /* TODO: implement + 1. get the latest finalized block number from `latestBlockNumber()` in the L1 L2OutputOracle contract + 2. compare the block number with `height` + */ + return false, nil } func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index feb35af4..ae7f2197 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -65,8 +65,8 @@ type ConsumerController interface { // QueryLatestFinalizedBlocks returns the latest finalized blocks QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) - // QueryBlock queries the block at the given height - QueryBlock(height uint64) (*types.BlockInfo, error) + // QueryIsBlockFinalized queries if the block at the given height is finalized + QueryIsBlockFinalized(height uint64) (bool, error) // QueryBlocks returns a list of blocks from startHeight to endHeight QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) diff --git a/finality-provider/service/chain_poller.go b/finality-provider/service/chain_poller.go index 6ea2979b..28b82460 100644 --- a/finality-provider/service/chain_poller.go +++ b/finality-provider/service/chain_poller.go @@ -152,11 +152,11 @@ func (cp *ChainPoller) latestBlockHeightWithRetry() (uint64, error) { func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { var ( - block *types.BlockInfo - err error + blocks []*types.BlockInfo + err error ) if err := retry.Do(func() error { - block, err = cp.consumerCon.QueryBlock(height) + blocks, err = cp.consumerCon.QueryBlocks(height, height, 1) if err != nil { return err } @@ -173,7 +173,7 @@ func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { return nil, err } - return block, nil + return blocks[0], nil } func (cp *ChainPoller) validateStartHeight(startHeight uint64) error { diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 6d777f2d..20c405e8 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -41,7 +41,8 @@ func FuzzChainPoller_Start(f *testing.F) { resBlock := &types.BlockInfo{ Height: i, } - mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + // mockConsumerController.EXPECT().QueryIsBlockFinalized(i).Return(false, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(i, i, 1).Return([]*types.BlockInfo{resBlock}, nil).AnyTimes() } // TODO: use mock metrics @@ -89,7 +90,8 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { resBlock := &types.BlockInfo{ Height: i, } - mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + // mockConsumerController.EXPECT().QueryIsBlockFinalized(i).Return(false, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(i, i, 1).Return([]*types.BlockInfo{resBlock}, nil).AnyTimes() } // TODO: use mock metrics diff --git a/finality-provider/service/fastsync.go b/finality-provider/service/fastsync.go index 77089faa..1821bc1d 100644 --- a/finality-provider/service/fastsync.go +++ b/finality-provider/service/fastsync.go @@ -50,11 +50,11 @@ func (fp *FinalityProviderInstance) FastSync(startHeight, endHeight uint64) (*Fa catchUpBlocks := make([]*types.BlockInfo, 0, len(blocks)) for _, b := range blocks { // check whether the block has been processed before - if fp.hasProcessed(b) { + if fp.hasProcessed(b.Height) { continue } // check whether the finality provider has voting power - hasVp, err := fp.hasVotingPower(b) + hasVp, err := fp.hasVotingPower(b.Height) if err != nil { return nil, err } diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index 00a5ba16..247a6519 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -200,11 +200,11 @@ func (fp *FinalityProviderInstance) finalitySigSubmissionLoop() { ) // check whether the block has been processed before - if fp.hasProcessed(b) { + if fp.hasProcessed(b.Height) { continue } // check whether the finality provider has voting power - hasVp, err := fp.hasVotingPower(b) + hasVp, err := fp.hasVotingPower(b.Height) if err != nil { fp.reportCriticalErr(err) continue @@ -359,12 +359,12 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlockHeight uint64) (*Fast return fp.FastSync(startHeight, targetBlockHeight) } -func (fp *FinalityProviderInstance) hasProcessed(b *types.BlockInfo) bool { - if b.Height <= fp.GetLastProcessedHeight() { +func (fp *FinalityProviderInstance) hasProcessed(blockHeight uint64) bool { + if blockHeight <= fp.GetLastProcessedHeight() { fp.logger.Debug( "the block has been processed before, skip processing", zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("block_height", b.Height), + zap.Uint64("block_height", blockHeight), zap.Uint64("last_processed_height", fp.GetLastProcessedHeight()), ) return true @@ -374,8 +374,8 @@ func (fp *FinalityProviderInstance) hasProcessed(b *types.BlockInfo) bool { } // hasVotingPower checks whether the finality provider has voting power for the given block -func (fp *FinalityProviderInstance) hasVotingPower(b *types.BlockInfo) (bool, error) { - power, err := fp.GetVotingPowerWithRetry(b.Height) +func (fp *FinalityProviderInstance) hasVotingPower(blockHeight uint64) (bool, error) { + power, err := fp.GetVotingPowerWithRetry(blockHeight) if err != nil { return false, err } @@ -383,7 +383,7 @@ func (fp *FinalityProviderInstance) hasVotingPower(b *types.BlockInfo) (bool, er fp.logger.Debug( "the finality provider does not have voting power", zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("block_height", b.Height), + zap.Uint64("block_height", blockHeight), ) return false, nil @@ -466,12 +466,12 @@ func (fp *FinalityProviderInstance) retrySubmitFinalitySignatureUntilBlockFinali } func (fp *FinalityProviderInstance) checkBlockFinalization(height uint64) (bool, error) { - b, err := fp.consumerCon.QueryBlock(height) + finalized, err := fp.consumerCon.QueryIsBlockFinalized(height) if err != nil { return false, err } - return b.Finalized, nil + return finalized, nil } // SubmitFinalitySignature builds and sends a finality signature over the given block to the consumer chain diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index 3c16e833..8b90d8f1 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -56,7 +56,7 @@ func FuzzStatusUpdate(f *testing.F) { mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - mockConsumerController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(gomock.Any(), gomock.Any(), gomock.Any()).Return([]*types.BlockInfo{currentBlockRes}, nil).AnyTimes() votingPower := uint64(r.Intn(2)) mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes() diff --git a/itest/test_manager.go b/itest/test_manager.go index 98caf53c..deeb65cc 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -317,12 +317,12 @@ func (tm *TestManager) CheckBlockFinalization(t *testing.T, height uint64, num i // as the votes have been collected, the block should be finalized require.Eventually(t, func() bool { - b, err := tm.BBNConsumerClient.QueryBlock(height) + finalized, err := tm.BBNConsumerClient.QueryIsBlockFinalized(height) if err != nil { t.Logf("failed to query block at height %v: %s", height, err.Error()) return false } - return b.Finalized + return finalized }, eventuallyWaitTimeOut, eventuallyPollTime) } diff --git a/testutil/mocks/clientcontroller.go b/testutil/mocks/clientcontroller.go index 65ceafa1..5eb98bd6 100644 --- a/testutil/mocks/clientcontroller.go +++ b/testutil/mocks/clientcontroller.go @@ -148,21 +148,6 @@ func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } -// QueryBlock mocks base method. -func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryBlock", height) - ret0, _ := ret[0].(*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryBlock indicates an expected call of QueryBlock. -func (mr *MockConsumerControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBlock), height) -} - // QueryBlocks mocks base method. func (m *MockConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() @@ -193,6 +178,21 @@ func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(f return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) } +// QueryIsBlockFinalized mocks base method. +func (m *MockConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryIsBlockFinalized", height) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryIsBlockFinalized indicates an expected call of QueryIsBlockFinalized. +func (mr *MockConsumerControllerMockRecorder) QueryIsBlockFinalized(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryIsBlockFinalized", reflect.TypeOf((*MockConsumerController)(nil).QueryIsBlockFinalized), height) +} + // QueryLatestBlockHeight mocks base method. func (m *MockConsumerController) QueryLatestBlockHeight() (uint64, error) { m.ctrl.T.Helper() diff --git a/testutil/utils.go b/testutil/utils.go index 05bc4c25..70bbc31e 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -27,7 +27,8 @@ func PrepareMockedConsumerController(t *testing.T, r *rand.Rand, startHeight, cu Height: currentHeight, Hash: GenRandomByteArray(r, 32), } - mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + // mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(i, i, 1).Return([]*types.BlockInfo{resBlock}, nil).AnyTimes() } mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() diff --git a/types/blockinfo.go b/types/blockinfo.go index 4fbc3708..ec302ac2 100644 --- a/types/blockinfo.go +++ b/types/blockinfo.go @@ -1,7 +1,6 @@ package types type BlockInfo struct { - Height uint64 - Hash []byte - Finalized bool + Height uint64 + Hash []byte } From 252a3284c1d5d9f0a1dff90820ae1701d2eb1e93 Mon Sep 17 00:00:00 2001 From: bap2pecs <111917526+bap2pecs@users.noreply.github.com> Date: Mon, 20 May 2024 10:05:16 -0400 Subject: [PATCH 13/26] split ClientController and ConsumerController (Part 2) (#335) --- Makefile | 3 +- clientcontroller/babylon.go | 13 -- clientcontroller/babylon_consumer.go | 12 -- clientcontroller/evm_consumer.go | 46 ++++- clientcontroller/interface.go | 8 +- finality-provider/service/app_test.go | 12 +- .../service/chain_poller_test.go | 26 +-- finality-provider/service/fastsync_test.go | 15 +- finality-provider/service/fp_instance.go | 2 +- finality-provider/service/fp_instance_test.go | 11 +- finality-provider/service/fp_manager_test.go | 21 +-- .../mocks/{babylon.go => clientcontroller.go} | 177 +++++++++++------- testutil/utils.go | 24 ++- 13 files changed, 212 insertions(+), 158 deletions(-) rename testutil/mocks/{babylon.go => clientcontroller.go} (64%) diff --git a/Makefile b/Makefile index c8d6b32c..47f9b1b3 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ build-docker: .PHONY: build build-docker test: + make mock-gen go test ./... test-e2e: @@ -75,7 +76,7 @@ proto-gen: mock-gen: mkdir -p $(MOCKS_DIR) - $(MOCKGEN_CMD) -source=clientcontroller/interface.go -package mocks -destination $(MOCKS_DIR)/babylon.go + $(MOCKGEN_CMD) -source=clientcontroller/interface.go -package mocks -destination $(MOCKS_DIR)/clientcontroller.go .PHONY: mock-gen diff --git a/clientcontroller/babylon.go b/clientcontroller/babylon.go index 7a28467a..703d5c68 100644 --- a/clientcontroller/babylon.go +++ b/clientcontroller/babylon.go @@ -162,19 +162,6 @@ func (bc *BabylonController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) return slashed, nil } -// QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height -func (bc *BabylonController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { - res, err := bc.bbnClient.QueryClient.FinalityProviderPowerAtHeight( - bbntypes.NewBIP340PubKeyFromBTCPK(fpPk).MarshalHex(), - blockHeight, - ) - if err != nil { - return 0, fmt.Errorf("failed to query the finality provider's voting power at height %d: %w", blockHeight, err) - } - - return res.VotingPower, nil -} - // QueryFinalityProviderRegisteredEpoch queries the registered epoch of the finality provider func (bc *BabylonController) QueryFinalityProviderRegisteredEpoch(fpPk *btcec.PublicKey) (uint64, error) { res, err := bc.bbnClient.QueryClient.FinalityProvider( diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index ae470ee7..8060942f 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -153,18 +153,6 @@ func (bc *BabylonConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicK return &types.TxResponse{TxHash: res.TxHash, Events: res.Events}, nil } -func (bc *BabylonConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - fpPubKey := bbntypes.NewBIP340PubKeyFromBTCPK(fpPk) - res, err := bc.bbnClient.QueryClient.FinalityProvider(fpPubKey.MarshalHex()) - if err != nil { - return false, fmt.Errorf("failed to query the finality provider %s: %v", fpPubKey.MarshalHex(), err) - } - - slashed := res.FinalityProvider.SlashedBtcHeight > 0 - - return slashed, nil -} - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height func (bc *BabylonConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { res, err := bc.bbnClient.QueryClient.FinalityProviderPowerAtHeight( diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index f664f849..c55a091a 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -13,6 +13,10 @@ import ( "go.uber.org/zap" ) +// TODO: rename the file name, class name and etc +// This is not a simple EVM chain. It's a OP Stack L2 chain, which has many +// implications. So we should rename to sth like e.g. OPStackL2Consumer +// This helps distinguish from pure EVM sidechains e.g. Binance Chain var _ ConsumerController = &EVMConsumerController{} type EVMConsumerController struct { @@ -54,13 +58,24 @@ func (ec *EVMConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, return &types.TxResponse{TxHash: "", Events: nil}, nil } -func (ec *EVMConsumerController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - - return false, nil -} - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { + /* TODO: implement + + latest_committed_l2_height = read `latestBlockNumber()` from the L1 L2OutputOracle contract and return the result + + if blockHeight > latest_committed_l2_height: + + query the VP from the L1 oracle contract using "latest" as the block tag + + else: + + 1. query the L1 event `emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp, block.number);` + to find the first event where the `_l2BlockNumber` >= blockHeight + 2. get the block.number from the event + 3. query the VP from the L1 oracle contract using `block.number` as the block tag + + */ return 0, nil } @@ -90,11 +105,32 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er } func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { + /* TODO: implement + + oracle_event = query the event in the L1 oracle contract where the FP's voting power is firstly set + + l1_activated_height = get the L1 block number from the `oracle_event` + + output_event = query the L1 event `emit OutputProposed(_outputRoot, nextOutputIndex(), _l2BlockNumber, block.timestamp, block.number);` + to find the first event where the `block.number` >= l1_activated_height + + if output_event == nil: + + read `nextBlockNumber()` from the L1 L2OutputOracle contract and return the result + + else: + + return output_event._l2BlockNumber + + */ return 0, nil } func (ec *EVMConsumerController) QueryBestBlock() (*types.BlockInfo, error) { + /* TODO: implement + get the latest L2 block number from a RPC call + */ return &types.BlockInfo{ Height: uint64(0), diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index 4e05ae5a..0c94cd70 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -31,10 +31,9 @@ type ClientController interface { // Note: the following queries are only for PoC - // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height - QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) - // QueryFinalityProviderSlashed queries if the finality provider is slashed + // Note: if the FP wants to get the information from the consumer chain directly, they should add this interface + // function in ConsumerController. (https://github.com/babylonchain/finality-provider/pull/335#discussion_r1606175344) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) // QueryLastFinalizedEpoch returns the last finalised epoch of Babylon @@ -65,9 +64,6 @@ type ConsumerController interface { // QueryFinalityProviderVotingPower queries the voting power of the finality provider at a given height QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) - // QueryFinalityProviderSlashed queries if the finality provider is slashed - QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) - // QueryLatestFinalizedBlocks returns the latest finalized blocks QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) diff --git a/finality-provider/service/app_test.go b/finality-provider/service/app_test.go index 03d8b230..040378e1 100644 --- a/finality-provider/service/app_test.go +++ b/finality-provider/service/app_test.go @@ -48,11 +48,11 @@ 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.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() - mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), gomock.Any()).Return(uint64(0), nil).AnyTimes() - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(uint64(0), nil).AnyTimes() + mockBabylonController := testutil.PrepareMockedBabylonController(t, uint64(0)) // Create randomized config fpHomeDir := filepath.Join(t.TempDir(), "fp-home") @@ -61,7 +61,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) { fpCfg.PollerConfig.StaticChainScanningStartHeight = randomStartingHeight fpdb, err := fpCfg.DatabaseConfig.GetDbBackend() require.NoError(t, err) - app, err := service.NewFinalityProviderApp(&fpCfg, mockClientController, mockClientController, em, fpdb, logger) + app, err := service.NewFinalityProviderApp(&fpCfg, mockBabylonController, mockConsumerController, em, fpdb, logger) require.NoError(t, err) defer func() { err = fpdb.Close() @@ -98,7 +98,7 @@ func FuzzRegisterFinalityProvider(f *testing.F) { require.Equal(t, fpInfo.BtcPkHex, fpListInfo[0].BtcPkHex) txHash := testutil.GenRandomHexStr(r, 32) - mockClientController.EXPECT(). + mockBabylonController.EXPECT(). RegisterFinalityProvider( fp.ChainPk.Key, fp.BtcPk, diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 2b918540..7bd71ee7 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -30,27 +30,28 @@ func FuzzChainPoller_Start(f *testing.F) { endHeight := startHeight + uint64(r.Int63n(10)+1) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockBabylonController := mocks.NewMockClientController(ctl) + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController := mocks.NewMockConsumerController(ctl) + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() currentBlockRes := &types.BlockInfo{ Height: currentHeight, } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() for i := startHeight; i <= endHeight; i++ { resBlock := &types.BlockInfo{ Height: i, } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } // TODO: use mock metrics m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 10 * time.Millisecond - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockBabylonController, mockConsumerController, m) err := poller.Start(startHeight) require.NoError(t, err) defer func() { @@ -81,27 +82,28 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { skipHeight := endHeight + uint64(r.Int63n(10)+1) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockBabylonController := mocks.NewMockClientController(ctl) + mockConsumerController := mocks.NewMockConsumerController(ctl) + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() currentBlockRes := &types.BlockInfo{ Height: currentHeight, } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() for i := startHeight; i <= skipHeight; i++ { resBlock := &types.BlockInfo{ Height: i, } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } // TODO: use mock metrics m := metrics.NewFpMetrics() pollerCfg := fpcfg.DefaultChainPollerConfig() pollerCfg.PollInterval = 1 * time.Second - poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockClientController, mockClientController, m) + poller := service.NewChainPoller(zap.NewNop(), &pollerCfg, mockBabylonController, mockConsumerController, m) // should expect error if the poller is not started err := poller.SkipToHeight(skipHeight) require.Error(t, err) diff --git a/finality-provider/service/fastsync_test.go b/finality-provider/service/fastsync_test.go index 187b1d7b..51f0dd43 100644 --- a/finality-provider/service/fastsync_test.go +++ b/finality-provider/service/fastsync_test.go @@ -24,23 +24,22 @@ func FuzzFastSync(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) - // mock finalised BTC timestamped - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) + mockBabylonController := testutil.PrepareMockedBabylonController(t, randomRegiteredEpoch) + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockBabylonController, mockConsumerController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power - mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). Return(uint64(1), nil).AnyTimes() catchUpBlocks := testutil.GenBlocks(r, finalizedHeight+1, currentHeight) expectedTxHash := testutil.GenRandomHexStr(r, 32) finalizedBlock := &types.BlockInfo{Height: finalizedHeight, Hash: testutil.GenRandomByteArray(r, 32)} - mockClientController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return([]*types.BlockInfo{finalizedBlock}, nil).AnyTimes() - mockClientController.EXPECT().QueryBlocks(finalizedHeight+1, currentHeight, uint64(10)). + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(uint64(1)).Return([]*types.BlockInfo{finalizedBlock}, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlocks(finalizedHeight+1, currentHeight, uint64(10)). Return(catchUpBlocks, nil) - mockClientController.EXPECT().SubmitBatchFinalitySigs(fpIns.GetBtcPk(), catchUpBlocks, gomock.Any()). + mockConsumerController.EXPECT().SubmitBatchFinalitySigs(fpIns.GetBtcPk(), catchUpBlocks, gomock.Any()). Return(&types.TxResponse{TxHash: expectedTxHash}, nil).AnyTimes() result, err := fpIns.FastSync(finalizedHeight+1, currentHeight) require.NoError(t, err) diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index c9f21a40..e434fb32 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -692,7 +692,7 @@ func (fp *FinalityProviderInstance) GetFinalityProviderSlashedWithRetry() (bool, ) if err := retry.Do(func() error { - slashed, err = fp.consumerCon.QueryFinalityProviderSlashed(fp.GetBtcPk()) + slashed, err = fp.cc.QueryFinalityProviderSlashed(fp.GetBtcPk()) if err != nil { return err } diff --git a/finality-provider/service/fp_instance_test.go b/finality-provider/service/fp_instance_test.go index a139635f..9077e3e7 100644 --- a/finality-provider/service/fp_instance_test.go +++ b/finality-provider/service/fp_instance_test.go @@ -30,15 +30,14 @@ 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) - // mock finalised BTC timestamped - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() + mockConsumerController := testutil.PrepareMockedConsumerController(t, r, randomStartingHeight, currentHeight) + mockBabylonController := testutil.PrepareMockedBabylonController(t, randomRegiteredEpoch) - _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockClientController, mockClientController, randomStartingHeight, randomRegiteredEpoch) + _, fpIns, cleanUp := startFinalityProviderAppWithRegisteredFp(t, r, mockBabylonController, mockConsumerController, randomStartingHeight, randomRegiteredEpoch) defer cleanUp() // mock voting power - mockClientController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(fpIns.GetBtcPk(), gomock.Any()). Return(uint64(1), nil).AnyTimes() // submit finality sig @@ -47,7 +46,7 @@ func FuzzSubmitFinalitySig(f *testing.F) { Hash: testutil.GenRandomByteArray(r, 32), } expectedTxHash := testutil.GenRandomHexStr(r, 32) - mockClientController.EXPECT(). + mockConsumerController.EXPECT(). SubmitFinalitySig(fpIns.GetBtcPk(), nextBlock.Height, nextBlock.Hash, gomock.Any()). Return(&types.TxResponse{TxHash: expectedTxHash}, nil).AnyTimes() providerRes, err := fpIns.SubmitFinalitySignature(nextBlock) diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index 320b6636..eb2a0122 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -41,8 +41,9 @@ func FuzzStatusUpdate(f *testing.F) { r := rand.New(rand.NewSource(seed)) ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) - vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController, mockClientController) + mockClientController := testutil.PrepareMockedBabylonController(t, uint64(0)) + mockConsumerController := mocks.NewMockConsumerController(ctl) + vm, fpPk, cleanUp := newFinalityProviderManagerWithRegisteredFp(t, r, mockClientController, mockConsumerController) defer cleanUp() // setup mocks @@ -51,17 +52,15 @@ func FuzzStatusUpdate(f *testing.F) { Height: currentHeight, Hash: datagen.GenRandomByteArray(r, 32), } - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - 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().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().QueryLastFinalizedEpoch().Return(uint64(0), nil).AnyTimes() + mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() votingPower := uint64(r.Intn(2)) - mockClientController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes() - mockClientController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes() + mockConsumerController.EXPECT().QueryFinalityProviderVotingPower(gomock.Any(), currentHeight).Return(votingPower, nil).AnyTimes() + mockConsumerController.EXPECT().SubmitFinalitySig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(&types.TxResponse{TxHash: ""}, nil).AnyTimes() var slashedHeight uint64 if votingPower == 0 { mockClientController.EXPECT().QueryFinalityProviderSlashed(gomock.Any()).Return(true, nil).AnyTimes() diff --git a/testutil/mocks/babylon.go b/testutil/mocks/clientcontroller.go similarity index 64% rename from testutil/mocks/babylon.go rename to testutil/mocks/clientcontroller.go index bf9cc8bb..b9b754ca 100644 --- a/testutil/mocks/babylon.go +++ b/testutil/mocks/clientcontroller.go @@ -50,8 +50,91 @@ func (mr *MockClientControllerMockRecorder) Close() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockClientController)(nil).Close)) } +// QueryFinalityProviderSlashed mocks base method. +func (m *MockClientController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryFinalityProviderSlashed", fpPk) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryFinalityProviderSlashed indicates an expected call of QueryFinalityProviderSlashed. +func (mr *MockClientControllerMockRecorder) QueryFinalityProviderSlashed(fpPk interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderSlashed", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderSlashed), fpPk) +} + +// QueryLastFinalizedEpoch mocks base method. +func (m *MockClientController) QueryLastFinalizedEpoch() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryLastFinalizedEpoch") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryLastFinalizedEpoch indicates an expected call of QueryLastFinalizedEpoch. +func (mr *MockClientControllerMockRecorder) QueryLastFinalizedEpoch() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLastFinalizedEpoch", reflect.TypeOf((*MockClientController)(nil).QueryLastFinalizedEpoch)) +} + +// RegisterFinalityProvider mocks base method. +func (m *MockClientController) RegisterFinalityProvider(chainPk []byte, fpPk *btcec.PublicKey, pop []byte, commission *math.LegacyDec, description []byte, masterPubRand string) (*types.TxResponse, uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegisterFinalityProvider", chainPk, fpPk, pop, commission, description, masterPubRand) + ret0, _ := ret[0].(*types.TxResponse) + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// RegisterFinalityProvider indicates an expected call of RegisterFinalityProvider. +func (mr *MockClientControllerMockRecorder) RegisterFinalityProvider(chainPk, fpPk, pop, commission, description, masterPubRand interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterFinalityProvider", reflect.TypeOf((*MockClientController)(nil).RegisterFinalityProvider), chainPk, fpPk, pop, commission, description, masterPubRand) +} + +// MockConsumerController is a mock of ConsumerController interface. +type MockConsumerController struct { + ctrl *gomock.Controller + recorder *MockConsumerControllerMockRecorder +} + +// MockConsumerControllerMockRecorder is the mock recorder for MockConsumerController. +type MockConsumerControllerMockRecorder struct { + mock *MockConsumerController +} + +// NewMockConsumerController creates a new mock instance. +func NewMockConsumerController(ctrl *gomock.Controller) *MockConsumerController { + mock := &MockConsumerController{ctrl: ctrl} + mock.recorder = &MockConsumerControllerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConsumerController) EXPECT() *MockConsumerControllerMockRecorder { + return m.recorder +} + +// Close mocks base method. +func (m *MockConsumerController) Close() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Close") + ret0, _ := ret[0].(error) + return ret0 +} + +// Close indicates an expected call of Close. +func (mr *MockConsumerControllerMockRecorder) Close() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConsumerController)(nil).Close)) +} + // QueryActivatedHeight mocks base method. -func (m *MockClientController) QueryActivatedHeight() (uint64, error) { +func (m *MockConsumerController) QueryActivatedHeight() (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryActivatedHeight") ret0, _ := ret[0].(uint64) @@ -60,13 +143,13 @@ func (m *MockClientController) QueryActivatedHeight() (uint64, error) { } // QueryActivatedHeight indicates an expected call of QueryActivatedHeight. -func (mr *MockClientControllerMockRecorder) QueryActivatedHeight() *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockClientController)(nil).QueryActivatedHeight)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } // QueryBestBlock mocks base method. -func (m *MockClientController) QueryBestBlock() (*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBestBlock() (*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBestBlock") ret0, _ := ret[0].(*types.BlockInfo) @@ -75,13 +158,13 @@ func (m *MockClientController) QueryBestBlock() (*types.BlockInfo, error) { } // QueryBestBlock indicates an expected call of QueryBestBlock. -func (mr *MockClientControllerMockRecorder) QueryBestBlock() *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBestBlock() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockClientController)(nil).QueryBestBlock)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBestBlock)) } // QueryBlock mocks base method. -func (m *MockClientController) QueryBlock(height uint64) (*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBlock", height) ret0, _ := ret[0].(*types.BlockInfo) @@ -90,13 +173,13 @@ func (m *MockClientController) QueryBlock(height uint64) (*types.BlockInfo, erro } // QueryBlock indicates an expected call of QueryBlock. -func (mr *MockClientControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockClientController)(nil).QueryBlock), height) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBlock), height) } // QueryBlocks mocks base method. -func (m *MockClientController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { +func (m *MockConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryBlocks", startHeight, endHeight, limit) ret0, _ := ret[0].([]*types.BlockInfo) @@ -105,28 +188,13 @@ func (m *MockClientController) QueryBlocks(startHeight, endHeight, limit uint64) } // QueryBlocks indicates an expected call of QueryBlocks. -func (mr *MockClientControllerMockRecorder) QueryBlocks(startHeight, endHeight, limit interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryBlocks(startHeight, endHeight, limit interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlocks", reflect.TypeOf((*MockClientController)(nil).QueryBlocks), startHeight, endHeight, limit) -} - -// QueryFinalityProviderSlashed mocks base method. -func (m *MockClientController) QueryFinalityProviderSlashed(fpPk *btcec.PublicKey) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryFinalityProviderSlashed", fpPk) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryFinalityProviderSlashed indicates an expected call of QueryFinalityProviderSlashed. -func (mr *MockClientControllerMockRecorder) QueryFinalityProviderSlashed(fpPk interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderSlashed", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderSlashed), fpPk) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryBlocks), startHeight, endHeight, limit) } // QueryFinalityProviderVotingPower mocks base method. -func (m *MockClientController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { +func (m *MockConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryFinalityProviderVotingPower", fpPk, blockHeight) ret0, _ := ret[0].(uint64) @@ -135,28 +203,13 @@ func (m *MockClientController) QueryFinalityProviderVotingPower(fpPk *btcec.Publ } // QueryFinalityProviderVotingPower indicates an expected call of QueryFinalityProviderVotingPower. -func (mr *MockClientControllerMockRecorder) QueryFinalityProviderVotingPower(fpPk, blockHeight interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(fpPk, blockHeight interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockClientController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) -} - -// QueryLastFinalizedEpoch mocks base method. -func (m *MockClientController) QueryLastFinalizedEpoch() (uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryLastFinalizedEpoch") - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryLastFinalizedEpoch indicates an expected call of QueryLastFinalizedEpoch. -func (mr *MockClientControllerMockRecorder) QueryLastFinalizedEpoch() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLastFinalizedEpoch", reflect.TypeOf((*MockClientController)(nil).QueryLastFinalizedEpoch)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) } // QueryLatestFinalizedBlocks mocks base method. -func (m *MockClientController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { +func (m *MockConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "QueryLatestFinalizedBlocks", count) ret0, _ := ret[0].([]*types.BlockInfo) @@ -165,29 +218,13 @@ func (m *MockClientController) QueryLatestFinalizedBlocks(count uint64) ([]*type } // QueryLatestFinalizedBlocks indicates an expected call of QueryLatestFinalizedBlocks. -func (mr *MockClientControllerMockRecorder) QueryLatestFinalizedBlocks(count interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlocks", reflect.TypeOf((*MockClientController)(nil).QueryLatestFinalizedBlocks), count) -} - -// RegisterFinalityProvider mocks base method. -func (m *MockClientController) RegisterFinalityProvider(chainPk []byte, fpPk *btcec.PublicKey, pop []byte, commission *math.LegacyDec, description []byte, masterPubRand string) (*types.TxResponse, uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RegisterFinalityProvider", chainPk, fpPk, pop, commission, description, masterPubRand) - ret0, _ := ret[0].(*types.TxResponse) - ret1, _ := ret[1].(uint64) - ret2, _ := ret[2].(error) - return ret0, ret1, ret2 -} - -// RegisterFinalityProvider indicates an expected call of RegisterFinalityProvider. -func (mr *MockClientControllerMockRecorder) RegisterFinalityProvider(chainPk, fpPk, pop, commission, description, masterPubRand interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) QueryLatestFinalizedBlocks(count interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterFinalityProvider", reflect.TypeOf((*MockClientController)(nil).RegisterFinalityProvider), chainPk, fpPk, pop, commission, description, masterPubRand) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestFinalizedBlocks), count) } // SubmitBatchFinalitySigs mocks base method. -func (m *MockClientController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { +func (m *MockConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SubmitBatchFinalitySigs", fpPk, blocks, sigs) ret0, _ := ret[0].(*types.TxResponse) @@ -196,13 +233,13 @@ func (m *MockClientController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, bl } // SubmitBatchFinalitySigs indicates an expected call of SubmitBatchFinalitySigs. -func (mr *MockClientControllerMockRecorder) SubmitBatchFinalitySigs(fpPk, blocks, sigs interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) SubmitBatchFinalitySigs(fpPk, blocks, sigs interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitBatchFinalitySigs", reflect.TypeOf((*MockClientController)(nil).SubmitBatchFinalitySigs), fpPk, blocks, sigs) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitBatchFinalitySigs", reflect.TypeOf((*MockConsumerController)(nil).SubmitBatchFinalitySigs), fpPk, blocks, sigs) } // SubmitFinalitySig mocks base method. -func (m *MockClientController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { +func (m *MockConsumerController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHeight uint64, blockHash []byte, sig *btcec.ModNScalar) (*types.TxResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SubmitFinalitySig", fpPk, blockHeight, blockHash, sig) ret0, _ := ret[0].(*types.TxResponse) @@ -211,7 +248,7 @@ func (m *MockClientController) SubmitFinalitySig(fpPk *btcec.PublicKey, blockHei } // SubmitFinalitySig indicates an expected call of SubmitFinalitySig. -func (mr *MockClientControllerMockRecorder) SubmitFinalitySig(fpPk, blockHeight, blockHash, sig interface{}) *gomock.Call { +func (mr *MockConsumerControllerMockRecorder) SubmitFinalitySig(fpPk, blockHeight, blockHash, sig interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitFinalitySig", reflect.TypeOf((*MockClientController)(nil).SubmitFinalitySig), fpPk, blockHeight, blockHash, sig) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitFinalitySig", reflect.TypeOf((*MockConsumerController)(nil).SubmitFinalitySig), fpPk, blockHeight, blockHash, sig) } diff --git a/testutil/utils.go b/testutil/utils.go index 76f14af2..fc8ddadb 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -18,16 +18,16 @@ func ZeroCommissionRate() *sdkmath.LegacyDec { return &zeroCom } -func PrepareMockedClientController(t *testing.T, r *rand.Rand, startHeight, currentHeight uint64) *mocks.MockClientController { +func PrepareMockedConsumerController(t *testing.T, r *rand.Rand, startHeight, currentHeight uint64) *mocks.MockConsumerController { ctl := gomock.NewController(t) - mockClientController := mocks.NewMockClientController(ctl) + mockConsumerController := mocks.NewMockConsumerController(ctl) for i := startHeight + 1; i <= currentHeight; i++ { resBlock := &types.BlockInfo{ Height: currentHeight, Hash: GenRandomByteArray(r, 32), } - mockClientController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() + mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } currentBlockRes := &types.BlockInfo{ @@ -35,9 +35,19 @@ func PrepareMockedClientController(t *testing.T, r *rand.Rand, startHeight, curr Hash: GenRandomByteArray(r, 32), } - mockClientController.EXPECT().Close().Return(nil).AnyTimes() - mockClientController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() - mockClientController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() + mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() + mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - return mockClientController + return mockConsumerController +} + +func PrepareMockedBabylonController(t *testing.T, randomRegiteredEpoch uint64) *mocks.MockClientController { + ctl := gomock.NewController(t) + mockBabylonController := mocks.NewMockClientController(ctl) + // mock finalised BTC timestamped + mockBabylonController.EXPECT().QueryLastFinalizedEpoch().Return(randomRegiteredEpoch, nil).AnyTimes() + mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() + + return mockBabylonController } From 5e6e9ad7355bf14f8fd581df9f313dcb3fba195c Mon Sep 17 00:00:00 2001 From: bap2pecs <111917526+bap2pecs@users.noreply.github.com> Date: Mon, 20 May 2024 10:13:44 -0400 Subject: [PATCH 14/26] Refactor QueryBestBlock() to only return the uint64 block height (#336) --- clientcontroller/babylon_consumer.go | 7 +-- clientcontroller/evm_consumer.go | 7 +-- clientcontroller/interface.go | 4 +- finality-provider/service/app.go | 4 +- finality-provider/service/chain_poller.go | 16 +++---- .../service/chain_poller_test.go | 11 +---- finality-provider/service/fp_instance.go | 44 +++++++++---------- finality-provider/service/fp_manager.go | 19 ++++---- finality-provider/service/fp_manager_test.go | 2 +- itest/e2e_test.go | 3 +- itest/test_manager.go | 6 +-- testutil/mocks/clientcontroller.go | 30 ++++++------- testutil/utils.go | 7 +-- 13 files changed, 72 insertions(+), 88 deletions(-) diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index 8060942f..5eb3c476 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -232,14 +232,15 @@ func (bc *BabylonConsumerController) QueryActivatedHeight() (uint64, error) { return res.Height, nil } -func (bc *BabylonConsumerController) QueryBestBlock() (*types.BlockInfo, error) { +func (bc *BabylonConsumerController) QueryLatestBlockHeight() (uint64, error) { blocks, err := bc.queryLatestBlocks(nil, 1, finalitytypes.QueriedBlockStatus_ANY, true) if err != nil || len(blocks) != 1 { // try query comet block if the index block query is not available - return bc.queryCometBestBlock() + block, err := bc.queryCometBestBlock() + return block.Height, err } - return blocks[0], nil + return blocks[0].Height, nil } func (bc *BabylonConsumerController) queryCometBestBlock() (*types.BlockInfo, error) { diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index c55a091a..b3450df2 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -127,15 +127,12 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { return 0, nil } -func (ec *EVMConsumerController) QueryBestBlock() (*types.BlockInfo, error) { +func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { /* TODO: implement get the latest L2 block number from a RPC call */ - return &types.BlockInfo{ - Height: uint64(0), - Hash: nil, - }, nil + return uint64(0), nil } func (ec *EVMConsumerController) Close() error { diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index 0c94cd70..dbdb9c9a 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -73,8 +73,8 @@ type ConsumerController interface { // QueryBlocks returns a list of blocks from startHeight to endHeight QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) - // QueryBestBlock queries the tip block of the consumer chain - QueryBestBlock() (*types.BlockInfo, error) + // QueryBestBlock queries the tip block height of the consumer chain + QueryLatestBlockHeight() (uint64, error) // QueryActivatedHeight returns the activated height of the consumer chain // error will be returned if the consumer chain has not been activated diff --git a/finality-provider/service/app.go b/finality-provider/service/app.go index ae870645..5baaf8e3 100644 --- a/finality-provider/service/app.go +++ b/finality-provider/service/app.go @@ -231,7 +231,7 @@ func (app *FinalityProviderApp) getFpPrivKey(fpPk []byte) (*btcec.PrivateKey, er // SyncFinalityProviderStatus syncs the status of the finality-providers func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { - latestBlock, err := app.consumerCon.QueryBestBlock() + latestBlockHeight, err := app.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -242,7 +242,7 @@ func (app *FinalityProviderApp) SyncFinalityProviderStatus() error { } for _, fp := range fps { - vp, err := app.consumerCon.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlock.Height) + vp, err := app.consumerCon.QueryFinalityProviderVotingPower(fp.BtcPk, latestBlockHeight) if err != nil { // if error occured then the finality-provider is not registered in the Babylon chain yet continue diff --git a/finality-provider/service/chain_poller.go b/finality-provider/service/chain_poller.go index 3c40db11..6ea2979b 100644 --- a/finality-provider/service/chain_poller.go +++ b/finality-provider/service/chain_poller.go @@ -125,14 +125,14 @@ func (cp *ChainPoller) GetBlockInfoChan() <-chan *types.BlockInfo { return cp.blockInfoChan } -func (cp *ChainPoller) latestBlockWithRetry() (*types.BlockInfo, error) { +func (cp *ChainPoller) latestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = cp.consumerCon.QueryBestBlock() + latestBlockHeight, err = cp.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -145,9 +145,9 @@ func (cp *ChainPoller) latestBlockWithRetry() (*types.BlockInfo, error) { zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - return latestBlock, nil + return latestBlockHeight, nil } func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { @@ -186,13 +186,13 @@ func (cp *ChainPoller) validateStartHeight(startHeight uint64) error { var currentBestChainHeight uint64 for { - lastestBlock, err := cp.latestBlockWithRetry() + lastestBlockHeight, err := cp.latestBlockHeightWithRetry() if err != nil { cp.logger.Debug("failed to query babylon for the latest status", zap.Error(err)) continue } - currentBestChainHeight = lastestBlock.Height + currentBestChainHeight = lastestBlockHeight break } diff --git a/finality-provider/service/chain_poller_test.go b/finality-provider/service/chain_poller_test.go index 7bd71ee7..6d777f2d 100644 --- a/finality-provider/service/chain_poller_test.go +++ b/finality-provider/service/chain_poller_test.go @@ -35,10 +35,7 @@ func FuzzChainPoller_Start(f *testing.F) { mockConsumerController := mocks.NewMockConsumerController(ctl) mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - } - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() for i := startHeight; i <= endHeight; i++ { resBlock := &types.BlockInfo{ @@ -86,11 +83,7 @@ func FuzzChainPoller_SkipHeight(f *testing.F) { mockConsumerController := mocks.NewMockConsumerController(ctl) mockBabylonController.EXPECT().Close().Return(nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() - - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - } - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() for i := startHeight; i <= skipHeight; i++ { resBlock := &types.BlockInfo{ diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index e434fb32..00a5ba16 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -43,7 +43,7 @@ type FinalityProviderInstance struct { // passphrase is used to unlock private keys passphrase string - laggingTargetChan chan *types.BlockInfo + laggingTargetChan chan uint64 criticalErrChan chan<- *CriticalError isStarted *atomic.Bool @@ -131,7 +131,7 @@ func (fp *FinalityProviderInstance) Start() error { fp.poller = poller - fp.laggingTargetChan = make(chan *types.BlockInfo, 1) + fp.laggingTargetChan = make(chan uint64, 1) fp.quit = make(chan struct{}) @@ -144,13 +144,13 @@ func (fp *FinalityProviderInstance) Start() error { } func (fp *FinalityProviderInstance) bootstrap() (uint64, error) { - latestBlock, err := fp.getLatestBlockWithRetry() + latestBlockHeight, err := fp.getLatestBlockHeightWithRetry() if err != nil { return 0, err } - if fp.checkLagging(latestBlock) { - _, err := fp.tryFastSync(latestBlock) + if fp.checkLagging(latestBlockHeight) { + _, err := fp.tryFastSync(latestBlockHeight) if err != nil && !clientcontroller.IsExpected(err) { return 0, err } @@ -298,7 +298,7 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { continue } - latestBlock, err := fp.getLatestBlockWithRetry() + latestBlockHeight, err := fp.getLatestBlockHeightWithRetry() if err != nil { fp.logger.Debug( "failed to get the latest block of the consumer chain", @@ -308,9 +308,9 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { continue } - if fp.checkLagging(latestBlock) { + if fp.checkLagging(latestBlockHeight) { fp.isLagging.Store(true) - fp.laggingTargetChan <- latestBlock + fp.laggingTargetChan <- latestBlockHeight } case <-fp.quit: fp.logger.Debug("the fast sync loop is closing") @@ -319,7 +319,7 @@ func (fp *FinalityProviderInstance) checkLaggingLoop() { } } -func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (*FastSyncResult, error) { +func (fp *FinalityProviderInstance) tryFastSync(targetBlockHeight uint64) (*FastSyncResult, error) { if fp.inSync.Load() { return nil, fmt.Errorf("the finality-provider %s is already in sync", fp.GetBtcPkHex()) } @@ -333,7 +333,7 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (* fp.logger.Debug( "no finalized blocks yet, no need to catch up", zap.String("pk", fp.GetBtcPkHex()), - zap.Uint64("height", targetBlock.Height), + zap.Uint64("height", targetBlockHeight), ) return nil, nil } @@ -350,13 +350,13 @@ func (fp *FinalityProviderInstance) tryFastSync(targetBlock *types.BlockInfo) (* startHeight = lastFinalizedHeight + 1 } - if startHeight > targetBlock.Height { - return nil, fmt.Errorf("the start height %v should not be higher than the current block %v", startHeight, targetBlock.Height) + if startHeight > targetBlockHeight { + return nil, fmt.Errorf("the start height %v should not be higher than the current block %v", startHeight, targetBlockHeight) } fp.logger.Debug("the finality-provider is entering fast sync") - return fp.FastSync(startHeight, targetBlock.Height) + return fp.FastSync(startHeight, targetBlockHeight) } func (fp *FinalityProviderInstance) hasProcessed(b *types.BlockInfo) bool { @@ -400,8 +400,8 @@ func (fp *FinalityProviderInstance) reportCriticalErr(err error) { } // checkLagging returns true if the lasted voted height is behind by a configured gap -func (fp *FinalityProviderInstance) checkLagging(currentBlock *types.BlockInfo) bool { - return currentBlock.Height >= fp.GetLastProcessedHeight()+fp.cfg.FastSyncGap +func (fp *FinalityProviderInstance) checkLagging(currentBlockHeight uint64) bool { + return currentBlockHeight >= fp.GetLastProcessedHeight()+fp.cfg.FastSyncGap } // retrySubmitFinalitySignatureUntilBlockFinalized periodically tries to submit finality signature until success or the block is finalized @@ -632,14 +632,14 @@ func (fp *FinalityProviderInstance) latestFinalizedBlocksWithRetry(count uint64) return response, nil } -func (fp *FinalityProviderInstance) getLatestBlockWithRetry() (*types.BlockInfo, error) { +func (fp *FinalityProviderInstance) getLatestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = fp.consumerCon.QueryBestBlock() + latestBlockHeight, err = fp.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -652,11 +652,11 @@ func (fp *FinalityProviderInstance) getLatestBlockWithRetry() (*types.BlockInfo, zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - fp.metrics.RecordBabylonTipHeight(latestBlock.Height) + fp.metrics.RecordBabylonTipHeight(latestBlockHeight) - return latestBlock, nil + return latestBlockHeight, nil } func (fp *FinalityProviderInstance) GetVotingPowerWithRetry(height uint64) (uint64, error) { diff --git a/finality-provider/service/fp_manager.go b/finality-provider/service/fp_manager.go index 833ba088..ac517cbd 100644 --- a/finality-provider/service/fp_manager.go +++ b/finality-provider/service/fp_manager.go @@ -18,7 +18,6 @@ import ( "github.com/babylonchain/finality-provider/finality-provider/proto" "github.com/babylonchain/finality-provider/finality-provider/store" "github.com/babylonchain/finality-provider/metrics" - "github.com/babylonchain/finality-provider/types" ) const instanceTerminatingMsg = "terminating the finality-provider instance due to critical error" @@ -134,7 +133,7 @@ func (fpm *FinalityProviderManager) monitorStatusUpdate() { for { select { case <-statusUpdateTicker.C: - latestBlock, err := fpm.getLatestBlockWithRetry() + latestBlockHeight, err := fpm.getLatestBlockHeightWithRetry() if err != nil { fpm.logger.Debug("failed to get the latest block", zap.Error(err)) continue @@ -142,12 +141,12 @@ func (fpm *FinalityProviderManager) monitorStatusUpdate() { fpis := fpm.ListFinalityProviderInstances() for _, fpi := range fpis { oldStatus := fpi.GetStatus() - power, err := fpi.GetVotingPowerWithRetry(latestBlock.Height) + power, err := fpi.GetVotingPowerWithRetry(latestBlockHeight) if err != nil { fpm.logger.Debug( "failed to get the voting power", zap.String("fp_btc_pk", fpi.GetBtcPkHex()), - zap.Uint64("height", latestBlock.Height), + zap.Uint64("height", latestBlockHeight), zap.Error(err), ) continue @@ -407,14 +406,14 @@ func (fpm *FinalityProviderManager) addFinalityProviderInstance( return nil } -func (fpm *FinalityProviderManager) getLatestBlockWithRetry() (*types.BlockInfo, error) { +func (fpm *FinalityProviderManager) getLatestBlockHeightWithRetry() (uint64, error) { var ( - latestBlock *types.BlockInfo - err error + latestBlockHeight uint64 + err error ) if err := retry.Do(func() error { - latestBlock, err = fpm.consumerCon.QueryBestBlock() + latestBlockHeight, err = fpm.consumerCon.QueryLatestBlockHeight() if err != nil { return err } @@ -427,8 +426,8 @@ func (fpm *FinalityProviderManager) getLatestBlockWithRetry() (*types.BlockInfo, zap.Error(err), ) })); err != nil { - return nil, err + return 0, err } - return latestBlock, nil + return latestBlockHeight, nil } diff --git a/finality-provider/service/fp_manager_test.go b/finality-provider/service/fp_manager_test.go index eb2a0122..3c16e833 100644 --- a/finality-provider/service/fp_manager_test.go +++ b/finality-provider/service/fp_manager_test.go @@ -54,7 +54,7 @@ func FuzzStatusUpdate(f *testing.F) { } mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() mockConsumerController.EXPECT().QueryLatestFinalizedBlocks(gomock.Any()).Return(nil, nil).AnyTimes() - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() mockConsumerController.EXPECT().QueryBlock(gomock.Any()).Return(currentBlockRes, nil).AnyTimes() diff --git a/itest/e2e_test.go b/itest/e2e_test.go index 91e0094e..7e0e2010 100644 --- a/itest/e2e_test.go +++ b/itest/e2e_test.go @@ -181,8 +181,7 @@ func TestFastSync(t *testing.T) { t.Logf("the latest finalized block is at %v", finalizedHeight) // check if the fast sync works by checking if the gap is not more than 1 - currentHeaderRes, err := tm.BBNConsumerClient.QueryBestBlock() - currentHeight := currentHeaderRes.Height + currentHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() t.Logf("the current block is at %v", currentHeight) require.NoError(t, err) require.True(t, currentHeight < finalizedHeight+uint64(n)) diff --git a/itest/test_manager.go b/itest/test_manager.go index df46c714..98caf53c 100644 --- a/itest/test_manager.go +++ b/itest/test_manager.go @@ -369,18 +369,18 @@ func (tm *TestManager) WaitForFpShutDown(t *testing.T, pk *bbntypes.BIP340PubKey } func (tm *TestManager) StopAndRestartFpAfterNBlocks(t *testing.T, n int, fpIns *service.FinalityProviderInstance) { - blockBeforeStop, err := tm.BBNConsumerClient.QueryBestBlock() + blockBeforeStopHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() require.NoError(t, err) err = fpIns.Stop() require.NoError(t, err) require.Eventually(t, func() bool { - headerAfterStop, err := tm.BBNConsumerClient.QueryBestBlock() + headerAfterStopHeight, err := tm.BBNConsumerClient.QueryLatestBlockHeight() if err != nil { return false } - return headerAfterStop.Height >= uint64(n)+blockBeforeStop.Height + return headerAfterStopHeight >= uint64(n)+blockBeforeStopHeight }, eventuallyWaitTimeOut, eventuallyPollTime) t.Log("restarting the finality-provider instance") diff --git a/testutil/mocks/clientcontroller.go b/testutil/mocks/clientcontroller.go index b9b754ca..65ceafa1 100644 --- a/testutil/mocks/clientcontroller.go +++ b/testutil/mocks/clientcontroller.go @@ -148,21 +148,6 @@ func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } -// QueryBestBlock mocks base method. -func (m *MockConsumerController) QueryBestBlock() (*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryBestBlock") - ret0, _ := ret[0].(*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryBestBlock indicates an expected call of QueryBestBlock. -func (mr *MockConsumerControllerMockRecorder) QueryBestBlock() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBestBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBestBlock)) -} - // QueryBlock mocks base method. func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { m.ctrl.T.Helper() @@ -208,6 +193,21 @@ func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(f return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) } +// QueryLatestBlockHeight mocks base method. +func (m *MockConsumerController) QueryLatestBlockHeight() (uint64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryLatestBlockHeight") + ret0, _ := ret[0].(uint64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryLatestBlockHeight indicates an expected call of QueryLatestBlockHeight. +func (mr *MockConsumerControllerMockRecorder) QueryLatestBlockHeight() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestBlockHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestBlockHeight)) +} + // QueryLatestFinalizedBlocks mocks base method. func (m *MockConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() diff --git a/testutil/utils.go b/testutil/utils.go index fc8ddadb..05bc4c25 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -30,13 +30,8 @@ func PrepareMockedConsumerController(t *testing.T, r *rand.Rand, startHeight, cu mockConsumerController.EXPECT().QueryBlock(i).Return(resBlock, nil).AnyTimes() } - currentBlockRes := &types.BlockInfo{ - Height: currentHeight, - Hash: GenRandomByteArray(r, 32), - } - mockConsumerController.EXPECT().Close().Return(nil).AnyTimes() - mockConsumerController.EXPECT().QueryBestBlock().Return(currentBlockRes, nil).AnyTimes() + mockConsumerController.EXPECT().QueryLatestBlockHeight().Return(currentHeight, nil).AnyTimes() mockConsumerController.EXPECT().QueryActivatedHeight().Return(uint64(1), nil).AnyTimes() return mockConsumerController From 5119c6462444528491ade3d884a521f77c67e342 Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Mon, 20 May 2024 10:17:54 -0400 Subject: [PATCH 15/26] nit --- clientcontroller/interface.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index 571656cd..71310752 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -73,7 +73,7 @@ type ConsumerController interface { // QueryBlocks returns a list of blocks from startHeight to endHeight QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) - // QueryBestBlock queries the tip block height of the consumer chain + // QueryLatestBlockHeight queries the tip block height of the consumer chain QueryLatestBlockHeight() (uint64, error) // QueryActivatedHeight returns the activated height of the consumer chain From 79a0e20f065862f287ca5ececa007f980a6cab93 Mon Sep 17 00:00:00 2001 From: bap2pecs Date: Mon, 20 May 2024 10:28:48 -0400 Subject: [PATCH 16/26] for comments --- clientcontroller/babylon_consumer.go | 12 ++++++++++++ clientcontroller/evm_consumer.go | 8 ++++++++ clientcontroller/interface.go | 3 +++ finality-provider/service/chain_poller.go | 8 ++++---- finality-provider/service/fp_instance.go | 11 +---------- testutil/mocks/clientcontroller.go | 15 +++++++++++++++ 6 files changed, 43 insertions(+), 14 deletions(-) diff --git a/clientcontroller/babylon_consumer.go b/clientcontroller/babylon_consumer.go index 7778abf3..a2a57c61 100644 --- a/clientcontroller/babylon_consumer.go +++ b/clientcontroller/babylon_consumer.go @@ -210,6 +210,18 @@ func getContextWithCancel(timeout time.Duration) (context.Context, context.Cance return ctx, cancel } +func (bc *BabylonConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + res, err := bc.bbnClient.QueryClient.Block(height) + if err != nil { + return nil, fmt.Errorf("failed to query indexed block at height %v: %w", height, err) + } + + return &types.BlockInfo{ + Height: height, + Hash: res.Block.AppHash, + }, nil +} + func (bc *BabylonConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { res, err := bc.bbnClient.QueryClient.Block(height) if err != nil { diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 73a8fc32..df1f5a94 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -95,6 +95,14 @@ func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64 return blocks, nil } +func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + + return &types.BlockInfo{ + Height: height, + Hash: nil, + }, nil +} + func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { /* TODO: implement 1. get the latest finalized block number from `latestBlockNumber()` in the L1 L2OutputOracle contract diff --git a/clientcontroller/interface.go b/clientcontroller/interface.go index 71310752..9c52a1b5 100644 --- a/clientcontroller/interface.go +++ b/clientcontroller/interface.go @@ -67,6 +67,9 @@ type ConsumerController interface { // QueryLatestFinalizedBlocks returns the latest finalized blocks QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) + // QueryBlock queries the block at the given height + QueryBlock(height uint64) (*types.BlockInfo, error) + // QueryIsBlockFinalized queries if the block at the given height is finalized QueryIsBlockFinalized(height uint64) (bool, error) diff --git a/finality-provider/service/chain_poller.go b/finality-provider/service/chain_poller.go index 28b82460..6ea2979b 100644 --- a/finality-provider/service/chain_poller.go +++ b/finality-provider/service/chain_poller.go @@ -152,11 +152,11 @@ func (cp *ChainPoller) latestBlockHeightWithRetry() (uint64, error) { func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { var ( - blocks []*types.BlockInfo - err error + block *types.BlockInfo + err error ) if err := retry.Do(func() error { - blocks, err = cp.consumerCon.QueryBlocks(height, height, 1) + block, err = cp.consumerCon.QueryBlock(height) if err != nil { return err } @@ -173,7 +173,7 @@ func (cp *ChainPoller) blockWithRetry(height uint64) (*types.BlockInfo, error) { return nil, err } - return blocks[0], nil + return block, nil } func (cp *ChainPoller) validateStartHeight(startHeight uint64) error { diff --git a/finality-provider/service/fp_instance.go b/finality-provider/service/fp_instance.go index 247a6519..a6fc7730 100644 --- a/finality-provider/service/fp_instance.go +++ b/finality-provider/service/fp_instance.go @@ -443,7 +443,7 @@ func (fp *FinalityProviderInstance) retrySubmitFinalitySignatureUntilBlockFinali 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) + finalized, err := fp.consumerCon.QueryIsBlockFinalized(targetBlock.Height) if err != nil { return nil, fmt.Errorf("failed to query block finalization at height %v: %w", targetBlock.Height, err) } @@ -465,15 +465,6 @@ func (fp *FinalityProviderInstance) retrySubmitFinalitySignatureUntilBlockFinali } } -func (fp *FinalityProviderInstance) checkBlockFinalization(height uint64) (bool, error) { - finalized, err := fp.consumerCon.QueryIsBlockFinalized(height) - if err != nil { - return false, err - } - - return finalized, nil -} - // SubmitFinalitySignature builds and sends a finality signature over the given block to the consumer chain func (fp *FinalityProviderInstance) SubmitFinalitySignature(b *types.BlockInfo) (*types.TxResponse, error) { eotsSig, err := fp.signEotsSig(b) diff --git a/testutil/mocks/clientcontroller.go b/testutil/mocks/clientcontroller.go index 5eb98bd6..82bbd053 100644 --- a/testutil/mocks/clientcontroller.go +++ b/testutil/mocks/clientcontroller.go @@ -148,6 +148,21 @@ func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Cal return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) } +// QueryBlock mocks base method. +func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "QueryBlock", height) + ret0, _ := ret[0].(*types.BlockInfo) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// QueryBlock indicates an expected call of QueryBlock. +func (mr *MockConsumerControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBlock), height) +} + // QueryBlocks mocks base method. func (m *MockConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { m.ctrl.T.Helper() From b992c72e08aeb6bbecf7e90672b16862b156a6e2 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Mon, 20 May 2024 21:29:50 +0200 Subject: [PATCH 17/26] update after review --- clientcontroller/evm_consumer.go | 129 ++++++++++++++----------------- finality-provider/config/evm.go | 4 +- 2 files changed, 60 insertions(+), 73 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 3606b0cb..30c3ae27 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -92,47 +92,37 @@ func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*ty return nil, fmt.Errorf("can't get latest finalized block:%s", err) } + type Block struct { Number string Hash string } - var B []rpc.BatchElem + var Batch []rpc.BatchElem - for i := 0; i < int(count); i++ { + InitBatch(Batch, lastnumber, count, "descent") - hexStr := Transform(lastnumber) - ib := rpc.BatchElem{ - Method: "eth_getBlockByNumber", - Args: []interface{}{hexStr, true}, - Result: new(Block), - } - B = append(B, ib) - lastnumber.Sub(lastnumber, big.NewInt(1)) - } + err = ec.evmClient.BatchCall(Batch) - err = ec.evmClient.BatchCall(B) if err != nil { return nil, fmt.Errorf("can't get latest block:%s", err) } var blocks []*types.BlockInfo - for _, b := range B { - nb := b.Result.(*Block) + for _, batch := range Batch { + nb := batch.Result.(*Block) num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) if err != nil { fmt.Println("Error:", err) } - ib := &types.BlockInfo{ - Height: num, - Hash: []byte(nb.Hash), - Finalized: true, + ibatch := &types.BlockInfo{ + Height: num, + Hash: []byte(nb.Hash), } - blocks = append(blocks, ib) + blocks = append(blocks, ibatch) } return blocks, nil - } func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { @@ -145,11 +135,6 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 count = limit } - lastnumber, err := ec.GetLatestFinalizedNumber() - if err != nil { - return nil, fmt.Errorf("can't get latest finalized block:%s", err) - - } type Block struct { Number string Hash string @@ -157,49 +142,33 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 startnumber := new(big.Int).SetUint64(startHeight) - var B []rpc.BatchElem + var Batch []rpc.BatchElem - for i := 0; i < int(count); i++ { + InitBatch(Batch, startnumber, count, "ascent") - hexStr := Transform(startnumber) - ib := rpc.BatchElem{ - Method: "eth_getBlockByNumber", - Args: []interface{}{hexStr, true}, - Result: new(Block), - } - B = append(B, ib) - startnumber.Add(startnumber, big.NewInt(1)) - } + err := ec.evmClient.BatchCall(Batch) - err = ec.evmClient.BatchCall(B) if err != nil { - return nil, fmt.Errorf("can't get blocks") + return nil, fmt.Errorf("can't get blocks") } + var blocks []*types.BlockInfo - for _, b := range B { - nb := b.Result.(*Block) + for _, batch := range Batch { + nb := batch.Result.(*Block) num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) if err != nil { return nil, fmt.Errorf("error:%s", err) } - number := new(big.Int).SetUint64(num) - var finalized bool = false - if number.Cmp(lastnumber) <= 0 { - finalized = true + ibatch := &types.BlockInfo{ + Height: num, + Hash: []byte(nb.Hash), } - - ib := &types.BlockInfo{ - Height: num, - Hash: []byte(nb.Hash), - Finalized: finalized, - } - blocks = append(blocks, ib) + blocks = append(blocks, ibatch) } return blocks, nil - } func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { @@ -230,31 +199,27 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er return nil, fmt.Errorf("error:%s", err) } + b := &types.BlockInfo{ + Height: num, + Hash: []byte(block.Hash), + } + + return b, nil +} + +func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { + lastnumber, err := ec.GetLatestFinalizedNumber() if err != nil { - return nil, fmt.Errorf("can't get latest finalized block:%s", err) + return false, fmt.Errorf("can't get latest finalized block:%s", err) } - + number := new(big.Int).SetUint64(height) var finalized bool = false if number.Cmp(lastnumber) <= 0 { finalized = true } - b := &types.BlockInfo{ - Height: num, - Hash: []byte(block.Hash), - Finalized: finalized, - } - - return b, nil -} - -func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { - /* TODO: implement - 1. get the latest finalized block number from `latestBlockNumber()` in the L1 L2OutputOracle contract - 2. compare the block number with `height` - */ - return false, nil + return finalized, nil } func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { @@ -298,7 +263,6 @@ func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { } return num, nil - } func (ec *EVMConsumerController) Close() error { @@ -313,8 +277,8 @@ func Transform(number *big.Int) string { hexStr = "0x" + hexStr } return hexStr - } + func (ec *EVMConsumerController) GetLatestFinalizedNumber() (*big.Int, error) { conn, err := ethclient.Dial(ec.cfg.RPCL1Addr) @@ -331,5 +295,28 @@ func (ec *EVMConsumerController) GetLatestFinalizedNumber() (*big.Int, error) { return nil, fmt.Errorf("failed to get latest finalize block number:%s ", err) } return lastnumber, err +} + +func InitBatch(Batch []rpc.BatchElem, number *big.Int, count uint64, order string) { + + type Block struct { + Number string + Hash string + } + for i := 0; i < int(count); i++ { + + hexStr := Transform(number) + ibatch := rpc.BatchElem{ + Method: "eth_getBlockByNumber", + Args: []interface{}{hexStr, true}, + Result: new(Block), + } + Batch = append(Batch, ibatch) + if order == "ascent" { + number.Add(number, big.NewInt(1)) + } else if order == "descent" { + number.Sub(number, big.NewInt(1)) + } + } } diff --git a/finality-provider/config/evm.go b/finality-provider/config/evm.go index 1fd6ab38..47017a5d 100644 --- a/finality-provider/config/evm.go +++ b/finality-provider/config/evm.go @@ -10,8 +10,8 @@ const ( ) type EVMConfig struct { - RPCL1Addr string `long:"rpc-address" description:"address of the L2rpc server to connect to"` - RPCL2Addr string `long:"rpc-address" description:"address of the L1rpc server to connect to"` + RPCL1Addr string `long:"rpc-address" description:"address of the L2 RPC server to connect to"` + RPCL2Addr string `long:"rpc-address" description:"address of the L1 RPC server to connect to"` L2OutputOracleContractAddress string `long:"sol-address" description:"address of the L2output smart contract"` BitcoinStackingContractAddress string `long:"sol-address" description:"address of the Bitcoinstaking smart contract"` } From 257a441abe7cbcb6b7495dbd4d186917de24c6e3 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Mon, 20 May 2024 21:34:22 +0200 Subject: [PATCH 18/26] rename var b --- clientcontroller/evm_consumer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 30c3ae27..d9e1d6d2 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -199,12 +199,12 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er return nil, fmt.Errorf("error:%s", err) } - b := &types.BlockInfo{ + blockinfo := &types.BlockInfo{ Height: num, Hash: []byte(block.Hash), } - return b, nil + return blockinfo, nil } func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { From 4b3061e70f01f64be5599307b0589c72b61f7529 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Mon, 20 May 2024 21:44:59 +0200 Subject: [PATCH 19/26] Printf err fix --- clientcontroller/evm_consumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index d9e1d6d2..ed6304ac 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -259,7 +259,7 @@ func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { num, err := strconv.ParseUint(strings.TrimPrefix(block.Number, "0x"), 16, 64) if err != nil { - fmt.Println("Error:%s", err) + return 0, fmt.Errorf("Error:%s", err) } return num, nil From d86f39c76623ab0dc08867c5da575eb11b6505d2 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Mon, 20 May 2024 23:00:26 +0200 Subject: [PATCH 20/26] rename respect of rules --- clientcontroller/evm_consumer.go | 40 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index ed6304ac..0ba85d4c 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -87,7 +87,7 @@ func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.Pu func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { - lastnumber, err := ec.GetLatestFinalizedNumber() + lastNumber, err := ec.GetLatestFinalizedNumber() if err != nil { return nil, fmt.Errorf("can't get latest finalized block:%s", err) @@ -98,11 +98,11 @@ func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*ty Hash string } - var Batch []rpc.BatchElem + var batchArray []rpc.BatchElem - InitBatch(Batch, lastnumber, count, "descent") + initBatch(batchArray, lastNumber, count, "descent") - err = ec.evmClient.BatchCall(Batch) + err = ec.evmClient.BatchCall(batchArray) if err != nil { return nil, fmt.Errorf("can't get latest block:%s", err) @@ -110,17 +110,17 @@ func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*ty } var blocks []*types.BlockInfo - for _, batch := range Batch { + for _, batch := range batchArray { nb := batch.Result.(*Block) num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) if err != nil { fmt.Println("Error:", err) } - ibatch := &types.BlockInfo{ + block := &types.BlockInfo{ Height: num, Hash: []byte(nb.Hash), } - blocks = append(blocks, ibatch) + blocks = append(blocks, block) } return blocks, nil } @@ -142,11 +142,11 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 startnumber := new(big.Int).SetUint64(startHeight) - var Batch []rpc.BatchElem + var batchArray []rpc.BatchElem - InitBatch(Batch, startnumber, count, "ascent") + initBatch(batchArray, startnumber, count, "ascent") - err := ec.evmClient.BatchCall(Batch) + err := ec.evmClient.BatchCall(batchArray) if err != nil { return nil, fmt.Errorf("can't get blocks") @@ -155,18 +155,18 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 var blocks []*types.BlockInfo - for _, batch := range Batch { + for _, batch := range batchArray { nb := batch.Result.(*Block) num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) if err != nil { return nil, fmt.Errorf("error:%s", err) } - ibatch := &types.BlockInfo{ + block := &types.BlockInfo{ Height: num, Hash: []byte(nb.Hash), } - blocks = append(blocks, ibatch) + blocks = append(blocks, block) } return blocks, nil } @@ -209,13 +209,13 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { - lastnumber, err := ec.GetLatestFinalizedNumber() + lastNumber, err := ec.GetLatestFinalizedNumber() if err != nil { return false, fmt.Errorf("can't get latest finalized block:%s", err) } number := new(big.Int).SetUint64(height) var finalized bool = false - if number.Cmp(lastnumber) <= 0 { + if number.Cmp(lastNumber) <= 0 { finalized = true } @@ -290,14 +290,14 @@ func (ec *EVMConsumerController) GetLatestFinalizedNumber() (*big.Int, error) { return nil, fmt.Errorf("failed to instantiate L2OutputOracle contract:%s ", err) } - lastnumber, err := output.LatestBlockNumber(nil) + lastNumber, err := output.LatestBlockNumber(nil) if err != nil { return nil, fmt.Errorf("failed to get latest finalize block number:%s ", err) } - return lastnumber, err + return lastNumber, err } -func InitBatch(Batch []rpc.BatchElem, number *big.Int, count uint64, order string) { +func initBatch(batchArray []rpc.BatchElem, number *big.Int, count uint64, order string) { type Block struct { Number string @@ -307,12 +307,12 @@ func InitBatch(Batch []rpc.BatchElem, number *big.Int, count uint64, order strin for i := 0; i < int(count); i++ { hexStr := Transform(number) - ibatch := rpc.BatchElem{ + batch := rpc.BatchElem{ Method: "eth_getBlockByNumber", Args: []interface{}{hexStr, true}, Result: new(Block), } - Batch = append(Batch, ibatch) + batchArray = append(batchArray, batch) if order == "ascent" { number.Add(number, big.NewInt(1)) } else if order == "descent" { From c12ab96152e5c945b05954eafcdcc896a3505ee3 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Wed, 22 May 2024 21:56:42 +0200 Subject: [PATCH 21/26] feat : evm_consumer optimization --- clientcontroller/evm_consumer.go | 187 ++++++++----------------------- 1 file changed, 47 insertions(+), 140 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 0ba85d4c..cef67528 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -1,20 +1,17 @@ package clientcontroller import ( + "context" "fmt" "math/big" - "strconv" - "strings" finalitytypes "github.com/babylonchain/babylon/x/finality/types" fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" "github.com/babylonchain/finality-provider/types" + "github.com/btcsuite/btcd/btcec/v2" "github.com/ethereum-optimism/optimism/op-bindings/bindings" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" - - "github.com/btcsuite/btcd/btcec/v2" "go.uber.org/zap" ) @@ -25,9 +22,10 @@ import ( var _ ConsumerController = &EVMConsumerController{} type EVMConsumerController struct { - evmClient *rpc.Client - cfg *fpcfg.EVMConfig - logger *zap.Logger + l1Client *ethclient.Client + l2Client *ethclient.Client + cfg *fpcfg.EVMConfig + logger *zap.Logger } func NewEVMConsumerController( @@ -37,12 +35,17 @@ func NewEVMConsumerController( if err := evmCfg.Validate(); err != nil { return nil, fmt.Errorf("invalid config for EVM RPC client: %w", err) } - ec, err := rpc.Dial(evmCfg.RPCL2Addr) + l1Client, err := ethclient.Dial(evmCfg.RPCL1Addr) + if err != nil { + return nil, fmt.Errorf("failed to connect to the L1 RPC server %s: %w", evmCfg.RPCL1Addr, err) + } + l2Client, err := ethclient.Dial(evmCfg.RPCL2Addr) if err != nil { - return nil, fmt.Errorf("failed to connect to the EVM RPC server %s: %w", evmCfg.RPCL2Addr, err) + return nil, fmt.Errorf("failed to connect to the L2 RPC server %s: %w", evmCfg.RPCL2Addr, err) } return &EVMConsumerController{ - ec, + l1Client, + l2Client, evmCfg, logger, }, nil @@ -87,41 +90,20 @@ func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.Pu func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { - lastNumber, err := ec.GetLatestFinalizedNumber() - if err != nil { - return nil, fmt.Errorf("can't get latest finalized block:%s", err) - - } - - type Block struct { - Number string - Hash string - } - - var batchArray []rpc.BatchElem - - initBatch(batchArray, lastNumber, count, "descent") - - err = ec.evmClient.BatchCall(batchArray) + var blocks []*types.BlockInfo - if err != nil { - return nil, fmt.Errorf("can't get latest block:%s", err) + /*will be implemented in next PR, wait for "refactor: QueryLatestFinalizedBlocks(count uint64) -> QueryLatestFinalizedBlock() #347" - } - var blocks []*types.BlockInfo - for _, batch := range batchArray { - nb := batch.Result.(*Block) - num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) + lastNumber, err := ec.GetLatestFinalizedNumber() if err != nil { - fmt.Println("Error:", err) + return false, fmt.Errorf("can't get latest finalized block:%s", err) } - block := &types.BlockInfo{ - Height: num, - Hash: []byte(nb.Hash), - } - blocks = append(blocks, block) - } + + block,err := ec.QueryBlock(lastNumber) + return blocks, nil + + */ return blocks, nil } @@ -135,39 +117,19 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 count = limit } - type Block struct { - Number string - Hash string - } - - startnumber := new(big.Int).SetUint64(startHeight) - - var batchArray []rpc.BatchElem - - initBatch(batchArray, startnumber, count, "ascent") - - err := ec.evmClient.BatchCall(batchArray) - - if err != nil { - return nil, fmt.Errorf("can't get blocks") - - } - var blocks []*types.BlockInfo - for _, batch := range batchArray { - nb := batch.Result.(*Block) - num, err := strconv.ParseUint(strings.TrimPrefix(nb.Number, "0x"), 16, 64) - if err != nil { - return nil, fmt.Errorf("error:%s", err) - } + for i := 0; i < int(count); i++ { - block := &types.BlockInfo{ - Height: num, - Hash: []byte(nb.Hash), + block, err := ec.QueryBlock(startHeight) + if err != nil { + return nil, fmt.Errorf("failed to get start block:%s", err) } blocks = append(blocks, block) + startHeight++ + } + return blocks, nil } @@ -181,27 +143,14 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er number := new(big.Int).SetUint64(height) - hexStr := Transform(number) - - type Block struct { - Number string - Hash string - } - - var block Block - err := ec.evmClient.Call(&block, "eth_getBlockByNumber", hexStr, true) + header, err := ec.l2Client.HeaderByNumber(context.Background(), number) if err != nil { - return nil, fmt.Errorf("can't get block by number:%s", err) - } - - num, err := strconv.ParseUint(strings.TrimPrefix(block.Number, "0x"), 16, 64) - if err != nil { - return nil, fmt.Errorf("error:%s", err) + return nil, fmt.Errorf("failed to get latest block:%s", err) } blockinfo := &types.BlockInfo{ - Height: num, - Hash: []byte(block.Hash), + Height: header.Number.Uint64(), + Hash: header.Hash().Bytes(), } return blockinfo, nil @@ -213,9 +162,10 @@ func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, err if err != nil { return false, fmt.Errorf("can't get latest finalized block:%s", err) } - number := new(big.Int).SetUint64(height) + var finalized bool = false - if number.Cmp(lastNumber) <= 0 { + + if height <= lastNumber { finalized = true } @@ -247,76 +197,33 @@ func (ec *EVMConsumerController) QueryActivatedHeight() (uint64, error) { func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { - type Block struct { - Number string - } - - var block Block - err := ec.evmClient.Call(&block, "eth_getBlockByNumber", "latest", true) + header, err := ec.l2Client.HeaderByNumber(context.Background(), nil) if err != nil { return 0, fmt.Errorf("failed to get latest block:%s", err) } - num, err := strconv.ParseUint(strings.TrimPrefix(block.Number, "0x"), 16, 64) - if err != nil { - return 0, fmt.Errorf("Error:%s", err) - } - - return num, nil + return header.Number.Uint64(), nil } func (ec *EVMConsumerController) Close() error { - ec.evmClient.Close() - return nil -} -func Transform(number *big.Int) string { + ec.l2Client.Close() + ec.l2Client.Close() - hexStr := fmt.Sprintf("%x", number) - if len(hexStr) >= 2 && hexStr[:2] != "0x" { - hexStr = "0x" + hexStr - } - return hexStr + return nil } -func (ec *EVMConsumerController) GetLatestFinalizedNumber() (*big.Int, error) { +func (ec *EVMConsumerController) GetLatestFinalizedNumber() (uint64, error) { - conn, err := ethclient.Dial(ec.cfg.RPCL1Addr) - if err != nil { - return nil, fmt.Errorf("failed to connect to the Ethereum client:%s", err) - } - output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleContractAddress), conn) + output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleContractAddress), ec.l1Client) if err != nil { - return nil, fmt.Errorf("failed to instantiate L2OutputOracle contract:%s ", err) + return 0, fmt.Errorf("failed to instantiate L2OutputOracle contract:%s ", err) } lastNumber, err := output.LatestBlockNumber(nil) if err != nil { - return nil, fmt.Errorf("failed to get latest finalize block number:%s ", err) + return 0, fmt.Errorf("failed to get latest finalize block number:%s ", err) } - return lastNumber, err -} -func initBatch(batchArray []rpc.BatchElem, number *big.Int, count uint64, order string) { - - type Block struct { - Number string - Hash string - } - - for i := 0; i < int(count); i++ { - - hexStr := Transform(number) - batch := rpc.BatchElem{ - Method: "eth_getBlockByNumber", - Args: []interface{}{hexStr, true}, - Result: new(Block), - } - batchArray = append(batchArray, batch) - if order == "ascent" { - number.Add(number, big.NewInt(1)) - } else if order == "descent" { - number.Sub(number, big.NewInt(1)) - } - } + return lastNumber.Uint64(), err } From 43b1734b7ca8fb863624906eff9fa22118667ae7 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Wed, 22 May 2024 22:11:08 +0200 Subject: [PATCH 22/26] modify : rename queryLatestFinalizedNumber --- clientcontroller/evm_consumer.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index cef67528..474c4eaa 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -95,7 +95,7 @@ func (ec *EVMConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*ty /*will be implemented in next PR, wait for "refactor: QueryLatestFinalizedBlocks(count uint64) -> QueryLatestFinalizedBlock() #347" - lastNumber, err := ec.GetLatestFinalizedNumber() + lastNumber, err := ec.queryLatestFinalizedNumber() if err != nil { return false, fmt.Errorf("can't get latest finalized block:%s", err) } @@ -158,7 +158,7 @@ func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, er func (ec *EVMConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { - lastNumber, err := ec.GetLatestFinalizedNumber() + lastNumber, err := ec.queryLatestFinalizedNumber() if err != nil { return false, fmt.Errorf("can't get latest finalized block:%s", err) } @@ -213,7 +213,7 @@ func (ec *EVMConsumerController) Close() error { return nil } -func (ec *EVMConsumerController) GetLatestFinalizedNumber() (uint64, error) { +func (ec *EVMConsumerController) queryLatestFinalizedNumber() (uint64, error) { output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleContractAddress), ec.l1Client) if err != nil { From 4329808d1499c8c76762c22874d80cebd5420c3b Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Wed, 22 May 2024 23:21:44 +0200 Subject: [PATCH 23/26] modify : duplicate l2Client mistake --- clientcontroller/evm_consumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index 474c4eaa..58b981f4 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -207,7 +207,7 @@ func (ec *EVMConsumerController) QueryLatestBlockHeight() (uint64, error) { func (ec *EVMConsumerController) Close() error { - ec.l2Client.Close() + ec.l1Client.Close() ec.l2Client.Close() return nil From a61277308de339eef7fb30f7daaf4026815c50d1 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Fri, 24 May 2024 15:40:58 +0200 Subject: [PATCH 24/26] implement : QueryLatestFinalizedBlock() --- clientcontroller/evm_consumer.go | 23 ++--- go.mod | 2 +- go.sum | 1 + testutil/mocks/clientcontroller.go | 142 ----------------------------- 4 files changed, 14 insertions(+), 154 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index c79e649d..c1af826c 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -5,7 +5,6 @@ import ( "fmt" "math/big" - finalitytypes "github.com/babylonchain/babylon/x/finality/types" fpcfg "github.com/babylonchain/finality-provider/finality-provider/config" "github.com/babylonchain/finality-provider/types" "github.com/btcsuite/btcd/btcec/v2" @@ -89,10 +88,18 @@ func (ec *EVMConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.Pu } func (ec *EVMConsumerController) QueryLatestFinalizedBlock() (*types.BlockInfo, error) { - return &types.BlockInfo{ - Height: 0, - Hash: nil, - }, nil + + lastNumber, err := ec.queryLatestFinalizedNumber() + if err != nil { + return nil, fmt.Errorf("can't get latest finalized block number:%s", err) + } + + block, err := ec.QueryBlock(lastNumber) + if err != nil { + return nil, fmt.Errorf("can't get latest finalized block:%s", err) + } + + return block, nil } func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { @@ -121,12 +128,6 @@ func (ec *EVMConsumerController) QueryBlocks(startHeight, endHeight, limit uint6 return blocks, nil } -func (ec *EVMConsumerController) queryLatestBlocks(startKey []byte, count uint64, status finalitytypes.QueriedBlockStatus, reverse bool) ([]*types.BlockInfo, error) { - var blocks []*types.BlockInfo - // Can be deleted for never using - return blocks, nil -} - func (ec *EVMConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { number := new(big.Int).SetUint64(height) diff --git a/go.mod b/go.mod index ed2902a8..f9aa8b07 100644 --- a/go.mod +++ b/go.mod @@ -227,7 +227,7 @@ require ( github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect - github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/soheilhy/cmux v0.1.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect diff --git a/go.sum b/go.sum index 83b9e485..cfad2d45 100644 --- a/go.sum +++ b/go.sum @@ -567,6 +567,7 @@ github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ4 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= diff --git a/testutil/mocks/clientcontroller.go b/testutil/mocks/clientcontroller.go index c46e35f9..a14aa958 100644 --- a/testutil/mocks/clientcontroller.go +++ b/testutil/mocks/clientcontroller.go @@ -238,148 +238,6 @@ func (mr *MockConsumerControllerMockRecorder) QueryLatestFinalizedBlock() *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestFinalizedBlock)) } -// MockConsumerController is a mock of ConsumerController interface. -type MockConsumerController struct { - ctrl *gomock.Controller - recorder *MockConsumerControllerMockRecorder -} - -// MockConsumerControllerMockRecorder is the mock recorder for MockConsumerController. -type MockConsumerControllerMockRecorder struct { - mock *MockConsumerController -} - -// NewMockConsumerController creates a new mock instance. -func NewMockConsumerController(ctrl *gomock.Controller) *MockConsumerController { - mock := &MockConsumerController{ctrl: ctrl} - mock.recorder = &MockConsumerControllerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockConsumerController) EXPECT() *MockConsumerControllerMockRecorder { - return m.recorder -} - -// Close mocks base method. -func (m *MockConsumerController) Close() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Close") - ret0, _ := ret[0].(error) - return ret0 -} - -// Close indicates an expected call of Close. -func (mr *MockConsumerControllerMockRecorder) Close() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockConsumerController)(nil).Close)) -} - -// QueryActivatedHeight mocks base method. -func (m *MockConsumerController) QueryActivatedHeight() (uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryActivatedHeight") - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryActivatedHeight indicates an expected call of QueryActivatedHeight. -func (mr *MockConsumerControllerMockRecorder) QueryActivatedHeight() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryActivatedHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryActivatedHeight)) -} - -// QueryBlock mocks base method. -func (m *MockConsumerController) QueryBlock(height uint64) (*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryBlock", height) - ret0, _ := ret[0].(*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryBlock indicates an expected call of QueryBlock. -func (mr *MockConsumerControllerMockRecorder) QueryBlock(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlock", reflect.TypeOf((*MockConsumerController)(nil).QueryBlock), height) -} - -// QueryBlocks mocks base method. -func (m *MockConsumerController) QueryBlocks(startHeight, endHeight, limit uint64) ([]*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryBlocks", startHeight, endHeight, limit) - ret0, _ := ret[0].([]*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryBlocks indicates an expected call of QueryBlocks. -func (mr *MockConsumerControllerMockRecorder) QueryBlocks(startHeight, endHeight, limit interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryBlocks), startHeight, endHeight, limit) -} - -// QueryFinalityProviderVotingPower mocks base method. -func (m *MockConsumerController) QueryFinalityProviderVotingPower(fpPk *btcec.PublicKey, blockHeight uint64) (uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryFinalityProviderVotingPower", fpPk, blockHeight) - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryFinalityProviderVotingPower indicates an expected call of QueryFinalityProviderVotingPower. -func (mr *MockConsumerControllerMockRecorder) QueryFinalityProviderVotingPower(fpPk, blockHeight interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryFinalityProviderVotingPower", reflect.TypeOf((*MockConsumerController)(nil).QueryFinalityProviderVotingPower), fpPk, blockHeight) -} - -// QueryIsBlockFinalized mocks base method. -func (m *MockConsumerController) QueryIsBlockFinalized(height uint64) (bool, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryIsBlockFinalized", height) - ret0, _ := ret[0].(bool) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryIsBlockFinalized indicates an expected call of QueryIsBlockFinalized. -func (mr *MockConsumerControllerMockRecorder) QueryIsBlockFinalized(height interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryIsBlockFinalized", reflect.TypeOf((*MockConsumerController)(nil).QueryIsBlockFinalized), height) -} - -// QueryLatestBlockHeight mocks base method. -func (m *MockConsumerController) QueryLatestBlockHeight() (uint64, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryLatestBlockHeight") - ret0, _ := ret[0].(uint64) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryLatestBlockHeight indicates an expected call of QueryLatestBlockHeight. -func (mr *MockConsumerControllerMockRecorder) QueryLatestBlockHeight() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestBlockHeight", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestBlockHeight)) -} - -// QueryLatestFinalizedBlocks mocks base method. -func (m *MockConsumerController) QueryLatestFinalizedBlocks(count uint64) ([]*types.BlockInfo, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "QueryLatestFinalizedBlocks", count) - ret0, _ := ret[0].([]*types.BlockInfo) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// QueryLatestFinalizedBlocks indicates an expected call of QueryLatestFinalizedBlocks. -func (mr *MockConsumerControllerMockRecorder) QueryLatestFinalizedBlocks(count interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLatestFinalizedBlocks", reflect.TypeOf((*MockConsumerController)(nil).QueryLatestFinalizedBlocks), count) -} - // SubmitBatchFinalitySigs mocks base method. func (m *MockConsumerController) SubmitBatchFinalitySigs(fpPk *btcec.PublicKey, blocks []*types.BlockInfo, sigs []*btcec.ModNScalar) (*types.TxResponse, error) { m.ctrl.T.Helper() From bb0007e76e202984be3a0ee5d58284e0dd608e27 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Fri, 24 May 2024 19:51:25 +0200 Subject: [PATCH 25/26] correction : evm.cfg --- clientcontroller/evm_consumer.go | 2 +- finality-provider/config/evm.go | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/clientcontroller/evm_consumer.go b/clientcontroller/evm_consumer.go index c1af826c..e8d8f858 100644 --- a/clientcontroller/evm_consumer.go +++ b/clientcontroller/evm_consumer.go @@ -204,7 +204,7 @@ func (ec *EVMConsumerController) Close() error { func (ec *EVMConsumerController) queryLatestFinalizedNumber() (uint64, error) { - output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleContractAddress), ec.l1Client) + output, err := bindings.NewL2OutputOracle(common.HexToAddress(ec.cfg.L2OutputOracleAddr), ec.l1Client) if err != nil { return 0, fmt.Errorf("failed to instantiate L2OutputOracle contract:%s ", err) } diff --git a/finality-provider/config/evm.go b/finality-provider/config/evm.go index 47017a5d..2db91716 100644 --- a/finality-provider/config/evm.go +++ b/finality-provider/config/evm.go @@ -10,10 +10,10 @@ const ( ) type EVMConfig struct { - RPCL1Addr string `long:"rpc-address" description:"address of the L2 RPC server to connect to"` - RPCL2Addr string `long:"rpc-address" description:"address of the L1 RPC server to connect to"` - L2OutputOracleContractAddress string `long:"sol-address" description:"address of the L2output smart contract"` - BitcoinStackingContractAddress string `long:"sol-address" description:"address of the Bitcoinstaking smart contract"` + RPCL1Addr string `long:"rpcl1-address" description:"address of the L1 RPC server to connect to"` + RPCL2Addr string `long:"rpcl2-address" description:"address of the L2 RPC server to connect to"` + L2OutputOracleAddr string `long:"l2outputoracle-address" description:"address of the L2OutputOracle smart contract"` + BSAddr string `long:"bitcoinstacking-address" description:"address of the BitcoinStaking smart contract"` } func DefaultEVMConfig() EVMConfig { @@ -23,6 +23,9 @@ func DefaultEVMConfig() EVMConfig { } func (cfg *EVMConfig) Validate() error { + if _, err := url.Parse(cfg.RPCL1Addr); err != nil { + return fmt.Errorf("rpcl1-addr is not correctly formatted: %w", err) + } if _, err := url.Parse(cfg.RPCL2Addr); err != nil { return fmt.Errorf("rpcl2-addr is not correctly formatted: %w", err) } From f3cf85b2ee68af8adc8b557e596ab2c5a567aee9 Mon Sep 17 00:00:00 2001 From: XiangEnze Date: Fri, 24 May 2024 20:04:38 +0200 Subject: [PATCH 26/26] correction : makefile merge problerm --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index a73c657c..e0acf7a5 100644 --- a/Makefile +++ b/Makefile @@ -56,7 +56,6 @@ build-docker: .PHONY: test test: - make mock-gen go test ./... test-e2e: