diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d1c9f0f..8dc848bc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,9 @@ jobs: run-unit-tests: true run-integration-tests: true run-lint: true - install-dependencies-command: sudo apt-get install libzmq3-dev + install-dependencies-command: | + sudo apt-get update + sudo apt-get install -y libzmq3-dev docker_pipeline: uses: babylonlabs-io/.github/.github/workflows/reusable_docker_pipeline.yml@v0.3.1 diff --git a/Makefile b/Makefile index ad9d324d..dd9d0f8b 100644 --- a/Makefile +++ b/Makefile @@ -6,12 +6,9 @@ MOCKGEN_CMD=go run ${MOCKGEN_REPO}@${MOCKGEN_VERSION} BUILDDIR ?= $(CURDIR)/build TOOLS_DIR := tools -BTCD_PKG := github.com/btcsuite/btcd -BTCDW_PKG := github.com/btcsuite/btcwallet BABYLON_PKG := github.com/babylonlabs-io/babylon/cmd/babylond GO_BIN := ${GOPATH}/bin -BTCD_BIN := $(GO_BIN)/btcd ldflags := $(LDFLAGS) build_tags := $(BUILD_TAGS) @@ -52,7 +49,7 @@ test: go test ./... test-e2e: - cd $(TOOLS_DIR); go install -trimpath $(BTCD_PKG); go install -trimpath $(BTCDW_PKG); go install -trimpath $(BABYLON_PKG); + cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG); go test -mod=readonly -timeout=25m -v $(PACKAGES_E2E) -count=1 --tags=e2e build-docker: diff --git a/btcclient/client.go b/btcclient/client.go index b784fd9b..4cd3933f 100644 --- a/btcclient/client.go +++ b/btcclient/client.go @@ -60,4 +60,10 @@ func (c *Client) Stop() { if c.blockEventChan != nil { close(c.blockEventChan) } + + if c.zmqClient != nil { + if err := c.zmqClient.Close(); err != nil { + c.logger.Debug(err) + } + } } diff --git a/btcclient/client_block_subscriber.go b/btcclient/client_block_subscriber.go index f0926a01..c3245158 100644 --- a/btcclient/client_block_subscriber.go +++ b/btcclient/client_block_subscriber.go @@ -51,15 +51,6 @@ func NewWithBlockSubscriber(cfg *config.BTCConfig, retrySleepTime, maxRetrySleep return nil, err } - // ensure we are using bitcoind as Bitcoin node, as zmq is only supported by bitcoind - backend, err := rpcClient.BackendVersion() - if err != nil { - return nil, fmt.Errorf("failed to get BTC backend: %v", err) - } - if backend != rpcclient.BitcoindPost25 { - return nil, fmt.Errorf("zmq is only supported by bitcoind, but got %v", backend) - } - zmqClient, err := zmq.New(logger, cfg.ZmqSeqEndpoint, client.blockEventChan, rpcClient) if err != nil { return nil, err diff --git a/btcclient/notifier.go b/btcclient/notifier.go index 2e31fd71..4bc73c71 100644 --- a/btcclient/notifier.go +++ b/btcclient/notifier.go @@ -48,7 +48,7 @@ func DefaultBitcoindConfig() Bitcoind { RPCHost: config.DefaultRpcBtcNodeHost, RPCUser: config.DefaultBtcNodeRpcUser, RPCPass: config.DefaultBtcNodeRpcPass, - RPCPolling: false, + RPCPolling: true, BlockPollingInterval: 30 * time.Second, TxPollingInterval: 30 * time.Second, EstimateMode: config.DefaultBtcNodeEstimateMode, @@ -81,7 +81,6 @@ func CfgToBtcNodeBackendConfig(cfg config.BTCConfig, rawCert string) *BtcNodeBac ActiveNodeBackend: types.Bitcoind, Bitcoind: &defaultBitcoindCfg, } - case types.Btcd: return &BtcNodeBackendConfig{ ActiveNodeBackend: types.Btcd, diff --git a/config/bitcoin.go b/config/bitcoin.go index c188dd14..aa2b5e97 100644 --- a/config/bitcoin.go +++ b/config/bitcoin.go @@ -102,7 +102,7 @@ const ( DefaultBtcNodeRpcPass = "rpcpass" DefaultBtcNodeEstimateMode = "CONSERVATIVE" DefaultBtcblockCacheSize = 20 * 1024 * 1024 // 20 MB - DefaultZmqSeqEndpoint = "tcp://127.0.0.1:29000" + DefaultZmqSeqEndpoint = "tcp://127.0.0.1:28333" DefaultZmqBlockEndpoint = "tcp://127.0.0.1:29001" DefaultZmqTxEndpoint = "tcp://127.0.0.1:29002" ) diff --git a/e2etest/atomicslasher_e2e_test.go b/e2etest/atomicslasher_e2e_test.go index d30181ac..c9799026 100644 --- a/e2etest/atomicslasher_e2e_test.go +++ b/e2etest/atomicslasher_e2e_test.go @@ -4,7 +4,7 @@ package e2etest import ( - "encoding/hex" + "go.uber.org/zap" "testing" "time" @@ -14,44 +14,22 @@ import ( "github.com/babylonlabs-io/vigilante/btcstaking-tracker/btcslasher" "github.com/babylonlabs-io/vigilante/config" "github.com/babylonlabs-io/vigilante/metrics" - "github.com/babylonlabs-io/vigilante/types" - "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btcd/wire" "github.com/stretchr/testify/require" ) +// TestAtomicSlasher verifies the behavior of the atomic slasher by setting up delegations, +// sending slashing transactions, and ensuring that slashing is detected and executed correctly. func TestAtomicSlasher(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := map[chainhash.Hash]struct{}{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs[*hash] = struct{}{} - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) + // start WebSocket connection with Babylon for subscriber services - err = tm.BabylonClient.Start() + err := tm.BabylonClient.Start() require.NoError(t, err) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -61,8 +39,8 @@ func TestAtomicSlasher(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -73,9 +51,6 @@ func TestAtomicSlasher(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - metrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( @@ -84,15 +59,12 @@ func TestAtomicSlasher(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, + zap.NewNop(), metrics, ) go bsTracker.Start() defer bsTracker.Stop() - // wait for bootstrapping - time.Sleep(5 * time.Second) - bsParamsResp, err := tm.BabylonClient.BTCStakingParams() require.NoError(t, err) bsParams := bsParamsResp.Params @@ -113,23 +85,25 @@ func TestAtomicSlasher(t *testing.T) { finality provider builds slashing tx witness and sends slashing tx to Bitcoin */ victimBTCDel := btcDels[0] - victimSlashingTx, err := btcslasher.BuildSlashingTxWithWitness(victimBTCDel, &bsParams, netParams, fpSK) + victimSlashingTx, err := btcslasher.BuildSlashingTxWithWitness(victimBTCDel, &bsParams, regtestParams, fpSK) // send slashing tx to Bitcoin require.NoError(t, err) slashingTxHash, err := tm.BTCClient.SendRawTransaction(victimSlashingTx, true) require.NoError(t, err) + require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(slashingTxHash) return err == nil }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx, which will trigger atomic slasher - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash})) - // ensure slashing tx will be detected on Bitcoin require.Eventually(t, func() bool { - _, ok := submittedTxs[*slashingTxHash] - return ok + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + minedBlock := tm.mineBlock(t) + require.Equal(t, 2, len(minedBlock.Transactions)) + /* atomic slasher will detect the selective slashing on victim BTC delegation the finality provider will get slashed on Babylon @@ -149,49 +123,33 @@ func TestAtomicSlasher(t *testing.T) { slashTx2, err := bstypes.NewBTCSlashingTxFromHex(btcDel2.SlashingTxHex) require.NoError(t, err) slashingTxHash2 := slashTx2.MustGetTxHash() + require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(slashingTxHash2) t.Logf("err of getting slashingTxHash of the BTC delegation affected by atomic slashing: %v", err) return err == nil }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx, which will trigger atomic slasher - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash2})) - // ensure slashing tx 2 will be detected on Bitcoin require.Eventually(t, func() bool { - _, ok := submittedTxs[*slashingTxHash2] - return ok + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash2})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + + minedBlock = tm.mineBlock(t) + require.Equal(t, 2, len(minedBlock.Transactions)) } +// TestAtomicSlasher_Unbonding tests the atomic slasher's handling of unbonding BTC delegations, +// including the creation and detection of unbonding slashing transactions. func TestAtomicSlasher_Unbonding(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := map[chainhash.Hash]struct{}{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs[*hash] = struct{}{} - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) + // start WebSocket connection with Babylon for subscriber services - err = tm.BabylonClient.Start() + err := tm.BabylonClient.Start() require.NoError(t, err) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -201,8 +159,8 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -213,10 +171,8 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -224,15 +180,12 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) go bsTracker.Start() defer bsTracker.Stop() - // wait for bootstrapping - time.Sleep(5 * time.Second) - bsParamsResp, err := tm.BabylonClient.BTCStakingParams() require.NoError(t, err) bsParams := bsParamsResp.Params @@ -252,6 +205,7 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { btcDelsResp2, err := tm.BabylonClient.BTCDelegations(bstypes.BTCDelegationStatus_ACTIVE, nil) require.NoError(t, err) require.Len(t, btcDelsResp2.BtcDelegations, 2) + // NOTE: `BTCDelegations` API does not return BTC delegations in created time order // thus we need to find out the 2nd BTC delegation one-by-one var btcDel2 *bstypes.BTCDelegationResponse @@ -262,6 +216,8 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { } } + require.NotNil(t, btcDel2, "err second delegation not found") + /* the victim BTC delegation unbonds */ @@ -270,8 +226,9 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { /* finality provider builds unbonding slashing tx witness and sends it to Bitcoin */ - victimUnbondingSlashingTx, err := btcslasher.BuildUnbondingSlashingTxWithWitness(victimBTCDel, &bsParams, netParams, fpSK) + victimUnbondingSlashingTx, err := btcslasher.BuildUnbondingSlashingTxWithWitness(victimBTCDel, &bsParams, regtestParams, fpSK) require.NoError(t, err) + // send slashing tx to Bitcoin // NOTE: sometimes unbonding slashing tx is not immediately spendable for some reason var unbondingSlashingTxHash *chainhash.Hash @@ -283,6 +240,7 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { } return true }, eventuallyWaitTimeOut, eventuallyPollTime) + // unbonding slashing tx is eventually queryable require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(unbondingSlashingTxHash) @@ -293,13 +251,13 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { return true }, eventuallyWaitTimeOut, eventuallyPollTime) // mine a block that includes unbonding slashing tx, which will trigger atomic slasher - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingSlashingTxHash})) - // ensure unbonding slashing tx will be detected on Bitcoin require.Eventually(t, func() bool { - _, ok := submittedTxs[*unbondingSlashingTxHash] - return ok + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingSlashingTxHash})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + minedBlock := tm.mineBlock(t) + require.Equal(t, 2, len(minedBlock.Transactions)) + /* atomic slasher will detect the selective slashing on victim BTC delegation the finality provider will get slashed on Babylon @@ -317,17 +275,19 @@ func TestAtomicSlasher_Unbonding(t *testing.T) { */ slashingTx2, err := bstypes.NewBTCSlashingTxFromHex(btcDel2.SlashingTxHex) require.NoError(t, err) + slashingTxHash2 := slashingTx2.MustGetTxHash() require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(slashingTxHash2) t.Logf("err of getting slashingTxHash of the BTC delegation affected by atomic slashing: %v", err) return err == nil }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx, which will trigger atomic slasher - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash2})) - // ensure slashing tx 2 will be detected on Bitcoin require.Eventually(t, func() bool { - _, ok := submittedTxs[*slashingTxHash2] - return ok + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingTxHash2})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + + minedBlock = tm.mineBlock(t) + require.Equal(t, 2, len(minedBlock.Transactions)) } diff --git a/e2etest/babylon_node_handler.go b/e2etest/babylon_node_handler.go index 0590047a..e77f623a 100644 --- a/e2etest/babylon_node_handler.go +++ b/e2etest/babylon_node_handler.go @@ -22,7 +22,7 @@ var ( func baseDirBabylondir() (string, error) { tempPath := os.TempDir() - tempName, err := os.MkdirTemp(tempPath, "zBabylonTestVigilante") + tempName, err := os.MkdirTemp(tempPath, "BabylonTestVigilante") if err != nil { return "", err } @@ -123,7 +123,7 @@ type BabylonNodeHandler struct { babylonNode *babylonNode } -func NewBabylonNodeHandler() (*BabylonNodeHandler, error) { +func NewBabylonNodeHandler(baseHeaderHex string, slashingAddress string) (*BabylonNodeHandler, error) { testDir, err := baseDirBabylondir() if err != nil { return nil, err @@ -140,6 +140,9 @@ func NewBabylonNodeHandler() (*BabylonNodeHandler, error) { "--btc-finalization-timeout=4", "--btc-confirmation-depth=2", "--additional-sender-account", + "--btc-network=regtest", + fmt.Sprintf("--slashing-address=%s", slashingAddress), + fmt.Sprintf("--btc-base-header=%s", baseHeaderHex), "--covenant-quorum=1", fmt.Sprintf("--covenant-pks=%s", bbn.NewBIP340PubKeyFromBTCPK(juryPK).MarshalHex()), ) diff --git a/e2etest/bitcoind_node_setup.go b/e2etest/bitcoind_node_setup.go new file mode 100644 index 00000000..52ffb4d4 --- /dev/null +++ b/e2etest/bitcoind_node_setup.go @@ -0,0 +1,110 @@ +package e2etest + +import ( + "encoding/json" + "fmt" + "github.com/babylonlabs-io/vigilante/e2etest/container" + "github.com/stretchr/testify/require" + "os" + "strconv" + "strings" + "testing" + "time" +) + +var ( + startTimeout = 30 * time.Second +) + +type CreateWalletResponse struct { + Name string `json:"name"` + Warning string `json:"warning"` +} + +type GenerateBlockResponse struct { + // address of the recipient of rewards + Address string `json:"address"` + // blocks generated + Blocks []string `json:"blocks"` +} + +type BitcoindTestHandler struct { + t *testing.T + m *container.Manager +} + +func NewBitcoindHandler(t *testing.T) *BitcoindTestHandler { + manager, err := container.NewManager() + require.NoError(t, err) + + return &BitcoindTestHandler{ + t: t, + m: manager, + } +} + +func (h *BitcoindTestHandler) Start() { + tempPath, err := os.MkdirTemp("", "vigilante-test-*") + require.NoError(h.t, err) + + h.t.Cleanup(func() { + _ = os.RemoveAll(tempPath) + }) + + _, err = h.m.RunBitcoindResource(tempPath) + require.NoError(h.t, err) + + h.t.Cleanup(func() { + _ = h.m.ClearResources() + }) + + require.Eventually(h.t, func() bool { + _, err := h.GetBlockCount() + if err != nil { + h.t.Logf("failed to get block count: %v", err) + } + return err == nil + }, startTimeout, 500*time.Millisecond, "bitcoind did not start") +} + +func (h *BitcoindTestHandler) GetBlockCount() (int, error) { + buff, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"getblockcount"}) + if err != nil { + return 0, err + } + + parsedBuffStr := strings.TrimSuffix(buff.String(), "\n") + + return strconv.Atoi(parsedBuffStr) +} + +func (h *BitcoindTestHandler) GenerateBlocks(count int) *GenerateBlockResponse { + buff, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"-generate", fmt.Sprintf("%d", count)}) + require.NoError(h.t, err) + + var response GenerateBlockResponse + err = json.Unmarshal(buff.Bytes(), &response) + require.NoError(h.t, err) + + return &response +} + +func (h *BitcoindTestHandler) CreateWallet(walletName string, passphrase string) *CreateWalletResponse { + // last false on the list will create legacy wallet. This is needed, as currently + // we are signing all taproot transactions by dumping the private key and signing it + // on app level. Descriptor wallets do not allow dumping private keys. + buff, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"createwallet", walletName, "false", "false", passphrase, "false", "false"}) + require.NoError(h.t, err) + + var response CreateWalletResponse + err = json.Unmarshal(buff.Bytes(), &response) + require.NoError(h.t, err) + + return &response +} + +// InvalidateBlock invalidates blocks starting from specified block hash +func (h *BitcoindTestHandler) InvalidateBlock(blockHash string) { + _, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"invalidateblock", blockHash}) + require.NoError(h.t, err) +} diff --git a/e2etest/btcd_wallet_handler.go b/e2etest/btcd_wallet_handler.go deleted file mode 100644 index 52a97813..00000000 --- a/e2etest/btcd_wallet_handler.go +++ /dev/null @@ -1,179 +0,0 @@ -package e2etest - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "runtime" -) - -func baseDir() (string, error) { - dirPath := filepath.Join(os.TempDir(), "btcdwallet", "rpctest") - err := os.MkdirAll(dirPath, 0755) - return dirPath, err -} - -type wallet struct { - cmd *exec.Cmd - pidFile string - dataDir string -} - -func newWallet(dataDir string, cmd *exec.Cmd) *wallet { - return &wallet{ - dataDir: dataDir, - cmd: cmd, - } -} - -func (n *wallet) start() error { - if err := n.cmd.Start(); err != nil { - return err - } - - pid, err := os.Create(filepath.Join(n.dataDir, - fmt.Sprintf("%s.pid", "config"))) - if err != nil { - return err - } - - n.pidFile = pid.Name() - if _, err = fmt.Fprintf(pid, "%d\n", n.cmd.Process.Pid); err != nil { - return err - } - - if err := pid.Close(); err != nil { - return err - } - - return nil -} - -func (n *wallet) stop() (err error) { - if n.cmd == nil || n.cmd.Process == nil { - // return if not properly initialized - // or error starting the process - return nil - } - - defer func() { - err = n.cmd.Wait() - }() - - if runtime.GOOS == "windows" { - return n.cmd.Process.Signal(os.Kill) - } - return n.cmd.Process.Signal(os.Interrupt) -} - -func (n *wallet) cleanup() error { - if n.pidFile != "" { - if err := os.Remove(n.pidFile); err != nil { - log.Errorf("unable to remove file %s: %v", n.pidFile, - err) - } - } - - dirs := []string{ - n.dataDir, - } - var err error - for _, dir := range dirs { - if err = os.RemoveAll(dir); err != nil { - log.Errorf("Cannot remove dir %s: %v", dir, err) - } - } - return err -} - -func (n *wallet) shutdown() error { - if err := n.stop(); err != nil { - return err - } - if err := n.cleanup(); err != nil { - return err - } - return nil -} - -type WalletHandler struct { - wallet *wallet -} - -func NewWalletHandler(btcdCert []byte, walletPath string, btcdHost string) (*WalletHandler, error) { - testDir, err := baseDir() - logsPath := filepath.Join(testDir, "logs") - walletDir := filepath.Join(testDir, "simnet") - - if err := os.Mkdir(walletDir, os.ModePerm); err != nil { - return nil, err - } - - if err != nil { - return nil, err - } - - certFile := filepath.Join(testDir, "rpc.cert") - - dir := fmt.Sprintf("--appdata=%s", testDir) - logDir := fmt.Sprintf("--logdir=%s", logsPath) - certDir := fmt.Sprintf("--cafile=%s", certFile) - hostConf := fmt.Sprintf("--rpcconnect=%s", btcdHost) - - // Write cert and key files. - if err = os.WriteFile(certFile, btcdCert, 0666); err != nil { - return nil, err - } - - tempWalletPath := filepath.Join(walletDir, "wallet.db") - - // Read all content of src to data, may cause OOM for a large file. - data, err := os.ReadFile(walletPath) - - if err != nil { - return nil, err - } - - // Write data to dst - err = os.WriteFile(tempWalletPath, data, 0644) - - if err != nil { - return nil, err - } - - // btcwallet --btcdusername=user --btcdpassword=pass --username=user --password=pass --noinitialload --noservertls --simnet - createCmd := exec.Command( - "btcwallet", - "--debuglevel=debug", - "--btcdusername=user", - "--btcdpassword=pass", - "--username=user", - "--password=pass", - "--noservertls", - "--simnet", - hostConf, - certDir, - dir, - logDir, - ) - - return &WalletHandler{ - wallet: newWallet(testDir, createCmd), - }, nil -} - -func (w *WalletHandler) Start() error { - if err := w.wallet.start(); err != nil { - return w.wallet.cleanup() - } - return nil -} - -func (w *WalletHandler) Stop() error { - if err := w.wallet.shutdown(); err != nil { - return err - } - - return nil -} diff --git a/e2etest/container/config.go b/e2etest/container/config.go new file mode 100644 index 00000000..b1d14313 --- /dev/null +++ b/e2etest/container/config.go @@ -0,0 +1,23 @@ +package container + +// ImageConfig contains all images and their respective tags +// needed for running e2e tests. +type ImageConfig struct { + BitcoindRepository string + BitcoindVersion string +} + +//nolint:deadcode +const ( + dockerBitcoindRepository = "lncm/bitcoind" + dockerBitcoindVersionTag = "v24.0.1" +) + +// NewImageConfig returns ImageConfig needed for running e2e test. +func NewImageConfig() ImageConfig { + config := ImageConfig{ + BitcoindRepository: dockerBitcoindRepository, + BitcoindVersion: dockerBitcoindVersionTag, + } + return config +} diff --git a/e2etest/container/container.go b/e2etest/container/container.go new file mode 100644 index 00000000..c95bd19b --- /dev/null +++ b/e2etest/container/container.go @@ -0,0 +1,188 @@ +package container + +import ( + "bytes" + "context" + "fmt" + "regexp" + "testing" + "time" + + "github.com/ory/dockertest/v3" + "github.com/ory/dockertest/v3/docker" + "github.com/stretchr/testify/require" +) + +const ( + bitcoindContainerName = "bitcoind-test" +) + +var errRegex = regexp.MustCompile(`(E|e)rror`) + +// Manager is a wrapper around all Docker instances, and the Docker API. +// It provides utilities to run and interact with all Docker containers used within e2e testing. +type Manager struct { + cfg ImageConfig + pool *dockertest.Pool + resources map[string]*dockertest.Resource +} + +// NewManager creates a new Manager instance and initializes +// all Docker specific utilities. Returns an error if initialization fails. +func NewManager() (docker *Manager, err error) { + docker = &Manager{ + cfg: NewImageConfig(), + resources: make(map[string]*dockertest.Resource), + } + docker.pool, err = dockertest.NewPool("") + if err != nil { + return nil, err + } + return docker, nil +} + +func (m *Manager) ExecBitcoindCliCmd(t *testing.T, command []string) (bytes.Buffer, bytes.Buffer, error) { + // this is currently hardcoded, as it will be the same for all tests + cmd := []string{"bitcoin-cli", "-chain=regtest", "-rpcuser=user", "-rpcpassword=pass"} + cmd = append(cmd, command...) + return m.ExecCmd(t, bitcoindContainerName, cmd) +} + +// ExecCmd executes command by running it on the given container. +// It word for word `error` in output to discern between error and regular output. +// It retures stdout and stderr as bytes.Buffer and an error if the command fails. +func (m *Manager) ExecCmd(t *testing.T, containerName string, command []string) (bytes.Buffer, bytes.Buffer, error) { + if _, ok := m.resources[containerName]; !ok { + return bytes.Buffer{}, bytes.Buffer{}, fmt.Errorf("no resource %s found", containerName) + } + containerId := m.resources[containerName].Container.ID + + var ( + outBuf bytes.Buffer + errBuf bytes.Buffer + ) + + timeout := 20 * time.Second + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + t.Logf("\n\nRunning: \"%s\"", command) + + // We use the `require.Eventually` function because it is only allowed to do one transaction per block without + // sequence numbers. For simplicity, we avoid keeping track of the sequence number and just use the `require.Eventually`. + require.Eventually( + t, + func() bool { + exec, err := m.pool.Client.CreateExec(docker.CreateExecOptions{ + Context: ctx, + AttachStdout: true, + AttachStderr: true, + Container: containerId, + User: "root", + Cmd: command, + }) + + if err != nil { + t.Logf("failed to create exec: %v", err) + return false + } + + err = m.pool.Client.StartExec(exec.ID, docker.StartExecOptions{ + Context: ctx, + Detach: false, + OutputStream: &outBuf, + ErrorStream: &errBuf, + }) + if err != nil { + t.Logf("failed to start exec: %v", err) + return false + } + + errBufString := errBuf.String() + // Note that this does not match all errors. + // This only works if CLI outputs "Error" or "error" + // to stderr. + if errRegex.MatchString(errBufString) { + t.Log("\nstderr:") + t.Log(errBufString) + + t.Log("\nstdout:") + t.Log(outBuf.String()) + return false + } + + return true + }, + timeout, + 500*time.Millisecond, + "command failed", + ) + + return outBuf, errBuf, nil +} + +func (m *Manager) RunBitcoindResource( + bitcoindCfgPath string, +) (*dockertest.Resource, error) { + bitcoindResource, err := m.pool.RunWithOptions( + &dockertest.RunOptions{ + Name: bitcoindContainerName, + Repository: m.cfg.BitcoindRepository, + Tag: m.cfg.BitcoindVersion, + User: "root:root", + Mounts: []string{ + fmt.Sprintf("%s/:/data/.bitcoin", bitcoindCfgPath), + }, + ExposedPorts: []string{ + "8332", + "8333", + "28332", + "28333", + "18443", + "18444", + }, + PortBindings: map[docker.Port][]docker.PortBinding{ + "8332/tcp": {{HostIP: "", HostPort: "8332"}}, + "8333/tcp": {{HostIP: "", HostPort: "8333"}}, + "28332/tcp": {{HostIP: "", HostPort: "28332"}}, + "28333/tcp": {{HostIP: "", HostPort: "28333"}}, + "18443/tcp": {{HostIP: "", HostPort: "18443"}}, + "18444/tcp": {{HostIP: "", HostPort: "18444"}}, + }, + Cmd: []string{ + "-debug=1", + "-regtest", + "-txindex", + "-rpcuser=user", + "-rpcpassword=pass", + "-rpcallowip=0.0.0.0/0", + "-rpcbind=0.0.0.0", + "-zmqpubsequence=tcp://0.0.0.0:28333", + }, + }, + noRestart, + ) + if err != nil { + return nil, err + } + m.resources[bitcoindContainerName] = bitcoindResource + return bitcoindResource, nil +} + +// ClearResources removes all outstanding Docker resources created by the Manager. +func (m *Manager) ClearResources() error { + for _, resource := range m.resources { + if err := m.pool.Purge(resource); err != nil { + return err + } + } + + return nil +} + +func noRestart(config *docker.HostConfig) { + // in this case we don't want the nodes to restart on failure + config.RestartPolicy = docker.RestartPolicy{ + Name: "no", + } +} diff --git a/e2etest/reporter_e2e_test.go b/e2etest/reporter_e2e_test.go index 142fe3a6..b269832c 100644 --- a/e2etest/reporter_e2e_test.go +++ b/e2etest/reporter_e2e_test.go @@ -4,18 +4,12 @@ package e2etest import ( - "math/rand" + "sync" "testing" "time" - "github.com/babylonlabs-io/babylon/testutil/datagen" "github.com/babylonlabs-io/vigilante/metrics" "github.com/babylonlabs-io/vigilante/reporter" - "github.com/babylonlabs-io/vigilante/types" - "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/integration/rpctest" - "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btcd/wire" "github.com/stretchr/testify/require" ) @@ -24,90 +18,48 @@ var ( ) func (tm *TestManager) BabylonBTCChainMatchesBtc(t *testing.T) bool { - tipHash, tipHeight, err := tm.BTCClient.GetBestBlock() + tipHeight, err := tm.TestRpcClient.GetBlockCount() + require.NoError(t, err) + tipHash, err := tm.TestRpcClient.GetBlockHash(tipHeight) require.NoError(t, err) bbnBtcLcTip, err := tm.BabylonClient.BTCHeaderChainTip() require.NoError(t, err) - return uint64(tipHeight) == bbnBtcLcTip.Header.Height && tipHash.String() == bbnBtcLcTip.Header.HashHex -} -func (tm *TestManager) GenerateAndSubmitsNBlocksFromTip(N int) { - var ut time.Time - - for i := 0; i < N; i++ { - tm.MinerNode.GenerateAndSubmitBlock(nil, -1, ut) - } + return uint64(tipHeight) == bbnBtcLcTip.Header.Height && tipHash.String() == bbnBtcLcTip.Header.HashHex } func (tm *TestManager) GenerateAndSubmitBlockNBlockStartingFromDepth(t *testing.T, N int, depth uint32) { - r := rand.New(rand.NewSource(time.Now().Unix())) - if depth == 0 { // depth 0 means we are starting from tip - tm.GenerateAndSubmitsNBlocksFromTip(N) + tm.BitcoindHandler.GenerateBlocks(N) return } - _, bestHeight, err := tm.MinerNode.Client.GetBestBlock() - require.NoError(t, err) - - startingBlockHeight := bestHeight - int32(depth) - - blockHash, err := tm.MinerNode.Client.GetBlockHash(int64(startingBlockHeight)) - require.NoError(t, err) - - startingBlockMsg, err := tm.MinerNode.Client.GetBlock(blockHash) + height, err := tm.TestRpcClient.GetBlockCount() require.NoError(t, err) - startingBlock := btcutil.NewBlock(startingBlockMsg) - startingBlock.SetHeight(startingBlockHeight) + startingBlockHeight := height - int64(depth) - arr := datagen.GenRandomByteArray(r, 20) - add, err := btcutil.NewAddressScriptHashFromHash(arr, tm.MinerNode.ActiveNet) + blockHash, err := tm.TestRpcClient.GetBlockHash(startingBlockHeight) require.NoError(t, err) - var lastSubmittedBlock *btcutil.Block - var ut time.Time + // invalidate blocks from this height + tm.BitcoindHandler.InvalidateBlock(blockHash.String()) for i := 0; i < N; i++ { - var blockToSubmit *btcutil.Block - - if lastSubmittedBlock == nil { - // first block to submit start from starting block - newBlock, err := rpctest.CreateBlock(startingBlock, nil, rpctest.BlockVersion, - ut, add, nil, tm.MinerNode.ActiveNet) - require.NoError(t, err) - blockToSubmit = newBlock - } else { - newBlock, err := rpctest.CreateBlock(lastSubmittedBlock, nil, rpctest.BlockVersion, - ut, add, nil, tm.MinerNode.ActiveNet) - require.NoError(t, err) - blockToSubmit = newBlock - } - err = tm.MinerNode.Client.SubmitBlock(blockToSubmit, nil) - require.NoError(t, err) - lastSubmittedBlock = blockToSubmit + tm.BitcoindHandler.GenerateBlocks(N) } } func TestReporter_BoostrapUnderFrequentBTCHeaders(t *testing.T) { // no need to much mature outputs, we are not going to submit transactions in this test - numMatureOutputs := uint32(2) - - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - } + numMatureOutputs := uint32(150) - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) reporterMetrics := metrics.NewReporterMetrics() + vigilantReporter, err := reporter.New( &tm.Config.Reporter, logger, @@ -120,15 +72,26 @@ func TestReporter_BoostrapUnderFrequentBTCHeaders(t *testing.T) { require.NoError(t, err) // start a routine that mines BTC blocks very fast + var wg sync.WaitGroup + stopChan := make(chan struct{}) + + wg.Add(1) go func() { + defer wg.Done() ticker := time.NewTicker(10 * time.Second) - for range ticker.C { - tm.GenerateAndSubmitsNBlocksFromTip(1) + defer ticker.Stop() + for { + select { + case <-ticker.C: + tm.BitcoindHandler.GenerateBlocks(1) + case <-stopChan: + return + } } }() // mine some BTC headers - tm.GenerateAndSubmitsNBlocksFromTip(2) + tm.BitcoindHandler.GenerateBlocks(1) // start reporter vigilantReporter.Start() @@ -138,23 +101,16 @@ func TestReporter_BoostrapUnderFrequentBTCHeaders(t *testing.T) { require.Eventually(t, func() bool { return tm.BabylonBTCChainMatchesBtc(t) }, longEventuallyWaitTimeOut, eventuallyPollTime) + + close(stopChan) + wg.Wait() } func TestRelayHeadersAndHandleRollbacks(t *testing.T) { // no need to much mature outputs, we are not going to submit transactions in this test - numMatureOutputs := uint32(2) - - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - } + numMatureOutputs := uint32(150) - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) + tm := StartManager(t, numMatureOutputs) // this is necessary to receive notifications about new transactions entering mempool defer tm.Stop(t) @@ -170,6 +126,7 @@ func TestRelayHeadersAndHandleRollbacks(t *testing.T) { reporterMetrics, ) require.NoError(t, err) + vigilantReporter.Start() defer vigilantReporter.Stop() @@ -178,7 +135,7 @@ func TestRelayHeadersAndHandleRollbacks(t *testing.T) { }, longEventuallyWaitTimeOut, eventuallyPollTime) // generate 3, we are submitting headers 1 by 1 so we use small amount as this is slow process - tm.GenerateAndSubmitsNBlocksFromTip(3) + tm.BitcoindHandler.GenerateBlocks(3) require.Eventually(t, func() bool { return tm.BabylonBTCChainMatchesBtc(t) @@ -195,19 +152,9 @@ func TestRelayHeadersAndHandleRollbacks(t *testing.T) { func TestHandleReorgAfterRestart(t *testing.T) { // no need to much mature outputs, we are not going to submit transactions in this test - numMatureOutputs := uint32(2) - - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - } + numMatureOutputs := uint32(150) - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) + tm := StartManager(t, numMatureOutputs) // this is necessary to receive notifications about new transactions entering mempool defer tm.Stop(t) @@ -243,11 +190,14 @@ func TestHandleReorgAfterRestart(t *testing.T) { // // we will start from block before tip and submit 2 new block this should trigger rollback tm.GenerateAndSubmitBlockNBlockStartingFromDepth(t, 2, 1) + btcClient := initBTCClientWithSubscriber(t, tm.Config) //current tm.BtcClient already has an active zmq subscription, would panic + defer btcClient.Stop() + // Start new reporter vigilantReporterNew, err := reporter.New( &tm.Config.Reporter, logger, - tm.BTCClient, + btcClient, tm.BabylonClient, tm.Config.Common.RetrySleepTime, tm.Config.Common.MaxRetrySleepTime, @@ -261,5 +211,4 @@ func TestHandleReorgAfterRestart(t *testing.T) { require.Eventually(t, func() bool { return tm.BabylonBTCChainMatchesBtc(t) }, longEventuallyWaitTimeOut, eventuallyPollTime) - } diff --git a/e2etest/slasher_e2e_test.go b/e2etest/slasher_e2e_test.go index c83ae3e4..b9a94e3f 100644 --- a/e2etest/slasher_e2e_test.go +++ b/e2etest/slasher_e2e_test.go @@ -4,7 +4,7 @@ package e2etest import ( - "encoding/hex" + "go.uber.org/zap" "testing" "time" @@ -14,39 +14,14 @@ import ( bst "github.com/babylonlabs-io/vigilante/btcstaking-tracker" "github.com/babylonlabs-io/vigilante/config" "github.com/babylonlabs-io/vigilante/metrics" - "github.com/babylonlabs-io/vigilante/types" - "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btcd/wire" "github.com/stretchr/testify/require" ) func TestSlasher_GracefulShutdown(t *testing.T) { - numMatureOutputs := uint32(5) - - submittedTxs := []*chainhash.Hash{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs = append(submittedTxs, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + numMatureOutputs := uint32(300) + + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -56,8 +31,8 @@ func TestSlasher_GracefulShutdown(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -68,10 +43,8 @@ func TestSlasher_GracefulShutdown(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -79,8 +52,8 @@ func TestSlasher_GracefulShutdown(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) go bsTracker.Start() @@ -88,6 +61,7 @@ func TestSlasher_GracefulShutdown(t *testing.T) { // wait for bootstrapping time.Sleep(10 * time.Second) + tm.BTCClient.Stop() // gracefully shut down defer bsTracker.Stop() } @@ -96,31 +70,10 @@ func TestSlasher_Slasher(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := []*chainhash.Hash{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs = append(submittedTxs, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) // start WebSocket connection with Babylon for subscriber services - err = tm.BabylonClient.Start() + err := tm.BabylonClient.Start() require.NoError(t, err) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -130,8 +83,8 @@ func TestSlasher_Slasher(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -142,10 +95,7 @@ func TestSlasher_Slasher(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -153,8 +103,8 @@ func TestSlasher_Slasher(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) go bsTracker.Start() defer bsTracker.Stop() @@ -175,49 +125,25 @@ func TestSlasher_Slasher(t *testing.T) { require.NoError(t, err) slashingMsgTxHash1 := slashingMsgTx.TxHash() slashingMsgTxHash := &slashingMsgTxHash1 - // slashing tx will eventually enter mempool - require.Eventually(t, func() bool { - _, err := tm.BTCClient.GetRawTransaction(slashingMsgTxHash) - t.Logf("err of getting slashingMsgTxHash: %v", err) - return err == nil - }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingMsgTxHash})) - // ensure 2 txs will eventually be received (staking tx and slashing tx) require.Eventually(t, func() bool { - return len(submittedTxs) == 2 + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingMsgTxHash})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + + minedBlock := tm.mineBlock(t) + // ensure 2 txs will eventually be received (staking tx and slashing tx) + require.Equal(t, 2, len(minedBlock.Transactions)) } func TestSlasher_SlashingUnbonding(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := []*chainhash.Hash{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs = append(submittedTxs, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) // start WebSocket connection with Babylon for subscriber services - err = tm.BabylonClient.Start() + err := tm.BabylonClient.Start() require.NoError(t, err) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -227,8 +153,8 @@ func TestSlasher_SlashingUnbonding(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -239,10 +165,7 @@ func TestSlasher_SlashingUnbonding(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -250,8 +173,8 @@ func TestSlasher_SlashingUnbonding(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) go bsTracker.Start() defer bsTracker.Stop() @@ -283,8 +206,14 @@ func TestSlasher_SlashingUnbonding(t *testing.T) { _, err := tm.BTCClient.GetRawTransaction(unbondingSlashingMsgTxHash) return err == nil }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingSlashingMsgTxHash})) + require.Eventually(t, func() bool { + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingSlashingMsgTxHash})) == 1 + }, eventuallyWaitTimeOut, eventuallyPollTime) + + tm.mineBlock(t) + // ensure tx is eventually on Bitcoin require.Eventually(t, func() bool { res, err := tm.BTCClient.GetRawTransactionVerbose(unbondingSlashingMsgTxHash) @@ -299,32 +228,10 @@ func TestSlasher_Bootstrapping(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := []*chainhash.Hash{} - blockEventChan := make(chan *types.BlockEvent, 1000) - - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs = append(submittedTxs, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) // start WebSocket connection with Babylon for subscriber services - err = tm.BabylonClient.Start() + err := tm.BabylonClient.Start() require.NoError(t, err) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -341,8 +248,8 @@ func TestSlasher_Bootstrapping(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -353,10 +260,7 @@ func TestSlasher_Bootstrapping(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -364,8 +268,8 @@ func TestSlasher_Bootstrapping(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) // bootstrap BTC staking tracker @@ -377,15 +281,13 @@ func TestSlasher_Bootstrapping(t *testing.T) { require.NoError(t, err) slashingMsgTxHash1 := slashingMsgTx.TxHash() slashingMsgTxHash := &slashingMsgTxHash1 - require.Eventually(t, func() bool { - _, err := tm.BTCClient.GetRawTransaction(slashingMsgTxHash) - t.Logf("err of getting slashingMsgTxHash: %v", err) - return err == nil - }, eventuallyWaitTimeOut, eventuallyPollTime) + // mine a block that includes slashing tx - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingMsgTxHash})) - // ensure 2 txs will eventually be received (staking tx and slashing tx) require.Eventually(t, func() bool { - return len(submittedTxs) == 2 + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{slashingMsgTxHash})) == 1 }, eventuallyWaitTimeOut, eventuallyPollTime) + + minedBlock := tm.mineBlock(t) + // ensure 2 txs will eventually be received (staking tx and slashing tx) + require.Equal(t, 2, len(minedBlock.Transactions)) } diff --git a/e2etest/submitter_e2e_test.go b/e2etest/submitter_e2e_test.go index b4c1383a..55284a8f 100644 --- a/e2etest/submitter_e2e_test.go +++ b/e2etest/submitter_e2e_test.go @@ -13,7 +13,6 @@ import ( checkpointingtypes "github.com/babylonlabs-io/babylon/x/checkpointing/types" "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -24,22 +23,9 @@ import ( func TestSubmitterSubmission(t *testing.T) { r := rand.New(rand.NewSource(time.Now().Unix())) - numMatureOutputs := uint32(5) - - var submittedTransactions []*chainhash.Hash - - // We are setting handler for transaction hitting the mempool, to be sure we will - // pass transaction to the miner, in the same order as they were submitted by submitter - handlers := &rpcclient.NotificationHandlers{ - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTransactions = append(submittedTransactions, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, nil) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) + numMatureOutputs := uint32(300) + + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) randomCheckpoint := datagen.GenRandomRawCheckpointWithMeta(r) @@ -66,11 +52,12 @@ func TestSubmitterSubmission(t *testing.T) { }, nil).AnyTimes() tm.Config.Submitter.PollingIntervalSeconds = 2 + // create submitter vigilantSubmitter, _ := submitter.New( &tm.Config.Submitter, logger, - tm.BTCWalletClient, + tm.BTCClient, mockBabylonClient, subAddr, tm.Config.Common.RetrySleepTime, @@ -85,40 +72,32 @@ func TestSubmitterSubmission(t *testing.T) { vigilantSubmitter.WaitForShutdown() }() - // wait for our 2 op_returns with epoch 1 checkpoint to hit the mempool and then - // retrieve them from there - // - // TODO: to assert that those are really transactions send by submitter, we would - // need to expose sentCheckpointInfo from submitter + // wait for our 2 op_returns with epoch 1 checkpoint to hit the mempool + var mempoolTxs []*chainhash.Hash + require.Eventually(t, func() bool { + var err error + mempoolTxs, err = tm.BTCClient.GetRawMempool() + require.NoError(t, err) + return len(mempoolTxs) > 1 + }, eventuallyWaitTimeOut, eventuallyPollTime) + + require.NotNil(t, mempoolTxs) + require.Eventually(t, func() bool { - return len(submittedTransactions) == 2 + return len(tm.RetrieveTransactionFromMempool(t, mempoolTxs)) == 2 }, eventuallyWaitTimeOut, eventuallyPollTime) - sendTransactions := tm.RetrieveTransactionFromMempool(t, submittedTransactions) // mine a block with those transactions - blockWithOpReturnTranssactions := tm.MineBlockWithTxs(t, sendTransactions) + blockWithOpReturnTransactions := tm.mineBlock(t) // block should have 3 transactions, 2 from submitter and 1 coinbase - require.Equal(t, len(blockWithOpReturnTranssactions.Transactions), 3) + require.Equal(t, len(blockWithOpReturnTransactions.Transactions), 3) } func TestSubmitterSubmissionReplace(t *testing.T) { r := rand.New(rand.NewSource(time.Now().Unix())) - numMatureOutputs := uint32(5) - - var submittedTransactions []*chainhash.Hash - - // We are setting handler for transaction hitting the mempool, to be sure we will - // pass transaction to the miner, in the same order as they were submitted by submitter - handlers := &rpcclient.NotificationHandlers{ - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTransactions = append(submittedTransactions, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, nil) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) + numMatureOutputs := uint32(300) + + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) randomCheckpoint := datagen.GenRandomRawCheckpointWithMeta(r) @@ -151,7 +130,7 @@ func TestSubmitterSubmissionReplace(t *testing.T) { vigilantSubmitter, _ := submitter.New( &tm.Config.Submitter, logger, - tm.BTCWalletClient, + tm.BTCClient, mockBabylonClient, subAddr, tm.Config.Common.RetrySleepTime, @@ -168,27 +147,27 @@ func TestSubmitterSubmissionReplace(t *testing.T) { // wait for our 2 op_returns with epoch 1 checkpoint to hit the mempool and then // retrieve them from there - // - // TODO: to assert that those are really transactions send by submitter, we would - // need to expose sentCheckpointInfo from submitter - require.Eventually(t, func() bool { - return len(submittedTransactions) == 2 - }, eventuallyWaitTimeOut, eventuallyPollTime) - - sendTransactions := tm.RetrieveTransactionFromMempool(t, submittedTransactions) - - // at this point our submitter already sent 2 checkpoint transactions which landed in mempool. - // Zero out submittedTransactions, and wait for a new tx2 to be submitted and accepted - // it should be replacements for the previous one. - submittedTransactions = []*chainhash.Hash{} + txsMap := make(map[string]struct{}) + var sendTransactions []*btcutil.Tx + var mempoolTxs []*chainhash.Hash require.Eventually(t, func() bool { - // we only replace tx2 of the checkpoint, thus waiting for 1 tx to arrive - return len(submittedTransactions) == 1 - }, eventuallyWaitTimeOut, eventuallyPollTime) - - transactionReplacement := tm.RetrieveTransactionFromMempool(t, submittedTransactions) - resendTx2 := transactionReplacement[0] + var err error + mempoolTxs, err = tm.BTCClient.GetRawMempool() + require.NoError(t, err) + for _, hash := range mempoolTxs { + hashStr := hash.String() + if _, exists := txsMap[hashStr]; !exists { + tx, err := tm.BTCClient.GetRawTransaction(hash) + require.NoError(t, err) + txsMap[hashStr] = struct{}{} + sendTransactions = append(sendTransactions, tx) + } + } + return len(txsMap) == 3 + }, eventuallyWaitTimeOut, 50*time.Millisecond) + + resendTx2 := sendTransactions[2] // Here check that sendTransactions1 are replacements for sendTransactions, i.e they should have: // 1. same @@ -196,11 +175,10 @@ func TestSubmitterSubmissionReplace(t *testing.T) { // 3. different signatures require.Equal(t, sendTransactions[1].MsgTx().TxIn[0].PreviousOutPoint, resendTx2.MsgTx().TxIn[0].PreviousOutPoint) require.Less(t, resendTx2.MsgTx().TxOut[1].Value, sendTransactions[1].MsgTx().TxOut[1].Value) - require.NotEqual(t, sendTransactions[1].MsgTx().TxIn[0].SignatureScript, resendTx2.MsgTx().TxIn[0].SignatureScript) + require.NotEqual(t, sendTransactions[1].MsgTx().TxIn[0].Witness[0], resendTx2.MsgTx().TxIn[0].Witness[0]) // mine a block with those replacement transactions just to be sure they execute correctly - sendTransactions[1] = resendTx2 - blockWithOpReturnTransactions := tm.MineBlockWithTxs(t, sendTransactions) + blockWithOpReturnTransactions := tm.mineBlock(t) // block should have 2 transactions, 1 from submitter and 1 coinbase require.Equal(t, len(blockWithOpReturnTransactions.Transactions), 3) } diff --git a/e2etest/test_manager.go b/e2etest/test_manager.go index 0395cc02..c3f21be2 100644 --- a/e2etest/test_manager.go +++ b/e2etest/test_manager.go @@ -1,11 +1,10 @@ package e2etest import ( + "bytes" "context" - "encoding/binary" "encoding/hex" - "os" - "path/filepath" + "go.uber.org/zap" "testing" "time" @@ -19,164 +18,58 @@ import ( "github.com/babylonlabs-io/vigilante/types" "github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcutil" - "github.com/btcsuite/btcd/btcutil/hdkeychain" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/integration/rpctest" "github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/wire" "github.com/stretchr/testify/require" ) -// bticoin params used for testing var ( - netParams = &chaincfg.SimNetParams submitterAddrStr = "bbn1eppc73j56382wjn6nnq3quu5eye4pmm087xfdh" //nolint:unused babylonTag = []byte{1, 2, 3, 4} //nolint:unused babylonTagHex = hex.EncodeToString(babylonTag) //nolint:unused - // copy of the seed from btcd/integration/rpctest memWallet, this way we can - // import the same wallet in the btcd wallet - hdSeed = [chainhash.HashSize]byte{ - 0x79, 0xa6, 0x1a, 0xdb, 0xc6, 0xe5, 0xa2, 0xe1, - 0x39, 0xd2, 0x71, 0x3a, 0x54, 0x6e, 0xc7, 0xc8, - 0x75, 0x63, 0x2e, 0x75, 0xf1, 0xdf, 0x9c, 0x3f, - 0xa6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - } - - // current number of active test nodes. This is necessary to replicate btcd rpctest.Harness - // methods of generating keys i.e with each started btcd node we increment this number - // by 1, and then use hdSeed || numTestInstances as the seed for generating keys - numTestInstances = 0 - - existingWalletFile = "wallet.db" - exisitngWalletPass = "pass" - walletTimeout = 86400 - eventuallyWaitTimeOut = 40 * time.Second eventuallyPollTime = 1 * time.Second + regtestParams = &chaincfg.RegressionNetParams ) -// keyToAddr maps the passed private to corresponding p2pkh address. -func keyToAddr(key *btcec.PrivateKey, net *chaincfg.Params) (btcutil.Address, error) { - serializedKey := key.PubKey().SerializeCompressed() - pubKeyAddr, err := btcutil.NewAddressPubKey(serializedKey, net) - if err != nil { - return nil, err - } - return pubKeyAddr.AddressPubKeyHash(), nil -} - func defaultVigilanteConfig() *config.Config { defaultConfig := config.DefaultConfig() // Config setting necessary to connect btcd daemon - defaultConfig.BTC.NetParams = "simnet" - defaultConfig.BTC.Endpoint = "127.0.0.1:18556" + defaultConfig.BTC.NetParams = regtestParams.Name + defaultConfig.BTC.Endpoint = "127.0.0.1:18443" // Config setting necessary to connect btcwallet daemon - defaultConfig.BTC.BtcBackend = "btcd" + defaultConfig.BTC.BtcBackend = types.Bitcoind defaultConfig.BTC.WalletEndpoint = "127.0.0.1:18554" defaultConfig.BTC.WalletPassword = "pass" defaultConfig.BTC.Username = "user" defaultConfig.BTC.Password = "pass" defaultConfig.BTC.DisableClientTLS = true - return defaultConfig -} - -func GetSpendingKeyAndAddress(id uint32) (*btcec.PrivateKey, btcutil.Address, error) { - var harnessHDSeed [chainhash.HashSize + 4]byte - copy(harnessHDSeed[:], hdSeed[:]) - // id used for our test wallet is always 0 - binary.BigEndian.PutUint32(harnessHDSeed[:chainhash.HashSize], id) - - hdRoot, err := hdkeychain.NewMaster(harnessHDSeed[:], netParams) + defaultConfig.BTC.ZmqSeqEndpoint = config.DefaultZmqSeqEndpoint - if err != nil { - return nil, nil, err - } - - // The first child key from the hd root is reserved as the coinbase - // generation address. - coinbaseChild, err := hdRoot.Derive(0) - if err != nil { - return nil, nil, err - } - - coinbaseKey, err := coinbaseChild.ECPrivKey() - - if err != nil { - return nil, nil, err - } - - coinbaseAddr, err := keyToAddr(coinbaseKey, netParams) - if err != nil { - return nil, nil, err - } - - return coinbaseKey, coinbaseAddr, nil + return defaultConfig } type TestManager struct { - MinerNode *rpctest.Harness - BtcWalletHandler *WalletHandler - BabylonHandler *BabylonNodeHandler - BabylonClient *bbnclient.Client - BTCClient *btcclient.Client - BTCWalletClient *btcclient.Client - Config *config.Config -} - -func initBTCWalletClient( - t *testing.T, - cfg *config.Config, - walletPrivKey *btcec.PrivateKey, - outputsToWaitFor int) *btcclient.Client { - - var client *btcclient.Client - - require.Eventually(t, func() bool { - btcWallet, err := btcclient.NewWallet(&cfg.BTC, logger) - if err != nil { - return false - } - - client = btcWallet - return true - - }, eventuallyWaitTimeOut, eventuallyPollTime) - - // lets wait until chain rpc becomes available - // poll time is increase here to avoid spamming the btcwallet rpc server - require.Eventually(t, func() bool { - if _, _, err := client.GetBestBlock(); err != nil { - return false - } - - return true - }, eventuallyWaitTimeOut, 1*time.Second) - - err := ImportWalletSpendingKey(t, client, walletPrivKey) - require.NoError(t, err) - - waitForNOutputs(t, client, outputsToWaitFor) - - return client + TestRpcClient *rpcclient.Client + BitcoindHandler *BitcoindTestHandler + BabylonHandler *BabylonNodeHandler + BabylonClient *bbnclient.Client + BTCClient *btcclient.Client + Config *config.Config + WalletPrivKey *btcec.PrivateKey } -func initBTCClientWithSubscriber(t *testing.T, cfg *config.Config, rpcClient *rpcclient.Client, connCfg *rpcclient.ConnConfig, blockEventChan chan *types.BlockEvent) *btcclient.Client { - btcCfg := &config.BTCConfig{ - NetParams: cfg.BTC.NetParams, - Username: connCfg.User, - Password: connCfg.Pass, - Endpoint: connCfg.Host, - DisableClientTLS: connCfg.DisableTLS, - } - client, err := btcclient.NewTestClientWithWsSubscriber(rpcClient, btcCfg, cfg.Common.RetrySleepTime, cfg.Common.MaxRetrySleepTime, blockEventChan) +func initBTCClientWithSubscriber(t *testing.T, cfg *config.Config) *btcclient.Client { + client, err := btcclient.NewWithBlockSubscriber(&cfg.BTC, cfg.Common.RetrySleepTime, cfg.Common.MaxRetrySleepTime, zap.NewNop()) require.NoError(t, err) - // lets wait until chain rpc becomes available + // let's wait until chain rpc becomes available // poll time is increase here to avoid spamming the rpc server require.Eventually(t, func() bool { - if _, _, err := client.GetBestBlock(); err != nil { + if _, err := client.GetBlockCount(); err != nil { log.Errorf("failed to get best block: %v", err) return false } @@ -188,82 +81,51 @@ func initBTCClientWithSubscriber(t *testing.T, cfg *config.Config, rpcClient *rp } // StartManager creates a test manager -// NOTE: if handlers.OnFilteredBlockConnected, handlers.OnFilteredBlockDisconnected -// and blockEventChan are all not nil, then the test manager will create a BTC -// client with a WebSocket subscriber -func StartManager( - t *testing.T, - numMatureOutputsInWallet uint32, - numbersOfOutputsToWaitForDuringInit int, - handlers *rpcclient.NotificationHandlers, - blockEventChan chan *types.BlockEvent) *TestManager { - args := []string{ - "--rejectnonstd", - "--txindex", - "--trickleinterval=100ms", - "--debuglevel=debug", - "--nowinservice", - // The miner will get banned and disconnected from the node if - // its requested data are not found. We add a nobanning flag to - // make sure they stay connected if it happens. - "--nobanning", - // Don't disconnect if a reply takes too long. - "--nostalldetect", - } +// NOTE: uses btc client with zmq +func StartManager(t *testing.T, numMatureOutputsInWallet uint32) *TestManager { + btcHandler := NewBitcoindHandler(t) + btcHandler.Start() + passphrase := "pass" + _ = btcHandler.CreateWallet("default", passphrase) + blocksResponse := btcHandler.GenerateBlocks(int(numMatureOutputsInWallet)) - miner, err := rpctest.New(netParams, handlers, args, "") - require.NoError(t, err) + cfg := defaultVigilanteConfig() - privkey, _, err := GetSpendingKeyAndAddress(uint32(numTestInstances)) + testRpcClient, err := rpcclient.New(&rpcclient.ConnConfig{ + Host: cfg.BTC.Endpoint, + User: cfg.BTC.Username, + Pass: cfg.BTC.Password, + DisableTLS: true, + DisableConnectOnNew: true, + DisableAutoReconnect: false, + HTTPPostMode: true, + }, nil) require.NoError(t, err) - if err := miner.SetUp(true, numMatureOutputsInWallet); err != nil { - t.Fatalf("unable to set up mining node: %v", err) - } + btcClient := initBTCClientWithSubscriber(t, cfg) - minerNodeRpcConfig := miner.RPCConfig() - certFile := minerNodeRpcConfig.Certificates - - currentDir, err := os.Getwd() + var buff bytes.Buffer + err = regtestParams.GenesisBlock.Header.Serialize(&buff) require.NoError(t, err) - walletPath := filepath.Join(currentDir, existingWalletFile) + baseHeaderHex := hex.EncodeToString(buff.Bytes()) - // start Bitcoin wallet - wh, err := NewWalletHandler(certFile, walletPath, minerNodeRpcConfig.Host) - require.NoError(t, err) - err = wh.Start() + minerAddressDecoded, err := btcutil.DecodeAddress(blocksResponse.Address, regtestParams) require.NoError(t, err) - // Wait for wallet to re-index the outputs - time.Sleep(5 * time.Second) - - cfg := defaultVigilanteConfig() - cfg.BTC.Endpoint = minerNodeRpcConfig.Host - - var btcClient *btcclient.Client - if handlers.OnFilteredBlockConnected != nil && handlers.OnFilteredBlockDisconnected != nil { - // BTC client with subscriber - btcClient = initBTCClientWithSubscriber(t, cfg, miner.Client, &minerNodeRpcConfig, blockEventChan) - } - // we always want BTC wallet client for sending txs - btcWalletClient := initBTCWalletClient( - t, - cfg, - privkey, - numbersOfOutputsToWaitForDuringInit, - ) - // start Babylon node - bh, err := NewBabylonNodeHandler() + bh, err := NewBabylonNodeHandler(baseHeaderHex, minerAddressDecoded.EncodeAddress()) require.NoError(t, err) err = bh.Start() require.NoError(t, err) + // create Babylon client cfg.Babylon.KeyDirectory = bh.GetNodeDataDir() - cfg.Babylon.Key = "test-spending-key" + cfg.Babylon.Key = "test-spending-key" // keyring to bbn node cfg.Babylon.GasAdjustment = 3.0 + babylonClient, err := bbnclient.New(&cfg.Babylon, nil) require.NoError(t, err) + // wait until Babylon is ready require.Eventually(t, func() bool { resp, err := babylonClient.CurrentEpoch() @@ -274,82 +136,60 @@ func StartManager( return true }, eventuallyWaitTimeOut, eventuallyPollTime) - numTestInstances++ + err = testRpcClient.WalletPassphrase(passphrase, 600) + require.NoError(t, err) + + walletPrivKey, err := testRpcClient.DumpPrivKey(minerAddressDecoded) + require.NoError(t, err) return &TestManager{ - MinerNode: miner, - BtcWalletHandler: wh, - BabylonHandler: bh, - BabylonClient: babylonClient, - BTCClient: btcClient, - BTCWalletClient: btcWalletClient, - Config: cfg, + TestRpcClient: testRpcClient, + BabylonHandler: bh, + BabylonClient: babylonClient, + BitcoindHandler: btcHandler, + BTCClient: btcClient, + Config: cfg, + WalletPrivKey: walletPrivKey.PrivKey, } } func (tm *TestManager) Stop(t *testing.T) { - err := tm.BtcWalletHandler.Stop() - require.NoError(t, err) - err = tm.MinerNode.TearDown() + err := tm.BabylonHandler.Stop() require.NoError(t, err) + if tm.BabylonClient.IsRunning() { - err = tm.BabylonClient.Stop() + err := tm.BabylonClient.Stop() require.NoError(t, err) } - err = tm.BabylonHandler.Stop() - require.NoError(t, err) } -func ImportWalletSpendingKey( - t *testing.T, - walletClient *btcclient.Client, - privKey *btcec.PrivateKey) error { +// mineBlock mines a single block +func (tm *TestManager) mineBlock(t *testing.T) *wire.MsgBlock { + resp := tm.BitcoindHandler.GenerateBlocks(1) - wifKey, err := btcutil.NewWIF(privKey, netParams, true) + hash, err := chainhash.NewHashFromStr(resp.Blocks[0]) require.NoError(t, err) - err = walletClient.WalletPassphrase(exisitngWalletPass, int64(walletTimeout)) - - if err != nil { - return err - } - - err = walletClient.ImportPrivKey(wifKey) - - if err != nil { - return err - } - - return nil -} - -// MineBlocksWithTxes mines a single block to include the specifies -// transactions only. -func (tm *TestManager) MineBlockWithTxs(t *testing.T, txs []*btcutil.Tx) *wire.MsgBlock { - var emptyTime time.Time - - // Generate a block. - b, err := tm.MinerNode.GenerateAndSubmitBlock(txs, -1, emptyTime) - require.NoError(t, err, "unable to mine block") - - block, err := tm.MinerNode.Client.GetBlock(b.Hash()) - require.NoError(t, err, "unable to get block") + header, err := tm.TestRpcClient.GetBlock(hash) + require.NoError(t, err) - return block + return header } func (tm *TestManager) MustGetBabylonSigner() string { return tm.BabylonClient.MustGetAddr() } +// RetrieveTransactionFromMempool fetches transactions from the mempool for the given hashes func (tm *TestManager) RetrieveTransactionFromMempool(t *testing.T, hashes []*chainhash.Hash) []*btcutil.Tx { - var txes []*btcutil.Tx + var txs []*btcutil.Tx for _, txHash := range hashes { tx, err := tm.BTCClient.GetRawTransaction(txHash) require.NoError(t, err) - txes = append(txes, tx) + txs = append(txs, tx) } - return txes + + return txs } func (tm *TestManager) InsertBTCHeadersToBabylon(headers []*wire.BlockHeader) (*pv.RelayerTxResponse, error) { @@ -368,18 +208,18 @@ func (tm *TestManager) InsertBTCHeadersToBabylon(headers []*wire.BlockHeader) (* } func (tm *TestManager) CatchUpBTCLightClient(t *testing.T) { - _, btcHeight, err := tm.MinerNode.Client.GetBestBlock() + btcHeight, err := tm.TestRpcClient.GetBlockCount() require.NoError(t, err) tipResp, err := tm.BabylonClient.BTCHeaderChainTip() require.NoError(t, err) btclcHeight := tipResp.Header.Height - headers := []*wire.BlockHeader{} + var headers []*wire.BlockHeader for i := int(btclcHeight + 1); i <= int(btcHeight); i++ { - hash, err := tm.MinerNode.Client.GetBlockHash(int64(i)) + hash, err := tm.TestRpcClient.GetBlockHash(int64(i)) require.NoError(t, err) - header, err := tm.MinerNode.Client.GetBlockHeader(hash) + header, err := tm.TestRpcClient.GetBlockHeader(hash) require.NoError(t, err) headers = append(headers, header) } @@ -387,15 +227,3 @@ func (tm *TestManager) CatchUpBTCLightClient(t *testing.T) { _, err = tm.InsertBTCHeadersToBabylon(headers) require.NoError(t, err) } - -func waitForNOutputs(t *testing.T, walletClient *btcclient.Client, n int) { - require.Eventually(t, func() bool { - outputs, err := walletClient.ListUnspent() - - if err != nil { - return false - } - - return len(outputs) >= n - }, eventuallyWaitTimeOut, eventuallyPollTime) -} diff --git a/e2etest/test_manager_btcstaking.go b/e2etest/test_manager_btcstaking.go index a780aa77..579a5eea 100644 --- a/e2etest/test_manager_btcstaking.go +++ b/e2etest/test_manager_btcstaking.go @@ -93,23 +93,20 @@ func (tm *TestManager) CreateBTCDelegation( require.NoError(t, err) stakingTimeBlocks := uint16(math.MaxUint16) // get top UTXO - topUnspentResult, _, err := tm.BTCWalletClient.GetHighUTXOAndSum() + topUnspentResult, _, err := tm.BTCClient.GetHighUTXOAndSum() require.NoError(t, err) - topUTXO, err := types.NewUTXO(topUnspentResult, netParams) + topUTXO, err := types.NewUTXO(topUnspentResult, regtestParams) require.NoError(t, err) // staking value stakingValue := int64(topUTXO.Amount) / 3 - // dump SK - wif, err := tm.BTCWalletClient.DumpPrivKey(topUTXO.Addr) - require.NoError(t, err) // generate legitimate BTC del stakingSlashingInfo := datagen.GenBTCStakingSlashingInfoWithOutPoint( r, t, - netParams, + regtestParams, topUTXO.GetOutPoint(), - wif.PrivKey, + tm.WalletPrivKey, []*btcec.PublicKey{fpPK}, covenantBtcPks, bsParams.Params.CovenantQuorum, @@ -121,7 +118,7 @@ func (tm *TestManager) CreateBTCDelegation( ) // sign staking tx and overwrite the staking tx to the signed version // NOTE: the tx hash has changed here since stakingMsgTx is pre-segwit - stakingMsgTx, signed, err := tm.BTCWalletClient.SignRawTransaction(stakingSlashingInfo.StakingTx) + stakingMsgTx, signed, err := tm.BTCClient.SignRawTransactionWithWallet(stakingSlashingInfo.StakingTx) require.NoError(t, err) require.True(t, signed) // overwrite staking tx @@ -140,12 +137,16 @@ func (tm *TestManager) CreateBTCDelegation( require.NoError(t, err) // send staking tx to Bitcoin node's mempool - _, err = tm.BTCWalletClient.SendRawTransaction(stakingMsgTx, true) + _, err = tm.BTCClient.SendRawTransaction(stakingMsgTx, true) require.NoError(t, err) - // mine a block with this tx, and insert it to Bitcoin / Babylon - mBlock := tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{stakingMsgTxHash})) + require.Eventually(t, func() bool { + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{stakingMsgTxHash})) == 1 + }, eventuallyWaitTimeOut, eventuallyPollTime) + + mBlock := tm.mineBlock(t) require.Equal(t, 2, len(mBlock.Transactions)) + // wait until staking tx is on Bitcoin require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(stakingMsgTxHash) @@ -159,14 +160,15 @@ func (tm *TestManager) CreateBTCDelegation( require.NoError(t, err) btccParams := btccParamsResp.Params for i := 0; i < int(btccParams.BtcConfirmationDepth); i++ { - tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{})) + //tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{})) + tm.mineBlock(t) } stakingOutIdx, err := outIdx(stakingSlashingInfo.StakingTx, stakingSlashingInfo.StakingInfo.StakingOutput) require.NoError(t, err) // create PoP - pop, err := bstypes.NewPoPBTC(addr, wif.PrivKey) + pop, err := bstypes.NewPoPBTC(addr, tm.WalletPrivKey) require.NoError(t, err) slashingSpendPath, err := stakingSlashingInfo.StakingInfo.SlashingPathSpendInfo() require.NoError(t, err) @@ -176,7 +178,7 @@ func (tm *TestManager) CreateBTCDelegation( stakingMsgTx, stakingOutIdx, slashingSpendPath.GetPkScriptPath(), - wif.PrivKey, + tm.WalletPrivKey, ) require.NoError(t, err) @@ -186,8 +188,8 @@ func (tm *TestManager) CreateBTCDelegation( unbondingSlashingInfo := datagen.GenBTCUnbondingSlashingInfo( r, t, - netParams, - wif.PrivKey, + regtestParams, + tm.WalletPrivKey, []*btcec.PublicKey{fpPK}, covenantBtcPks, bsParams.Params.CovenantQuorum, @@ -208,7 +210,7 @@ func (tm *TestManager) CreateBTCDelegation( unbondingSlashingInfo.UnbondingTx, 0, // Only one output in the unbonding tx unbondingSlashingPathSpendInfo.GetPkScriptPath(), - wif.PrivKey, + tm.WalletPrivKey, ) require.NoError(t, err) @@ -219,7 +221,7 @@ func (tm *TestManager) CreateBTCDelegation( msgBTCDel := &bstypes.MsgCreateBTCDelegation{ StakerAddr: signerAddr, Pop: pop, - BtcPk: bbn.NewBIP340PubKeyFromBTCPK(wif.PrivKey.PubKey()), + BtcPk: bbn.NewBIP340PubKeyFromBTCPK(tm.WalletPrivKey.PubKey()), FpBtcPkList: []bbn.BIP340PubKey{*bbn.NewBIP340PubKeyFromBTCPK(fpPK)}, StakingTime: uint32(stakingTimeBlocks), StakingValue: stakingValue, @@ -288,7 +290,7 @@ func (tm *TestManager) CreateBTCDelegation( require.NoError(t, err) t.Logf("submitted covenant signature") - return stakingSlashingInfo, unbondingSlashingInfo, wif.PrivKey + return stakingSlashingInfo, unbondingSlashingInfo, tm.WalletPrivKey } func (tm *TestManager) Undelegate( @@ -334,16 +336,22 @@ func (tm *TestManager) Undelegate( unbondingSlashingInfo.UnbondingTx.TxIn[0].Witness = witness // send unbonding tx to Bitcoin node's mempool - unbondingTxHash, err := tm.BTCWalletClient.SendRawTransaction(unbondingSlashingInfo.UnbondingTx, true) + unbondingTxHash, err := tm.BTCClient.SendRawTransaction(unbondingSlashingInfo.UnbondingTx, true) require.NoError(t, err) require.Eventually(t, func() bool { _, err := tm.BTCClient.GetRawTransaction(unbondingTxHash) return err == nil }, eventuallyWaitTimeOut, eventuallyPollTime) t.Logf("submitted unbonding tx with hash %s", unbondingTxHash.String()) + // mine a block with this tx, and insert it to Bitcoin - mBlock := tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingTxHash})) + require.Eventually(t, func() bool { + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{unbondingTxHash})) == 1 + }, eventuallyWaitTimeOut, eventuallyPollTime) + + mBlock := tm.mineBlock(t) require.Equal(t, 2, len(mBlock.Transactions)) + // wait until unbonding tx is on Bitcoin require.Eventually(t, func() bool { resp, err := tm.BTCClient.GetRawTransactionVerbose(unbondingTxHash) diff --git a/e2etest/unbondingwatcher_e2e_test.go b/e2etest/unbondingwatcher_e2e_test.go index 53ef2fcf..fc60c51f 100644 --- a/e2etest/unbondingwatcher_e2e_test.go +++ b/e2etest/unbondingwatcher_e2e_test.go @@ -4,7 +4,7 @@ package e2etest import ( - "encoding/hex" + "go.uber.org/zap" "testing" "time" @@ -13,13 +13,9 @@ import ( bst "github.com/babylonlabs-io/vigilante/btcstaking-tracker" "github.com/babylonlabs-io/vigilante/config" "github.com/babylonlabs-io/vigilante/metrics" - "github.com/babylonlabs-io/vigilante/types" "github.com/btcsuite/btcd/btcec/v2/schnorr" - "github.com/btcsuite/btcd/btcutil" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" - "github.com/btcsuite/btcd/rpcclient" - "github.com/btcsuite/btcd/wire" "github.com/stretchr/testify/require" ) @@ -27,28 +23,7 @@ func TestUnbondingWatcher(t *testing.T) { // segwit is activated at height 300. It's needed by staking/slashing tx numMatureOutputs := uint32(300) - submittedTxs := []*chainhash.Hash{} - blockEventChan := make(chan *types.BlockEvent, 1000) - handlers := &rpcclient.NotificationHandlers{ - OnFilteredBlockConnected: func(height int32, header *wire.BlockHeader, txs []*btcutil.Tx) { - log.Debugf("Block %v at height %d has been connected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockConnected, height, header) - }, - OnFilteredBlockDisconnected: func(height int32, header *wire.BlockHeader) { - log.Debugf("Block %v at height %d has been disconnected at time %v", header.BlockHash(), height, header.Timestamp) - blockEventChan <- types.NewBlockEvent(types.BlockDisconnected, height, header) - }, - OnTxAccepted: func(hash *chainhash.Hash, amount btcutil.Amount) { - submittedTxs = append(submittedTxs, hash) - }, - } - - tm := StartManager(t, numMatureOutputs, 2, handlers, blockEventChan) - // this is necessary to receive notifications about new transactions entering mempool - err := tm.MinerNode.Client.NotifyNewTransactions(false) - require.NoError(t, err) - err = tm.MinerNode.Client.NotifyBlocks() - require.NoError(t, err) + tm := StartManager(t, numMatureOutputs) defer tm.Stop(t) // Insert all existing BTC headers to babylon node tm.CatchUpBTCLightClient(t) @@ -58,8 +33,8 @@ func TestUnbondingWatcher(t *testing.T) { // TODO: our config only support btcd wallet tls, not btcd directly tm.Config.BTC.DisableClientTLS = false backend, err := btcclient.NewNodeBackend( - btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, hex.EncodeToString(tm.MinerNode.RPCConfig().Certificates)), - &chaincfg.SimNetParams, + btcclient.CfgToBtcNodeBackendConfig(tm.Config.BTC, ""), + &chaincfg.RegressionNetParams, &emptyHintCache, ) require.NoError(t, err) @@ -70,10 +45,7 @@ func TestUnbondingWatcher(t *testing.T) { commonCfg := config.DefaultCommonConfig() bstCfg := config.DefaultBTCStakingTrackerConfig() bstCfg.CheckDelegationsInterval = 1 * time.Second - logger, err := config.NewRootLogger("auto", "debug") - require.NoError(t, err) - - metrics := metrics.NewBTCStakingTrackerMetrics() + stakingTrackerMetrics := metrics.NewBTCStakingTrackerMetrics() bsTracker := bst.NewBTCSTakingTracker( tm.BTCClient, @@ -81,24 +53,23 @@ func TestUnbondingWatcher(t *testing.T) { tm.BabylonClient, &bstCfg, &commonCfg, - logger, - metrics, + zap.NewNop(), + stakingTrackerMetrics, ) bsTracker.Start() defer bsTracker.Stop() // set up a finality provider _, fpSK := tm.CreateFinalityProvider(t) - logger.Info("created finality provider") // set up a BTC delegation stakingSlashingInfo, unbondingSlashingInfo, delSK := tm.CreateBTCDelegation(t, fpSK) - logger.Info("created BTC delegation") // Staker unbonds by directly sending tx to btc network. Watcher should detect it and report to babylon. unbondingPathSpendInfo, err := stakingSlashingInfo.StakingInfo.UnbondingPathSpendInfo() require.NoError(t, err) stakingOutIdx, err := outIdx(unbondingSlashingInfo.UnbondingTx, unbondingSlashingInfo.UnbondingInfo.UnbondingOutput) require.NoError(t, err) + unbondingTxSchnorrSig, err := btcstaking.SignTxWithOneScriptSpendInputStrict( unbondingSlashingInfo.UnbondingTx, stakingSlashingInfo.StakingTx, @@ -107,22 +78,30 @@ func TestUnbondingWatcher(t *testing.T) { delSK, ) require.NoError(t, err) + resp, err := tm.BabylonClient.BTCDelegation(stakingSlashingInfo.StakingTx.TxHash().String()) require.NoError(t, err) + covenantSigs := resp.BtcDelegation.UndelegationResponse.CovenantUnbondingSigList witness, err := unbondingPathSpendInfo.CreateUnbondingPathWitness( []*schnorr.Signature{covenantSigs[0].Sig.MustToBTCSig()}, unbondingTxSchnorrSig, ) unbondingSlashingInfo.UnbondingTx.TxIn[0].Witness = witness + // Send unbonding tx to Bitcoin - _, err = tm.BTCWalletClient.SendRawTransaction(unbondingSlashingInfo.UnbondingTx, true) + _, err = tm.BTCClient.SendRawTransaction(unbondingSlashingInfo.UnbondingTx, true) require.NoError(t, err) + // mine a block with this tx, and insert it to Bitcoin unbondingTxHash := unbondingSlashingInfo.UnbondingTx.TxHash() t.Logf("submitted unbonding tx with hash %s", unbondingTxHash.String()) - mBlock := tm.MineBlockWithTxs(t, tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{&unbondingTxHash})) - require.Equal(t, 2, len(mBlock.Transactions)) + require.Eventually(t, func() bool { + return len(tm.RetrieveTransactionFromMempool(t, []*chainhash.Hash{&unbondingTxHash})) == 1 + }, eventuallyWaitTimeOut, eventuallyPollTime) + + minedBlock := tm.mineBlock(t) + require.Equal(t, 2, len(minedBlock.Transactions)) require.Eventually(t, func() bool { resp, err := tm.BabylonClient.BTCDelegation(stakingSlashingInfo.StakingTx.TxHash().String()) diff --git a/go.mod b/go.mod index ee3c7c95..fc04e971 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ require ( github.com/jinzhu/copier v0.3.5 github.com/jsternberg/zap-logfmt v1.3.0 github.com/lightningnetwork/lnd v0.16.4-beta.rc1 + github.com/ory/dockertest/v3 v3.9.1 github.com/pebbe/zmq4 v1.2.9 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.0 @@ -63,10 +64,13 @@ require ( cosmossdk.io/x/upgrade v0.1.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/keyring v1.2.1 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/CosmWasm/wasmd v0.51.0 // indirect github.com/CosmWasm/wasmvm/v2 v2.0.1 // 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/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // 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 @@ -93,6 +97,7 @@ require ( github.com/cometbft/cometbft-db v0.9.1 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect + github.com/containerd/continuity v0.3.0 // indirect github.com/coreos/go-semver v0.3.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect @@ -119,7 +124,10 @@ require ( github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/distribution/reference v0.5.0 // indirect + github.com/docker/cli v23.0.1+incompatible // indirect github.com/docker/docker v23.0.8+incompatible // indirect + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.6.0 // indirect @@ -148,6 +156,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/s2a-go v0.1.7 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect @@ -172,6 +181,7 @@ require ( github.com/holiman/uint256 v1.2.4 // indirect github.com/huandu/skiplist v1.2.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect + github.com/imdario/mergo v0.3.13 // indirect github.com/improbable-eng/grpc-web v0.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect @@ -220,6 +230,7 @@ require ( github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mmcloughlin/addchain v0.4.0 // indirect + github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mtibben/percent v0.2.1 // indirect @@ -227,6 +238,8 @@ require ( github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc2 // indirect + github.com/opencontainers/runc v1.1.5 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pierrec/lz4/v4 v4.1.8 // indirect @@ -259,6 +272,9 @@ require ( 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 + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect github.com/zondax/hid v0.9.2 // indirect diff --git a/go.sum b/go.sum index 32b26993..27d54b94 100644 --- a/go.sum +++ b/go.sum @@ -361,6 +361,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= @@ -371,6 +372,7 @@ github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObk github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -412,6 +414,7 @@ github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/Yj github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= @@ -422,6 +425,7 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -469,6 +473,9 @@ github.com/creachadair/tomledit v0.0.24 h1:5Xjr25R2esu1rKCbQEmjZYlrhFkDspoAbAKb6 github.com/creachadair/tomledit v0.0.24/go.mod h1:9qHbShRWQzSCcn617cMzg4eab1vbLCOjOshAWSzWr8U= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= @@ -498,10 +505,13 @@ github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WA github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM= +github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v23.0.8+incompatible h1:z4ZCIwfqHgOEwhxmAWugSL1PFtPQmLP60EVhJYJPaX8= github.com/docker/docker v23.0.8+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q= @@ -549,6 +559,7 @@ github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8 github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -601,6 +612,8 @@ github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJWXmqUsHwfTRRkQ= github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= +github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= @@ -614,6 +627,7 @@ github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/E github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -724,6 +738,8 @@ github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10/go.mod h1:79YE0hCXdHa github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -837,6 +853,8 @@ github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSAS github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/improbable-eng/grpc-web v0.15.0 h1:BN+7z6uNXZ1tQGcNAuaU1YjsLTApzkjt2tzCixLaUPQ= github.com/improbable-eng/grpc-web v0.15.0/go.mod h1:1sy9HKV4Jt9aEs9JSnkWlRJPuPtwNr0l57L4f878wP8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= @@ -950,6 +968,7 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -1059,6 +1078,9 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587 h1:HfkjXDfhgVaN5rmueG8cL8KKeFNecRCXFhaJ2qZ5SKA= +github.com/moby/term v0.0.0-20221205130635-1aeaba878587/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1066,6 +1088,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1118,6 +1141,8 @@ github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7X github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs= github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1128,6 +1153,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= +github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= +github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -1228,6 +1255,7 @@ github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71e github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= 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/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -1239,6 +1267,7 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -1299,6 +1328,7 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4= github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= @@ -1329,8 +1359,17 @@ github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vulpine-io/io-test v1.0.0 h1:Ot8vMh+ssm1VWDAwJ3U4C5qG9aRnr5YfQFZPNZBAUGI= github.com/vulpine-io/io-test v1.0.0/go.mod h1:X1I+p5GCxVX9m4nFd1HBtr2bVX9v1ZE6x8w+Obt36AU= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -1525,6 +1564,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= @@ -1609,6 +1649,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1619,6 +1660,7 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w 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= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1650,6 +1692,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1668,9 +1711,11 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2067,6 +2112,7 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/tools/go.mod b/tools/go.mod index 577a04bf..09da8089 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -6,8 +6,6 @@ toolchain go1.21.4 require ( github.com/babylonlabs-io/babylon v0.9.1 - github.com/btcsuite/btcd v0.24.2 - github.com/btcsuite/btcwallet v0.16.9 ) require ( diff --git a/tools/tools.go b/tools/tools.go index 54f759ac..01550773 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -5,6 +5,4 @@ package vigilante import ( _ "github.com/babylonlabs-io/babylon/cmd/babylond" - _ "github.com/btcsuite/btcd" - _ "github.com/btcsuite/btcwallet" )