diff --git a/CHANGELOG.md b/CHANGELOG.md index d9854273..ceb87f4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,9 +39,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) ### Improvements +* [#80](https://github.com/babylonlabs-io/vigilante/pull/80) bump babylon to use +uint32 in BTC block heights and BLS valset response * [#79](https://github.com/babylonlabs-io/vigilante/pull/79) handle no change output when building tx - * [#77](https://github.com/babylonlabs-io/vigilante/pull/77) add arm64 static build - -* [#76](https://github.com/babylonlabs-io/vigilante/pull/76) add goreleaser +* [#76](https://github.com/babylonlabs-io/vigilante/pull/76) add goreleaser setup and move out changelog reminder diff --git a/btcclient/interface.go b/btcclient/interface.go index 72fe738f..ed913c30 100644 --- a/btcclient/interface.go +++ b/btcclient/interface.go @@ -15,10 +15,10 @@ import ( type BTCClient interface { Stop() WaitForShutdown() - GetBestBlock() (uint64, error) + GetBestBlock() (uint32, error) GetBlockByHash(blockHash *chainhash.Hash) (*types.IndexedBlock, *wire.MsgBlock, error) - FindTailBlocksByHeight(height uint64) ([]*types.IndexedBlock, error) - GetBlockByHeight(height uint64) (*types.IndexedBlock, *wire.MsgBlock, error) + FindTailBlocksByHeight(height uint32) ([]*types.IndexedBlock, error) + GetBlockByHeight(height uint32) (*types.IndexedBlock, *wire.MsgBlock, error) GetTxOut(txHash *chainhash.Hash, index uint32, mempool bool) (*btcjson.GetTxOutResult, error) SendRawTransaction(tx *wire.MsgTx, allowHighFees bool) (*chainhash.Hash, error) GetTransaction(txHash *chainhash.Hash) (*btcjson.GetTransactionResult, error) diff --git a/btcclient/query.go b/btcclient/query.go index ad5057f4..c7a4225d 100644 --- a/btcclient/query.go +++ b/btcclient/query.go @@ -13,13 +13,13 @@ import ( ) // GetBestBlock returns the height of the best block -func (c *Client) GetBestBlock() (uint64, error) { +func (c *Client) GetBestBlock() (uint32, error) { height, err := c.getBlockCountWithRetry() if err != nil { return 0, err } - return uint64(height), nil + return uint32(height), nil } func (c *Client) GetBlockByHash(blockHash *chainhash.Hash) (*types.IndexedBlock, *wire.MsgBlock, error) { @@ -38,7 +38,7 @@ func (c *Client) GetBlockByHash(blockHash *chainhash.Hash) (*types.IndexedBlock, } // GetBlockByHeight returns a block with the given height -func (c *Client) GetBlockByHeight(height uint64) (*types.IndexedBlock, *wire.MsgBlock, error) { +func (c *Client) GetBlockByHeight(height uint32) (*types.IndexedBlock, *wire.MsgBlock, error) { blockHash, err := c.getBlockHashWithRetry(height) if err != nil { return nil, nil, fmt.Errorf("failed to get block by height %d: %w", height, err) @@ -78,7 +78,7 @@ func (c *Client) getBestBlockHashWithRetry() (*chainhash.Hash, error) { return blockHash, nil } -func (c *Client) getBlockHashWithRetry(height uint64) (*chainhash.Hash, error) { +func (c *Client) getBlockHashWithRetry(height uint32) (*chainhash.Hash, error) { var ( blockHash *chainhash.Hash err error @@ -96,7 +96,7 @@ func (c *Client) getBlockHashWithRetry(height uint64) (*chainhash.Hash, error) { retry.Attempts(c.maxRetryTimes), ); err != nil { c.logger.Debug( - "failed to query the block hash", zap.Uint64("height", height), zap.Error(err)) + "failed to query the block hash", zap.Uint32("height", height), zap.Error(err)) } return blockHash, nil @@ -152,8 +152,8 @@ func (c *Client) getBlockVerboseWithRetry(hash *chainhash.Hash) (*btcjson.GetBlo // getChainBlocks returns a chain of indexed blocks from the block at baseHeight to the tipBlock // note: the caller needs to ensure that tipBlock is on the blockchain -func (c *Client) getChainBlocks(baseHeight uint64, tipBlock *types.IndexedBlock) ([]*types.IndexedBlock, error) { - tipHeight := uint64(tipBlock.Height) +func (c *Client) getChainBlocks(baseHeight uint32, tipBlock *types.IndexedBlock) ([]*types.IndexedBlock, error) { + tipHeight := uint32(tipBlock.Height) if tipHeight < baseHeight { return nil, fmt.Errorf("the tip block height %v is less than the base height %v", tipHeight, baseHeight) } @@ -195,13 +195,13 @@ func (c *Client) getBestIndexedBlock() (*types.IndexedBlock, error) { } // FindTailBlocksByHeight returns the chain of blocks from the block at baseHeight to the tip -func (c *Client) FindTailBlocksByHeight(baseHeight uint64) ([]*types.IndexedBlock, error) { +func (c *Client) FindTailBlocksByHeight(baseHeight uint32) ([]*types.IndexedBlock, error) { tipIb, err := c.getBestIndexedBlock() if err != nil { return nil, err } - if baseHeight > uint64(tipIb.Height) { + if baseHeight > uint32(tipIb.Height) { return nil, fmt.Errorf("invalid base height %d, should not be higher than tip block %d", baseHeight, tipIb.Height) } diff --git a/btcstaking-tracker/btcslasher/bootstrapping_test.go b/btcstaking-tracker/btcslasher/bootstrapping_test.go index 153cf27f..5582aa70 100644 --- a/btcstaking-tracker/btcslasher/bootstrapping_test.go +++ b/btcstaking-tracker/btcslasher/bootstrapping_test.go @@ -120,6 +120,7 @@ func FuzzSlasher_Bootstrapping(f *testing.F) { covPks, bsParams.Params.CovenantQuorum, slashingPkScript, + 1000, 100, 1100, delAmount, @@ -150,6 +151,7 @@ func FuzzSlasher_Bootstrapping(f *testing.F) { covPks, bsParams.Params.CovenantQuorum, slashingPkScript, + 1000, 100, 1100, delAmount, diff --git a/btcstaking-tracker/btcslasher/slasher.go b/btcstaking-tracker/btcslasher/slasher.go index 095e15bc..39e4afa2 100644 --- a/btcstaking-tracker/btcslasher/slasher.go +++ b/btcstaking-tracker/btcslasher/slasher.go @@ -3,11 +3,12 @@ package btcslasher import ( "context" "fmt" + "sync" + "time" + "github.com/babylonlabs-io/vigilante/types" "github.com/decred/dcrd/dcrec/secp256k1/v4" "golang.org/x/sync/semaphore" - "sync" - "time" bbn "github.com/babylonlabs-io/babylon/types" bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" @@ -35,7 +36,7 @@ type BTCSlasher struct { // parameters netParams *chaincfg.Params - btcFinalizationTimeout uint64 + btcFinalizationTimeout uint32 retrySleepTime time.Duration maxRetrySleepTime time.Duration maxRetryTimes uint diff --git a/btcstaking-tracker/btcslasher/slasher_test.go b/btcstaking-tracker/btcslasher/slasher_test.go index 5727fd44..d9f3dca8 100644 --- a/btcstaking-tracker/btcslasher/slasher_test.go +++ b/btcstaking-tracker/btcslasher/slasher_test.go @@ -115,6 +115,7 @@ func FuzzSlasher(f *testing.F) { covenantBtcPks, bsParams.Params.CovenantQuorum, slashingPkScript, + 999, 100, 1099, delAmount, @@ -142,6 +143,7 @@ func FuzzSlasher(f *testing.F) { covenantBtcPks, bsParams.Params.CovenantQuorum, slashingPkScript, + 1000, 100, 1100, delAmount, @@ -169,6 +171,7 @@ func FuzzSlasher(f *testing.F) { covenantBtcPks, bsParams.Params.CovenantQuorum, slashingPkScript, + 1000, 100, 1100, delAmount, diff --git a/btcstaking-tracker/btcslasher/slasher_utils.go b/btcstaking-tracker/btcslasher/slasher_utils.go index a192bef7..b4a5959b 100644 --- a/btcstaking-tracker/btcslasher/slasher_utils.go +++ b/btcstaking-tracker/btcslasher/slasher_utils.go @@ -262,6 +262,7 @@ func BuildUnbondingSlashingTxWithWitness( 0, delSlashingSig, covAdaptorSigs, + bsParams.CovenantQuorum, slashingSpendInfo, ) if err != nil { @@ -364,6 +365,7 @@ func BuildSlashingTxWithWitness( d.StakingOutputIdx, delSigSlash, covAdaptorSigs, + bsParams.CovenantQuorum, slashingSpendInfo, ) if err != nil { diff --git a/btcstaking-tracker/stakingeventwatcher/expected_babylon_client.go b/btcstaking-tracker/stakingeventwatcher/expected_babylon_client.go index dfdfaa5b..52537ce0 100644 --- a/btcstaking-tracker/stakingeventwatcher/expected_babylon_client.go +++ b/btcstaking-tracker/stakingeventwatcher/expected_babylon_client.go @@ -3,6 +3,7 @@ package stakingeventwatcher import ( "context" "fmt" + btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" "cosmossdk.io/errors" @@ -18,7 +19,7 @@ import ( type Delegation struct { StakingTx *wire.MsgTx StakingOutputIdx uint32 - DelegationStartHeight uint64 + DelegationStartHeight uint32 UnbondingOutput *wire.TxOut HasProof bool } diff --git a/btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go b/btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go index a95a3d0d..331ff720 100644 --- a/btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go +++ b/btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go @@ -5,13 +5,14 @@ import ( "context" "errors" "fmt" + "sync" + "sync/atomic" + "time" + btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" btcstakingtypes "github.com/babylonlabs-io/babylon/x/btcstaking/types" "github.com/babylonlabs-io/vigilante/btcclient" "github.com/babylonlabs-io/vigilante/types" - "sync" - "sync/atomic" - "time" "github.com/avast/retry-go/v4" "github.com/babylonlabs-io/vigilante/config" @@ -50,7 +51,7 @@ type newDelegation struct { stakingTxHash chainhash.Hash stakingTx *wire.MsgTx stakingOutputIdx uint32 - delegationStartHeight uint64 + delegationStartHeight uint32 unbondingOutput *wire.TxOut } diff --git a/btcstaking-tracker/stakingeventwatcher/tracked_delegations.go b/btcstaking-tracker/stakingeventwatcher/tracked_delegations.go index d11e050e..d5ec235c 100644 --- a/btcstaking-tracker/stakingeventwatcher/tracked_delegations.go +++ b/btcstaking-tracker/stakingeventwatcher/tracked_delegations.go @@ -12,7 +12,7 @@ type TrackedDelegation struct { StakingTx *wire.MsgTx StakingOutputIdx uint32 UnbondingOutput *wire.TxOut - DelegationStartHeight uint64 + DelegationStartHeight uint32 } type TrackedDelegations struct { @@ -61,7 +61,7 @@ func (td *TrackedDelegations) AddDelegation( StakingTx *wire.MsgTx, StakingOutputIdx uint32, UnbondingOutput *wire.TxOut, - delegationStartHeight uint64, + delegationStartHeight uint32, shouldUpdate bool, ) (*TrackedDelegation, error) { delegation := &TrackedDelegation{ diff --git a/e2etest/reporter_e2e_test.go b/e2etest/reporter_e2e_test.go index 37b87bd6..accb120b 100644 --- a/e2etest/reporter_e2e_test.go +++ b/e2etest/reporter_e2e_test.go @@ -4,12 +4,13 @@ package e2etest import ( - "github.com/babylonlabs-io/vigilante/btcclient" - "github.com/babylonlabs-io/vigilante/netparams" "sync" "testing" "time" + "github.com/babylonlabs-io/vigilante/btcclient" + "github.com/babylonlabs-io/vigilante/netparams" + "github.com/babylonlabs-io/vigilante/metrics" "github.com/babylonlabs-io/vigilante/reporter" "github.com/stretchr/testify/require" @@ -27,7 +28,7 @@ func (tm *TestManager) BabylonBTCChainMatchesBtc(t *testing.T) bool { bbnBtcLcTip, err := tm.BabylonClient.BTCHeaderChainTip() require.NoError(t, err) - return uint64(tipHeight) == bbnBtcLcTip.Header.Height && tipHash.String() == bbnBtcLcTip.Header.HashHex + return uint32(tipHeight) == bbnBtcLcTip.Header.Height && tipHash.String() == bbnBtcLcTip.Header.HashHex } func (tm *TestManager) GenerateAndSubmitBlockNBlockStartingFromDepth(t *testing.T, N int, depth uint32) { diff --git a/e2etest/test_manager_btcstaking.go b/e2etest/test_manager_btcstaking.go index aeb4c717..818d4e2f 100644 --- a/e2etest/test_manager_btcstaking.go +++ b/e2etest/test_manager_btcstaking.go @@ -3,9 +3,13 @@ package e2etest import ( "bytes" "context" - sdkmath "cosmossdk.io/math" "encoding/hex" "fmt" + "math/rand" + "testing" + "time" + + sdkmath "cosmossdk.io/math" "github.com/avast/retry-go/v4" "github.com/babylonlabs-io/babylon/btcstaking" txformat "github.com/babylonlabs-io/babylon/btctxformatter" @@ -29,9 +33,6 @@ import ( stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/relayer/v2/relayer/provider" "github.com/stretchr/testify/require" - "math/rand" - "testing" - "time" ) var ( @@ -43,7 +44,7 @@ var ( ) ) -func (tm *TestManager) getBTCUnbondingTime(t *testing.T) uint64 { +func (tm *TestManager) getBTCUnbondingTime(t *testing.T) uint32 { bsParams, err := tm.BabylonClient.BTCStakingParams() require.NoError(t, err) btccParams, err := tm.BabylonClient.BTCCheckpointParams() diff --git a/go.mod b/go.mod index 841fc831..c14a2009 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( cosmossdk.io/log v1.4.1 cosmossdk.io/math v1.3.0 github.com/avast/retry-go/v4 v4.6.0 - github.com/babylonlabs-io/babylon v0.12.0 + github.com/babylonlabs-io/babylon v0.13.0 github.com/boljen/go-bitmap v0.0.0-20151001105940-23cd2fb0ce7d github.com/btcsuite/btcd v0.24.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2 diff --git a/go.sum b/go.sum index 0774fc87..68a7e0ce 100644 --- a/go.sum +++ b/go.sum @@ -283,8 +283,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.44.312 h1:llrElfzeqG/YOLFFKjg1xNpZCFJ2xraIi3PqSuP+95k= github.com/aws/aws-sdk-go v1.44.312/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/babylonlabs-io/babylon v0.12.0 h1:s2OTcxpk0RzrkVBnVTfnPdJVYDSqnm/33YKPQqEzNCE= -github.com/babylonlabs-io/babylon v0.12.0/go.mod h1:ZOrTde9vs2xoqGTFw4xhupu2CMulnpywiuk0eh4kPOw= +github.com/babylonlabs-io/babylon v0.13.0 h1:h7cazmFmItePvZHEbLhDbsq2l7xN4e2AjDHRM7zDLkg= +github.com/babylonlabs-io/babylon v0.13.0/go.mod h1:cxRwVqVLoJ39FpyovTEHJLu1lwwrM1tE8davu7nRHwY= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= diff --git a/monitor/btcscanner/block_handler.go b/monitor/btcscanner/block_handler.go index abce39cc..4f0c569c 100644 --- a/monitor/btcscanner/block_handler.go +++ b/monitor/btcscanner/block_handler.go @@ -3,6 +3,7 @@ package btcscanner import ( "errors" "fmt" + "github.com/btcsuite/btcd/wire" "github.com/lightningnetwork/lnd/chainntnfs" ) @@ -91,7 +92,7 @@ func (bs *BtcScanner) handleNewBlock(height int32, header *wire.BlockHeader) err bs.unconfirmedBlockCache.Add(ib) // still unconfirmed - if bs.unconfirmedBlockCache.Size() <= bs.k { + if uint32(bs.unconfirmedBlockCache.Size()) <= bs.k { return nil } diff --git a/monitor/btcscanner/btc_scanner.go b/monitor/btcscanner/btc_scanner.go index e18e2396..40096ebd 100644 --- a/monitor/btcscanner/btc_scanner.go +++ b/monitor/btcscanner/btc_scanner.go @@ -2,9 +2,10 @@ package btcscanner import ( "fmt" - notifier "github.com/lightningnetwork/lnd/chainntnfs" "sync" + notifier "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/babylonlabs-io/babylon/btctxformatter" ckpttypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/btcsuite/btcd/wire" @@ -19,12 +20,12 @@ import ( var _ Scanner = (*BtcScanner)(nil) type Scanner interface { - Start(startHeight uint64) + Start(startHeight uint32) Stop() GetCheckpointsChan() chan *types.CheckpointRecord GetConfirmedBlocksChan() chan *types.IndexedBlock - GetBaseHeight() uint64 + GetBaseHeight() uint32 } type BtcScanner struct { @@ -36,9 +37,9 @@ type BtcScanner struct { btcNotifier notifier.ChainNotifier // the BTC height the scanner starts - baseHeight uint64 + baseHeight uint32 // the BTC confirmation depth - k uint64 + k uint32 confirmedTipBlock *types.IndexedBlock confirmedBlocksChan chan *types.IndexedBlock @@ -77,7 +78,7 @@ func New( logger: parentLogger.With(zap.String("module", "btcscanner")).Sugar(), btcClient: btcClient, btcNotifier: btcNotifier, - k: monitorCfg.BtcConfirmationDepth, + k: uint32(monitorCfg.BtcConfirmationDepth), ckptCache: ckptCache, unconfirmedBlockCache: unconfirmedBlockCache, confirmedBlocksChan: confirmedBlocksChan, @@ -89,7 +90,7 @@ func New( } // Start starts the scanning process from curBTCHeight to tipHeight -func (bs *BtcScanner) Start(startHeight uint64) { +func (bs *BtcScanner) Start(startHeight uint32) { if bs.started.Load() { bs.logger.Info("the BTC scanner is already started") return @@ -136,15 +137,15 @@ func (bs *BtcScanner) Start(startHeight uint64) { // Bootstrap syncs with BTC by getting the confirmed blocks and the caching the unconfirmed blocks func (bs *BtcScanner) Bootstrap() { var ( - firstUnconfirmedHeight uint64 + firstUnconfirmedHeight uint32 confirmedBlock *types.IndexedBlock err error ) if bs.confirmedTipBlock != nil { - firstUnconfirmedHeight = uint64(bs.confirmedTipBlock.Height + 1) + firstUnconfirmedHeight = uint32(bs.confirmedTipBlock.Height + 1) } else { - firstUnconfirmedHeight = bs.GetBaseHeight() + firstUnconfirmedHeight = uint32(bs.GetBaseHeight()) } bs.logger.Infof("the bootstrapping starts at %d", firstUnconfirmedHeight) @@ -250,7 +251,7 @@ func (bs *BtcScanner) matchAndPop() (*types.CheckpointRecord, error) { return &types.CheckpointRecord{ RawCheckpoint: rawCheckpoint, - FirstSeenBtcHeight: uint64(ckptSegments.Segments[0].AssocBlock.Height), + FirstSeenBtcHeight: uint32(ckptSegments.Segments[0].AssocBlock.Height), }, nil } @@ -283,13 +284,13 @@ func (bs *BtcScanner) Stop() { close(bs.quit) } -func (bs *BtcScanner) GetBaseHeight() uint64 { +func (bs *BtcScanner) GetBaseHeight() uint32 { bs.mu.Lock() defer bs.mu.Unlock() return bs.baseHeight } -func (bs *BtcScanner) SetBaseHeight(h uint64) { +func (bs *BtcScanner) SetBaseHeight(h uint32) { bs.mu.Lock() defer bs.mu.Unlock() bs.baseHeight = h @@ -306,12 +307,12 @@ func (bs *BtcScanner) SetBtcClient(c btcclient.BTCClient) { } // GetK returns the value of k - confirmation depth -func (bs *BtcScanner) GetK() uint64 { +func (bs *BtcScanner) GetK() uint32 { return bs.k } // SetK sets the value of k - confirmation depth -func (bs *BtcScanner) SetK(k uint64) { +func (bs *BtcScanner) SetK(k uint32) { bs.k = k } diff --git a/monitor/btcscanner/btc_scanner_test.go b/monitor/btcscanner/btc_scanner_test.go index 62b85f58..fb5c0653 100644 --- a/monitor/btcscanner/btc_scanner_test.go +++ b/monitor/btcscanner/btc_scanner_test.go @@ -20,19 +20,19 @@ func FuzzBootStrap(f *testing.F) { f.Fuzz(func(t *testing.T, seed int64) { t.Parallel() r := rand.New(rand.NewSource(seed)) - k := datagen.RandomIntOtherThan(r, 0, 10) + k := uint32(datagen.RandomIntOtherThan(r, 0, 10)) // Generate a random number of blocks - numBlocks := datagen.RandomIntOtherThan(r, 0, 100) + k // make sure we have at least k+1 entry + numBlocks := datagen.RandomIntOtherThan(r, 0, 100) + uint64(k) // make sure we have at least k+1 entry chainIndexedBlocks := vdatagen.GetRandomIndexedBlocks(r, numBlocks) baseHeight := chainIndexedBlocks[0].Height bestHeight := chainIndexedBlocks[len(chainIndexedBlocks)-1].Height ctl := gomock.NewController(t) defer ctl.Finish() mockBtcClient := mocks.NewMockBTCClient(ctl) - confirmedBlocks := chainIndexedBlocks[:numBlocks-k] - mockBtcClient.EXPECT().GetBestBlock().Return(uint64(bestHeight), nil) + confirmedBlocks := chainIndexedBlocks[:numBlocks-uint64(k)] + mockBtcClient.EXPECT().GetBestBlock().Return(uint32(bestHeight), nil) for i := 0; i < int(numBlocks); i++ { - mockBtcClient.EXPECT().GetBlockByHeight(gomock.Eq(uint64(chainIndexedBlocks[i].Height))). + mockBtcClient.EXPECT().GetBlockByHeight(gomock.Eq(uint32(chainIndexedBlocks[i].Height))). Return(chainIndexedBlocks[i], nil, nil).AnyTimes() } @@ -40,7 +40,7 @@ func FuzzBootStrap(f *testing.F) { require.NoError(t, err) var btcScanner btcscanner.BtcScanner btcScanner.SetBtcClient(mockBtcClient) - btcScanner.SetBaseHeight(uint64(baseHeight)) + btcScanner.SetBaseHeight(uint32(baseHeight)) btcScanner.SetK(k) btcScanner.SetConfirmedBlocksChan(make(chan *types.IndexedBlock)) btcScanner.SetUnconfirmedBlockCache(cache) diff --git a/monitor/liveness_checker.go b/monitor/liveness_checker.go index 11c511aa..658aad86 100644 --- a/monitor/liveness_checker.go +++ b/monitor/liveness_checker.go @@ -49,10 +49,10 @@ func (m *Monitor) runLivenessChecker() { // H4 - min(H1, H2) > max_live_btc_heights (if the checkpoint is not reported), return error func (m *Monitor) CheckLiveness(cr *types.CheckpointRecord) error { var ( - btcHeightEpochEnded uint64 // the BTC light client height when the epoch ends (obtained from Babylon) - btcHeightFirstSeen uint64 // the BTC height at which the unique checkpoint first appears (obtained from BTC) - btcHeightCkptReported uint64 // the tip height of BTC light client when the checkpoint is reported (obtained from Babylon) - currentBtcTipHeight uint64 // the current tip height of BTC light client (obtained from Babylon) + btcHeightEpochEnded uint32 // the BTC light client height when the epoch ends (obtained from Babylon) + btcHeightFirstSeen uint32 // the BTC height at which the unique checkpoint first appears (obtained from BTC) + btcHeightCkptReported uint32 // the tip height of BTC light client when the checkpoint is reported (obtained from Babylon) + currentBtcTipHeight uint32 // the current tip height of BTC light client (obtained from Babylon) gap int // the gap between two BTC heights err error ) diff --git a/monitor/liveness_checker_test.go b/monitor/liveness_checker_test.go index 654b1490..dd355818 100644 --- a/monitor/liveness_checker_test.go +++ b/monitor/liveness_checker_test.go @@ -1,6 +1,9 @@ package monitor_test import ( + "math/rand" + "testing" + bbndatagen "github.com/babylonlabs-io/babylon/testutil/datagen" bbntypes "github.com/babylonlabs-io/babylon/types" btclctypes "github.com/babylonlabs-io/babylon/x/btclightclient/types" @@ -11,8 +14,6 @@ import ( "github.com/babylonlabs-io/vigilante/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "math/rand" - "testing" ) func FuzzLivenessChecker(f *testing.F) { @@ -44,13 +45,13 @@ func FuzzLivenessChecker(f *testing.F) { // 1. normal case, checkpoint is reported, h1 < h2 < h3, h3 - h1 < MaxLiveBtcHeights h1 := bbndatagen.RandomIntOtherThan(r, 0, 50) h2 := bbndatagen.RandomIntOtherThan(r, 0, 50) + h1 - cr.FirstSeenBtcHeight = h2 + cr.FirstSeenBtcHeight = uint32(h2) h3 := bbndatagen.RandomIntOtherThan(r, 0, 50) + h2 mockBabylonClient.EXPECT().EndedEpochBTCHeight(gomock.Eq(cr.EpochNum())).Return( - &monitortypes.QueryEndedEpochBtcHeightResponse{BtcLightClientHeight: h1}, nil, + &monitortypes.QueryEndedEpochBtcHeightResponse{BtcLightClientHeight: uint32(h1)}, nil, ).AnyTimes() mockBabylonClient.EXPECT().ReportedCheckpointBTCHeight(gomock.Eq(cr.ID())).Return( - &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: h3}, nil, + &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint32(h3)}, nil, ) err = m.CheckLiveness(cr) require.NoError(t, err) @@ -58,7 +59,7 @@ func FuzzLivenessChecker(f *testing.F) { // 2. attack case, checkpoint is reported, h1 < h2 < h3, h3 - h1 > MaxLiveBtcHeights h3 = bbndatagen.RandomIntOtherThan(r, 0, 50) + h2 + maxGap mockBabylonClient.EXPECT().ReportedCheckpointBTCHeight(gomock.Eq(cr.ID())).Return( - &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: h3}, nil, + &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint32(h3)}, nil, ) err = m.CheckLiveness(cr) require.ErrorIs(t, err, types.ErrLivenessAttack) @@ -66,13 +67,13 @@ func FuzzLivenessChecker(f *testing.F) { // 3. normal case, checkpoint is not reported, h1 < h2 < h4, h4 - h1 < MaxLiveBtcHeights h4 := bbndatagen.RandomIntOtherThan(r, 0, 50) + h2 mockBabylonClient.EXPECT().ReportedCheckpointBTCHeight(gomock.Eq(cr.ID())).Return( - &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint64(0)}, + &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint32(0)}, monitortypes.ErrCheckpointNotReported, ) randHashBytes := bbntypes.BTCHeaderHashBytes(bbndatagen.GenRandomByteArray(r, 32)) mockBabylonClient.EXPECT().BTCHeaderChainTip().Return( &btclctypes.QueryTipResponse{ - Header: &btclctypes.BTCHeaderInfoResponse{Height: h4, HashHex: randHashBytes.MarshalHex()}}, + Header: &btclctypes.BTCHeaderInfoResponse{Height: uint32(h4), HashHex: randHashBytes.MarshalHex()}}, nil, ) err = m.CheckLiveness(cr) @@ -81,13 +82,13 @@ func FuzzLivenessChecker(f *testing.F) { // 4. attack case, checkpoint is not reported, h1 < h2 < h4, h4 - h1 > MaxLiveBtcHeights h4 = bbndatagen.RandomIntOtherThan(r, 0, 50) + h2 + maxGap mockBabylonClient.EXPECT().ReportedCheckpointBTCHeight(gomock.Eq(cr.ID())).Return( - &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint64(0)}, + &monitortypes.QueryReportedCheckpointBtcHeightResponse{BtcLightClientHeight: uint32(0)}, monitortypes.ErrCheckpointNotReported, ) randHashBytes = bbntypes.BTCHeaderHashBytes(bbndatagen.GenRandomByteArray(r, 32)) mockBabylonClient.EXPECT().BTCHeaderChainTip().Return( &btclctypes.QueryTipResponse{ - Header: &btclctypes.BTCHeaderInfoResponse{Height: h4, HashHex: randHashBytes.MarshalHex()}, + Header: &btclctypes.BTCHeaderInfoResponse{Height: uint32(h4), HashHex: randHashBytes.MarshalHex()}, }, nil, ) diff --git a/monitor/monitor.go b/monitor/monitor.go index bed196ec..d9f8656c 100644 --- a/monitor/monitor.go +++ b/monitor/monitor.go @@ -3,11 +3,12 @@ package monitor import ( "encoding/hex" "fmt" + "sort" + "sync" + "github.com/babylonlabs-io/vigilante/monitor/store" notifier "github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/kvdb" - "sort" - "sync" "github.com/btcsuite/btcd/wire" "github.com/pkg/errors" @@ -110,7 +111,7 @@ func (m *Monitor) SetLogger(logger *zap.SugaredLogger) { } // Start starts the verification core -func (m *Monitor) Start(baseHeight uint64) { +func (m *Monitor) Start(baseHeight uint32) { if m.started.Load() { m.logger.Info("the Monitor is already started") return @@ -135,14 +136,14 @@ func (m *Monitor) Start(baseHeight uint64) { } // get the height from db if it exists otherwise use the baseHeight provided from genesis - var startHeight uint64 + var startHeight uint32 dbHeight, exists, err := m.store.LatestHeight() if err != nil { panic(fmt.Errorf("error getting latest height from db %w", err)) } else if !exists { startHeight = baseHeight } else { - startHeight = dbHeight + 1 + startHeight = uint32(dbHeight) + 1 } // starting BTC scanner @@ -180,7 +181,7 @@ func (m *Monitor) Start(baseHeight uint64) { m.logger.Info("the Monitor is stopped") } -func (m *Monitor) runBTCScanner(startHeight uint64) { +func (m *Monitor) runBTCScanner(startHeight uint32) { m.BTCScanner.Start(startHeight) m.wg.Done() } diff --git a/monitor/monitor_test.go b/monitor/monitor_test.go index 3b2935d9..68f49870 100644 --- a/monitor/monitor_test.go +++ b/monitor/monitor_test.go @@ -1,6 +1,7 @@ package monitor_test import ( + "encoding/hex" "math/rand" "testing" @@ -121,7 +122,7 @@ func FuzzVerifyCheckpoint(f *testing.F) { for _, tc := range testCases { mockBabylonClient.EXPECT().BlsPublicKeyList(gomock.Eq(tc.btcCheckpoint.EpochNum), gomock.Nil()).Return( &ckpttypes.QueryBlsPublicKeyListResponse{ - ValidatorWithBlsKeys: valSet.ValSet, + ValidatorWithBlsKeys: convertToBlsPublicKeyListResponse(valSet.ValSet), }, nil).AnyTimes() err := m.UpdateEpochInfo(btcCheckpoint.EpochNum) require.NoError(t, err) @@ -135,3 +136,16 @@ func FuzzVerifyCheckpoint(f *testing.F) { } }) } + +func convertToBlsPublicKeyListResponse(valBLSKeys []*ckpttypes.ValidatorWithBlsKey) []*ckpttypes.BlsPublicKeyListResponse { + blsPublicKeyListResponse := make([]*ckpttypes.BlsPublicKeyListResponse, len(valBLSKeys)) + + for i, valBlsKey := range valBLSKeys { + blsPublicKeyListResponse[i] = &ckpttypes.BlsPublicKeyListResponse{ + ValidatorAddress: valBlsKey.ValidatorAddress, + BlsPubKeyHex: hex.EncodeToString(valBlsKey.BlsPubKey), + VotingPower: valBlsKey.VotingPower, + } + } + return blsPublicKeyListResponse +} diff --git a/monitor/query.go b/monitor/query.go index 7cd880e7..04968ca9 100644 --- a/monitor/query.go +++ b/monitor/query.go @@ -1,7 +1,9 @@ package monitor import ( + "encoding/hex" "fmt" + "github.com/avast/retry-go/v4" "github.com/babylonlabs-io/vigilante/retrywrap" @@ -23,7 +25,28 @@ func (m *Monitor) QueryInfoForNextEpoch(epoch uint64) (*types.EpochInfo, error) return nil, fmt.Errorf("failed to query BLS key set for epoch %v: %w", epoch, err) } - return types.NewEpochInfo(epoch, ckpttypes.ValidatorWithBlsKeySet{ValSet: res.ValidatorWithBlsKeys}), nil + blsKeys, err := convertFromBlsPublicKeyListResponse(res.ValidatorWithBlsKeys) + if err != nil { + return nil, fmt.Errorf("failed to convert BLS key response set for epoch %v: %w", epoch, err) + } + return types.NewEpochInfo(epoch, ckpttypes.ValidatorWithBlsKeySet{ValSet: blsKeys}), nil +} + +func convertFromBlsPublicKeyListResponse(valBLSKeys []*ckpttypes.BlsPublicKeyListResponse) ([]*ckpttypes.ValidatorWithBlsKey, error) { + blsPublicKeyListResponse := make([]*ckpttypes.ValidatorWithBlsKey, len(valBLSKeys)) + + for i, valBlsKey := range valBLSKeys { + blsKey, err := hex.DecodeString(valBlsKey.BlsPubKeyHex) + if err != nil { + return nil, err + } + blsPublicKeyListResponse[i] = &ckpttypes.ValidatorWithBlsKey{ + ValidatorAddress: valBlsKey.ValidatorAddress, + BlsPubKey: blsKey, + VotingPower: valBlsKey.VotingPower, + } + } + return blsPublicKeyListResponse, nil } // FindTipConfirmedEpoch tries to find the last confirmed epoch number from Babylon diff --git a/monitor/query_test.go b/monitor/query_test.go index 3904d19c..cfd1b251 100644 --- a/monitor/query_test.go +++ b/monitor/query_test.go @@ -31,7 +31,7 @@ func FuzzQueryInfoForNextEpoch(f *testing.F) { bbnCli := monitor.NewMockBabylonQueryClient(ctrl) bbnCli.EXPECT().BlsPublicKeyList(gomock.Eq(e), gomock.Nil()).Return( &ckpttypes.QueryBlsPublicKeyListResponse{ - ValidatorWithBlsKeys: valSet.ValSet, + ValidatorWithBlsKeys: convertToBlsPublicKeyListResponse(valSet.ValSet), }, nil, ).AnyTimes() diff --git a/monitor/utils.go b/monitor/utils.go index abc86028..c9612f34 100644 --- a/monitor/utils.go +++ b/monitor/utils.go @@ -1,6 +1,6 @@ package monitor -func minBTCHeight(h1, h2 uint64) uint64 { +func minBTCHeight(h1, h2 uint32) uint32 { if h1 > h2 { return h2 } diff --git a/reporter/bootstrapping.go b/reporter/bootstrapping.go index 24382fd7..58bed291 100644 --- a/reporter/bootstrapping.go +++ b/reporter/bootstrapping.go @@ -21,8 +21,8 @@ var ( ) type consistencyCheckInfo struct { - bbnLatestBlockHeight uint64 - startSyncHeight uint64 + bbnLatestBlockHeight uint32 + startSyncHeight uint32 } // checkConsistency checks whether the `max(bbn_tip_height - confirmation_depth, bbn_base_height)` block is same @@ -41,7 +41,7 @@ func (r *Reporter) checkConsistency() (*consistencyCheckInfo, error) { return nil, err } - var consistencyCheckHeight uint64 + var consistencyCheckHeight uint32 if tipRes.Header.Height >= baseRes.Header.Height+r.btcConfirmationDepth { consistencyCheckHeight = tipRes.Header.Height - r.btcConfirmationDepth } else { @@ -106,7 +106,7 @@ func (r *Reporter) bootstrap() error { // trim cache to the latest k+w blocks on BTC (which are same as in BBN) maxEntries := r.btcConfirmationDepth + r.checkpointFinalizationTimeout - if err = r.btcCache.Resize(maxEntries); err != nil { + if err = r.btcCache.Resize(uint64(maxEntries)); err != nil { r.logger.Errorf("Failed to resize BTC cache: %v", err) panic(err) } @@ -174,9 +174,9 @@ func (r *Reporter) bootstrapWithRetries() { func (r *Reporter) initBTCCache() error { var ( err error - bbnLatestBlockHeight uint64 - bbnBaseHeight uint64 - baseHeight uint64 + bbnLatestBlockHeight uint32 + bbnBaseHeight uint32 + baseHeight uint32 ibs []*types.IndexedBlock ) @@ -226,9 +226,9 @@ func (r *Reporter) initBTCCache() error { func (r *Reporter) waitUntilBTCSync() error { var ( btcLatestBlockHash *chainhash.Hash - btcLatestBlockHeight uint64 + btcLatestBlockHeight uint32 bbnLatestBlockHash *chainhash.Hash - bbnLatestBlockHeight uint64 + bbnLatestBlockHeight uint32 err error ) @@ -284,7 +284,7 @@ func (r *Reporter) waitUntilBTCSync() error { return nil } -func (r *Reporter) checkHeaderConsistency(consistencyCheckHeight uint64) error { +func (r *Reporter) checkHeaderConsistency(consistencyCheckHeight uint32) error { var err error consistencyCheckBlock := r.btcCache.FindBlock(consistencyCheckHeight) diff --git a/reporter/reporter.go b/reporter/reporter.go index 4590f9d8..f2f4f866 100644 --- a/reporter/reporter.go +++ b/reporter/reporter.go @@ -3,11 +3,12 @@ package reporter import ( "encoding/hex" "fmt" - "github.com/babylonlabs-io/vigilante/retrywrap" - notifier "github.com/lightningnetwork/lnd/chainntnfs" "sync" "time" + "github.com/babylonlabs-io/vigilante/retrywrap" + notifier "github.com/lightningnetwork/lnd/chainntnfs" + "github.com/avast/retry-go/v4" "github.com/babylonlabs-io/babylon/btctxformatter" btcctypes "github.com/babylonlabs-io/babylon/x/btccheckpoint/types" @@ -33,8 +34,8 @@ type Reporter struct { // Internal states of the reporter CheckpointCache *types.CheckpointCache btcCache *types.BTCCache - btcConfirmationDepth uint64 - checkpointFinalizationTimeout uint64 + btcConfirmationDepth uint32 + checkpointFinalizationTimeout uint32 metrics *metrics.ReporterMetrics wg sync.WaitGroup started bool diff --git a/testutil/datagen/datagen.go b/testutil/datagen/datagen.go index ddaf7328..d38e45d2 100644 --- a/testutil/datagen/datagen.go +++ b/testutil/datagen/datagen.go @@ -1,9 +1,10 @@ package datagen import ( + "math/rand" + "github.com/babylonlabs-io/babylon/testutil/datagen" "github.com/babylonlabs-io/vigilante/types" - "math/rand" ) func GenerateRandomCheckpointRecord(r *rand.Rand) *types.CheckpointRecord { @@ -12,6 +13,6 @@ func GenerateRandomCheckpointRecord(r *rand.Rand) *types.CheckpointRecord { return &types.CheckpointRecord{ RawCheckpoint: rawCheckpoint, - FirstSeenBtcHeight: btcHeight, + FirstSeenBtcHeight: uint32(btcHeight), } } diff --git a/testutil/mocks/btcclient.go b/testutil/mocks/btcclient.go index 1cb5c03b..008c3a50 100644 --- a/testutil/mocks/btcclient.go +++ b/testutil/mocks/btcclient.go @@ -43,7 +43,7 @@ func (m *MockBTCClient) EXPECT() *MockBTCClientMockRecorder { } // FindTailBlocksByHeight mocks base method. -func (m *MockBTCClient) FindTailBlocksByHeight(height uint64) ([]*types.IndexedBlock, error) { +func (m *MockBTCClient) FindTailBlocksByHeight(height uint32) ([]*types.IndexedBlock, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "FindTailBlocksByHeight", height) ret0, _ := ret[0].([]*types.IndexedBlock) @@ -58,10 +58,10 @@ func (mr *MockBTCClientMockRecorder) FindTailBlocksByHeight(height interface{}) } // GetBestBlock mocks base method. -func (m *MockBTCClient) GetBestBlock() (uint64, error) { +func (m *MockBTCClient) GetBestBlock() (uint32, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBestBlock") - ret0, _ := ret[0].(uint64) + ret0, _ := ret[0].(uint32) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -89,7 +89,7 @@ func (mr *MockBTCClientMockRecorder) GetBlockByHash(blockHash interface{}) *gomo } // GetBlockByHeight mocks base method. -func (m *MockBTCClient) GetBlockByHeight(height uint64) (*types.IndexedBlock, *wire.MsgBlock, error) { +func (m *MockBTCClient) GetBlockByHeight(height uint32) (*types.IndexedBlock, *wire.MsgBlock, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetBlockByHeight", height) ret0, _ := ret[0].(*types.IndexedBlock) diff --git a/types/btccache.go b/types/btccache.go index 3007e31f..9515016d 100644 --- a/types/btccache.go +++ b/types/btccache.go @@ -130,7 +130,7 @@ func (b *BTCCache) size() uint64 { } // GetLastBlocks returns list of blocks between the given stopHeight and the tip of the chain in cache -func (b *BTCCache) GetLastBlocks(stopHeight uint64) ([]*IndexedBlock, error) { +func (b *BTCCache) GetLastBlocks(stopHeight uint32) ([]*IndexedBlock, error) { b.RLock() defer b.RUnlock() @@ -178,7 +178,7 @@ func (b *BTCCache) TrimConfirmedBlocks(k int) []*IndexedBlock { } // FindBlock uses binary search to find the block with the given height in cache -func (b *BTCCache) FindBlock(blockHeight uint64) *IndexedBlock { +func (b *BTCCache) FindBlock(blockHeight uint32) *IndexedBlock { b.RLock() defer b.RUnlock() diff --git a/types/btccache_test.go b/types/btccache_test.go index b7f5b787..08f265e8 100644 --- a/types/btccache_test.go +++ b/types/btccache_test.go @@ -1,10 +1,11 @@ package types_test import ( - "github.com/stretchr/testify/require" "math/rand" "testing" + "github.com/stretchr/testify/require" + "github.com/babylonlabs-io/babylon/testutil/datagen" vdatagen "github.com/babylonlabs-io/vigilante/testutil/datagen" "github.com/babylonlabs-io/vigilante/types" @@ -68,7 +69,7 @@ func FuzzBtcCache(f *testing.F) { // Find a random block in the cache randIdx := datagen.RandomInt(r, int(numBlocks)) randIb := ibs[randIdx] - randIbHeight := uint64(randIb.Height) + randIbHeight := uint32(randIb.Height) foundIb := cache.FindBlock(randIbHeight) require.NotNil(t, foundIb) require.Equal(t, foundIb, randIb) diff --git a/types/ckpt_record.go b/types/ckpt_record.go index df816909..95d2b522 100644 --- a/types/ckpt_record.go +++ b/types/ckpt_record.go @@ -6,10 +6,10 @@ import ( type CheckpointRecord struct { RawCheckpoint *ckpttypes.RawCheckpoint - FirstSeenBtcHeight uint64 + FirstSeenBtcHeight uint32 } -func NewCheckpointRecord(ckpt *ckpttypes.RawCheckpoint, height uint64) *CheckpointRecord { +func NewCheckpointRecord(ckpt *ckpttypes.RawCheckpoint, height uint32) *CheckpointRecord { return &CheckpointRecord{RawCheckpoint: ckpt, FirstSeenBtcHeight: height} } diff --git a/types/genesis_info.go b/types/genesis_info.go index a55df0c0..13922b92 100644 --- a/types/genesis_info.go +++ b/types/genesis_info.go @@ -18,14 +18,14 @@ import ( ) type GenesisInfo struct { - baseBTCHeight uint64 + baseBTCHeight uint32 epochInterval uint64 checkpointTag string valSet checkpointingtypes.ValidatorWithBlsKeySet } func NewGenesisInfo( - baseBTCHeight uint64, + baseBTCHeight uint32, epochInterval uint64, checkpointTag string, valSet *checkpointingtypes.ValidatorWithBlsKeySet, @@ -41,7 +41,7 @@ func NewGenesisInfo( // GetGenesisInfoFromFile reads genesis info from the provided genesis file func GetGenesisInfoFromFile(filePath string) (*GenesisInfo, error) { var ( - baseBTCHeight uint64 + baseBTCHeight uint32 epochInterval uint64 checkpointTag string valSet checkpointingtypes.ValidatorWithBlsKeySet @@ -156,7 +156,7 @@ func GetBtccheckpointGenesisStateFromAppState(cdc codec.Codec, appState map[stri return genesisState } -func (gi *GenesisInfo) GetBaseBTCHeight() uint64 { +func (gi *GenesisInfo) GetBaseBTCHeight() uint32 { return gi.baseBTCHeight } @@ -172,6 +172,6 @@ func (gi *GenesisInfo) GetCheckpointTag() string { return gi.checkpointTag } -func (gi *GenesisInfo) SetBaseBTCHeight(height uint64) { +func (gi *GenesisInfo) SetBaseBTCHeight(height uint32) { gi.baseBTCHeight = height } diff --git a/types/genesis_info_test.go b/types/genesis_info_test.go index 97941b22..46a48520 100644 --- a/types/genesis_info_test.go +++ b/types/genesis_info_test.go @@ -63,6 +63,6 @@ func FuzzGetGenesisInfoFromFile(f *testing.F) { require.NoError(t, err) require.Equal(t, uint64(epochInterval), genesisInfo.epochInterval) require.Len(t, genesisInfo.valSet.ValSet, validatorNum) - require.Equal(t, uint64(baseHeight), genesisInfo.baseBTCHeight) + require.Equal(t, uint32(baseHeight), genesisInfo.baseBTCHeight) }) }