Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(e2e): parallel e2e #37

Merged
merged 3 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 6 additions & 9 deletions cmd/stakerd/main.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
package main

import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"runtime/pprof"
"syscall"

"github.com/babylonlabs-io/btc-staker/metrics"
staker "github.com/babylonlabs-io/btc-staker/staker"
scfg "github.com/babylonlabs-io/btc-staker/stakercfg"
service "github.com/babylonlabs-io/btc-staker/stakerservice"

"github.com/jessevdk/go-flags"
"github.com/lightningnetwork/lnd/signal"
)

func main() {
// Hook interceptor for os signals.
shutdownInterceptor, err := signal.Intercept()
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer cancel()

cfg, cfgLogger, zapLogger, err := scfg.LoadConfig()

Expand Down Expand Up @@ -89,15 +88,13 @@ func main() {
cfg,
staker,
cfgLogger,
shutdownInterceptor,
dbBackend,
)

addr := fmt.Sprintf("%s:%d", cfg.MetricsConfig.Host, cfg.MetricsConfig.ServerPort)
metrics.Start(cfgLogger, addr, stakerMetrics.Registry)

err = service.RunUntilShutdown()
if err != nil {
if err = service.RunUntilShutdown(ctx); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
Expand Down
106 changes: 62 additions & 44 deletions itest/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ import (
sdkquerytypes "github.com/cosmos/cosmos-sdk/types/query"
sttypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/signal"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -144,7 +143,6 @@ type TestManager struct {
BabylonClient *babylonclient.BabylonController
WalletPubKey *btcec.PublicKey
MinerAddr btcutil.Address
serverStopper *signal.Interceptor
wg *sync.WaitGroup
serviceAddress string
StakerClient *dc.StakerServiceJsonRpcClient
Expand Down Expand Up @@ -221,6 +219,7 @@ func (td *testStakingData) withStakingAmout(amout int64) *testStakingData {

func StartManager(
t *testing.T,
ctx context.Context,
numMatureOutputsInWallet uint32,
) *TestManager {
manager, err := containers.NewManager(t)
Expand Down Expand Up @@ -321,9 +320,6 @@ func StartManager(
walletPubKey, err := btcec.ParsePubKey(pubKeyBytes)
require.NoError(t, err)

interceptor, err := signal.Intercept()
require.NoError(t, err)

addressString := fmt.Sprintf("127.0.0.1:%d", testutil.AllocateUniquePort(t))
addrPort := netip.MustParseAddrPort(addressString)
address := net.TCPAddrFromAddrPort(addrPort)
Expand All @@ -333,15 +329,14 @@ func StartManager(
cfg,
stakerApp,
logger,
interceptor,
dbbackend,
)

var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := stakerService.RunUntilShutdown()
err := stakerService.RunUntilShutdown(ctx)
if err != nil {
t.Fatalf("Error running server: %v", err)
}
Expand All @@ -359,7 +354,6 @@ func StartManager(
BabylonClient: bl,
WalletPubKey: walletPubKey,
MinerAddr: minerAddressDecoded,
serverStopper: &interceptor,
wg: &wg,
serviceAddress: addressString,
StakerClient: stakerClient,
Expand All @@ -370,28 +364,28 @@ func StartManager(
}
}

func (tm *TestManager) Stop(t *testing.T) {
tm.serverStopper.RequestShutdown()
func (tm *TestManager) Stop(t *testing.T, cancelFunc context.CancelFunc) {
cancelFunc()
tm.wg.Wait()
err := tm.manger.ClearResources()
require.NoError(t, err)
err = os.RemoveAll(tm.Config.DBConfig.DBPath)
require.NoError(t, err)
}

func (tm *TestManager) RestartApp(t *testing.T) {
func (tm *TestManager) RestartApp(t *testing.T, newCtx context.Context, cancelFunc context.CancelFunc) {
// Restart the app with no-op action
tm.RestartAppWithAction(t, func(t *testing.T) {})
tm.RestartAppWithAction(t, newCtx, cancelFunc, func(t *testing.T) {})
}

// RestartAppWithAction:
// 1. Stop the staker app
// 2. Perform provided action. Warning:this action must not use staker app as
// app is stopped at this point
// 3. Start the staker app
func (tm *TestManager) RestartAppWithAction(t *testing.T, action func(t *testing.T)) {
func (tm *TestManager) RestartAppWithAction(t *testing.T, ctx context.Context, cancelFunc context.CancelFunc, action func(t *testing.T)) {
// First stop the app
tm.serverStopper.RequestShutdown()
cancelFunc()
tm.wg.Wait()

// Perform the action
Expand All @@ -408,30 +402,25 @@ func (tm *TestManager) RestartAppWithAction(t *testing.T, action func(t *testing
stakerApp, err := staker.NewStakerAppFromConfig(tm.Config, logger, zapLogger, dbbackend, m)
require.NoError(t, err)

interceptor, err := signal.Intercept()
require.NoError(t, err)

service := service.NewStakerService(
tm.Config,
stakerApp,
logger,
interceptor,
dbbackend,
)

var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
err := service.RunUntilShutdown()
err := service.RunUntilShutdown(ctx)
if err != nil {
t.Fatalf("Error running server: %v", err)
}
}()
// Wait for the server to start
time.Sleep(3 * time.Second)

tm.serverStopper = &interceptor
tm.wg = &wg
tm.Db = dbbackend
tm.Sa = stakerApp
Expand Down Expand Up @@ -1110,9 +1099,11 @@ func (tm *TestManager) insertCovenantSigForDelegation(t *testing.T, btcDel *btcs
}

func TestStakingFailures(t *testing.T) {
t.Parallel()
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1146,12 +1137,14 @@ func TestStakingFailures(t *testing.T) {
}

func TestSendingStakingTransaction(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1220,12 +1213,14 @@ func TestSendingStakingTransaction(t *testing.T) {
}

func TestMultipleWithdrawableStakingTransactions(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1286,12 +1281,14 @@ func TestMultipleWithdrawableStakingTransactions(t *testing.T) {
}

func TestSendingWatchedStakingTransaction(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand All @@ -1308,12 +1305,14 @@ func TestSendingWatchedStakingTransaction(t *testing.T) {
}

func TestRestartingTxNotDeepEnough(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand All @@ -1325,20 +1324,24 @@ func TestRestartingTxNotDeepEnough(t *testing.T) {
tm.createAndRegisterFinalityProviders(t, testStakingData)
txHash := tm.sendStakingTxBTC(t, testStakingData)

newCtx, newCancel := context.WithCancel(context.Background())
defer newCancel()
// restart app when tx is not deep enough
tm.RestartApp(t)
tm.RestartApp(t, newCtx, cancel)

go tm.mineNEmptyBlocks(t, params.ConfirmationTimeBlocks, true)
tm.waitForStakingTxState(t, txHash, proto.TransactionState_SENT_TO_BABYLON)
}

func TestRestartingTxNotOnBabylon(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand All @@ -1362,8 +1365,10 @@ func TestRestartingTxNotOnBabylon(t *testing.T) {
tm.waitForStakingTxState(t, txHash, proto.TransactionState_CONFIRMED_ON_BTC)
}

newCtx, newCancel := context.WithCancel(context.Background())
defer newCancel()
// restart app, tx is confirmed but not delivered to babylon
tm.RestartApp(t)
tm.RestartApp(t, newCtx, cancel)

// send headers to babylon, so that we can send delegation tx
go tm.sendHeadersToBabylon(t, minedBlocks)
Expand All @@ -1374,12 +1379,14 @@ func TestRestartingTxNotOnBabylon(t *testing.T) {
}

func TestStakingUnbonding(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1445,12 +1452,14 @@ func TestStakingUnbonding(t *testing.T) {
}

func TestUnbondingRestartWaitingForSignatures(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand All @@ -1468,8 +1477,10 @@ func TestUnbondingRestartWaitingForSignatures(t *testing.T) {
tm.waitForStakingTxState(t, txHash, proto.TransactionState_SENT_TO_BABYLON)
require.NoError(t, err)

newCtx, newCancel := context.WithCancel(context.Background())
defer newCancel()
// restart app, tx was sent to babylon but we did not receive covenant signatures yet
tm.RestartApp(t)
tm.RestartApp(t, newCtx, cancel)

pend, err := tm.BabylonClient.QueryPendingBTCDelegations()
require.NoError(t, err)
Expand Down Expand Up @@ -1624,12 +1635,14 @@ func TestBitcoindWalletBip322Signing(t *testing.T) {
}

func TestSendingStakingTransaction_Restaking(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1664,12 +1677,14 @@ func TestSendingStakingTransaction_Restaking(t *testing.T) {
}

func TestRecoverAfterRestartDuringWithdrawal(t *testing.T) {
t.Parallel()
// need to have at least 300 block on testnet as only then segwit is activated.
// Mature output is out which has 100 confirmations, which means 200mature outputs
// will generate 300 blocks
numMatureOutputs := uint32(200)
tm := StartManager(t, numMatureOutputs)
defer tm.Stop(t)
ctx, cancel := context.WithCancel(context.Background())
tm := StartManager(t, ctx, numMatureOutputs)
defer tm.Stop(t, cancel)
tm.insertAllMinedBlocksToBabylon(t)

cl := tm.Sa.BabylonController()
Expand Down Expand Up @@ -1722,7 +1737,10 @@ func TestRecoverAfterRestartDuringWithdrawal(t *testing.T) {
return true
}, 1*time.Minute, eventuallyPollTime)

tm.RestartAppWithAction(t, func(t *testing.T) {
ctxAfter, cancelAfter := context.WithCancel(context.Background())
defer cancelAfter()

tm.RestartAppWithAction(t, ctxAfter, cancel, func(t *testing.T) {
// unbodning tx got confirmed during the stop period
_ = tm.mineNEmptyBlocks(t, staker.UnbondingTxConfirmations+1, false)
})
Expand Down
Loading
Loading