diff --git a/Makefile b/Makefile index 32eaca44..80e5537a 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,7 @@ test: test-e2e: cd $(TOOLS_DIR); go install -trimpath $(BABYLON_PKG); - go test -race -mod=readonly -timeout=25m -v $(PACKAGES_E2E) -count=1 --tags=e2e + go test -race -mod=readonly --failfast -timeout=25m -v $(PACKAGES_E2E) -count=1 --tags=e2e build-docker: $(DOCKER) build --tag babylonlabs-io/vigilante -f Dockerfile \ diff --git a/e2etest/bitcoind_node_setup.go b/e2etest/bitcoind_node_setup.go index 1e5b135d..7a7a0969 100644 --- a/e2etest/bitcoind_node_setup.go +++ b/e2etest/bitcoind_node_setup.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "github.com/babylonlabs-io/vigilante/e2etest/container" + "github.com/ory/dockertest/v3" "github.com/stretchr/testify/require" "os" "strconv" @@ -40,7 +41,7 @@ func NewBitcoindHandler(t *testing.T, manager *container.Manager) *BitcoindTestH } } -func (h *BitcoindTestHandler) Start() { +func (h *BitcoindTestHandler) Start(t *testing.T) *dockertest.Resource { tempPath, err := os.MkdirTemp("", "vigilante-test-*") require.NoError(h.t, err) @@ -48,7 +49,7 @@ func (h *BitcoindTestHandler) Start() { _ = os.RemoveAll(tempPath) }) - _, err = h.m.RunBitcoindResource(tempPath) + bitcoinResource, err := h.m.RunBitcoindResource(t, tempPath) require.NoError(h.t, err) h.t.Cleanup(func() { @@ -62,6 +63,8 @@ func (h *BitcoindTestHandler) Start() { } return err == nil }, startTimeout, 500*time.Millisecond, "bitcoind did not start") + + return bitcoinResource } // GetBlockCount retrieves the current number of blocks in the blockchain from the Bitcoind. @@ -112,3 +115,7 @@ func (h *BitcoindTestHandler) ImportDescriptors(descriptor string) { _, _, err := h.m.ExecBitcoindCliCmd(h.t, []string{"importdescriptors", descriptor}) require.NoError(h.t, err) } + +func (h *BitcoindTestHandler) Stop() { + _ = h.m.ClearResources() +} diff --git a/e2etest/container/config.go b/e2etest/container/config.go index 9caea79d..f37297f9 100644 --- a/e2etest/container/config.go +++ b/e2etest/container/config.go @@ -13,8 +13,8 @@ type ImageConfig struct { const ( dockerBitcoindRepository = "lncm/bitcoind" dockerBitcoindVersionTag = "v27.0" - dockerBabylondRepository = "babylonlabs/babylond" - dockerBabylondVersionTag = "b834df27bec4331b4962cdec85f71a5cff51bfa8" + dockerBabylondRepository = "babylonlabs-io/babylond" + dockerBabylondVersionTag = "latest" // todo(Lazar): we need version b1e255a ) // NewImageConfig returns ImageConfig needed for running e2e test. diff --git a/e2etest/container/container.go b/e2etest/container/container.go index c3857c2a..5aad54f3 100644 --- a/e2etest/container/container.go +++ b/e2etest/container/container.go @@ -6,7 +6,10 @@ import ( "fmt" bbn "github.com/babylonlabs-io/babylon/types" "github.com/btcsuite/btcd/btcec/v2" + "github.com/cometbft/cometbft/libs/rand" + "net" "regexp" + "strconv" "testing" "time" @@ -48,6 +51,7 @@ func NewManager() (docker *Manager, err error) { if err != nil { return nil, err } + return docker, nil } @@ -131,7 +135,9 @@ func (m *Manager) ExecCmd(t *testing.T, containerName string, command []string) return outBuf, errBuf, nil } +// RunBitcoindResource starts a bitcoind docker container func (m *Manager) RunBitcoindResource( + t *testing.T, bitcoindCfgPath string, ) (*dockertest.Resource, error) { bitcoindResource, err := m.pool.RunWithOptions( @@ -143,14 +149,6 @@ func (m *Manager) RunBitcoindResource( Mounts: []string{ fmt.Sprintf("%s/:/data/.bitcoin", bitcoindCfgPath), }, - ExposedPorts: []string{ - "8332", - "8333", - "28332", - "28333", - "18443", - "18444", - }, Cmd: []string{ "-regtest", "-txindex", @@ -164,12 +162,12 @@ func (m *Manager) RunBitcoindResource( }, func(config *docker.HostConfig) { config.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"}}, + "8332/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "8333/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "28332/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "28333/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "18443/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "18444/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, } }, noRestart, @@ -181,7 +179,9 @@ func (m *Manager) RunBitcoindResource( return bitcoindResource, nil } +// RunBabylondResource starts a babylond container func (m *Manager) RunBabylondResource( + t *testing.T, mounthPath string, baseHeaderHex string, slashingPkScript string, @@ -210,21 +210,23 @@ func (m *Manager) RunBabylondResource( Mounts: []string{ fmt.Sprintf("%s/:/home/", mounthPath), }, - Cmd: cmd, ExposedPorts: []string{ - "26656", - "26657", "1317", - "9090", "2345", + "9090", + "26656", + "26657", }, - PortBindings: map[docker.Port][]docker.PortBinding{ - "1317/tcp": {{HostIP: "", HostPort: "1317"}}, - "2345/tcp": {{HostIP: "", HostPort: "2345"}}, - "9090/tcp": {{HostIP: "", HostPort: "9090"}}, - "26656/tcp": {{HostIP: "", HostPort: "26656"}}, - "26657/tcp": {{HostIP: "", HostPort: "26657"}}, - }, + Cmd: cmd, + }, + func(config *docker.HostConfig) { + config.PortBindings = map[docker.Port][]docker.PortBinding{ + "1317/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "2345/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "9090/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "26656/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + "26657/tcp": {{HostIP: "", HostPort: strconv.Itoa(randomAvailablePort(t))}}, + } }, noRestart, ) @@ -240,8 +242,9 @@ func (m *Manager) RunBabylondResource( // ClearResources removes all outstanding Docker resources created by the Manager. func (m *Manager) ClearResources() error { for _, resource := range m.resources { + fmt.Printf("cleaning %s\n", resource.Container.Name) if err := m.pool.Purge(resource); err != nil { - return err + continue } } @@ -254,3 +257,36 @@ func noRestart(config *docker.HostConfig) { Name: "no", } } + +// randomAvailablePort tries to find an available TCP port on the localhost +// by testing multiple random ports within a specified range. +func randomAvailablePort(t *testing.T) int { + randPort := func(base, spread int) int { + return base + rand.Intn(spread) + } + + // Base port and spread range for port selection + const ( + basePort = 20000 + portRange = 10000 + ) + + // Seed the random number generator to ensure randomness + rand.Seed(time.Now().UnixNano()) + + // Try up to 5 times to find an available port + for i := 0; i < 5; i++ { + port := randPort(basePort, portRange) + address := fmt.Sprintf("127.0.0.1:%d", port) + + listener, err := net.Listen("tcp", address) + if err == nil { + _ = listener.Close() + return port + } + } + + // If no available port was found, fail the test + t.Fatalf("failed to find an available port in range %d-%d", basePort, basePort+portRange) + return 0 +} diff --git a/e2etest/submitter_e2e_test.go b/e2etest/submitter_e2e_test.go index 9034ee37..e8751b78 100644 --- a/e2etest/submitter_e2e_test.go +++ b/e2etest/submitter_e2e_test.go @@ -1,6 +1,7 @@ package e2etest import ( + "fmt" "github.com/babylonlabs-io/vigilante/testutil" "math/rand" "testing" @@ -187,9 +188,10 @@ func TestSubmitterSubmissionReplace(t *testing.T) { func TestSubmitterDocker(t *testing.T) { - numMatureOutputs := uint32(300) + numMatureOutputs := uint32(10) tm := StartManager(t, numMatureOutputs, defaultEpochInterval) defer tm.Stop(t) + fmt.Printf("asdf") } diff --git a/e2etest/test_manager.go b/e2etest/test_manager.go index e0d330ba..8af00104 100644 --- a/e2etest/test_manager.go +++ b/e2etest/test_manager.go @@ -87,12 +87,15 @@ func StartManager(t *testing.T, numMatureOutputsInWallet uint32, epochInterval u require.NoError(t, err) btcHandler := NewBitcoindHandler(t, manager) - btcHandler.Start() + bitcoind := btcHandler.Start(t) passphrase := "pass" _ = btcHandler.CreateWallet("default", passphrase) cfg := defaultVigilanteConfig() + cfg.BTC.Endpoint = fmt.Sprintf("127.0.0.1:%s", bitcoind.GetPort("18443/tcp")) + cfg.BTC.ZmqSeqEndpoint = fmt.Sprintf("tcp:// 127.0.0.1:%s", bitcoind.GetPort("28333/tcp")) + testRpcClient, err := rpcclient.New(&rpcclient.ConnConfig{ Host: cfg.BTC.Endpoint, User: cfg.BTC.Username, @@ -127,7 +130,7 @@ func StartManager(t *testing.T, numMatureOutputsInWallet uint32, epochInterval u // start Babylon node tmpDir := t.TempDir() - babylond, err := manager.RunBabylondResource(tmpDir, baseHeaderHex, hex.EncodeToString(pkScript), epochInterval) + babylond, err := manager.RunBabylondResource(t, tmpDir, baseHeaderHex, hex.EncodeToString(pkScript), epochInterval) require.NoError(t, err) // create Babylon client @@ -163,6 +166,7 @@ func StartManager(t *testing.T, numMatureOutputsInWallet uint32, epochInterval u } func (tm *TestManager) Stop(t *testing.T) { + tm.BitcoindHandler.Stop() if tm.BabylonClient.IsRunning() { err := tm.BabylonClient.Stop() require.NoError(t, err)