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

Improve integration tests #156

Merged
merged 3 commits into from
Oct 4, 2022
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
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- run: # sudo is needed, so that integration test binary have proper access to nodes keyring
name: Run integration tests
command: |
make localnet-start
make localnet-start-test
sudo -E env "PATH=$PATH" make test-babylon-integration
make localnet-stop

Expand Down
16 changes: 14 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -443,16 +443,28 @@ localnet-build-env:
localnet-build-dlv:
$(MAKE) -C contrib/images babylond-dlv

localnet-build-nodes-test:
$(DOCKER) run --rm -v $(CURDIR)/.testnets:/data babylonchain/babylond \
testnet init-files --v 4 -o /data \
--starting-ip-address 192.168.10.2 --keyring-backend=test \
--chain-id chain-test --btc-confirmation-depth 2 --additional-sender-account true \
--epoch-interval 5
docker-compose up -d

localnet-build-nodes:
$(DOCKER) run --rm -v $(CURDIR)/.testnets:/data babylonchain/babylond \
testnet init-files --v 4 -o /data \
--starting-ip-address 192.168.10.2 --keyring-backend=test \
--chain-id chain-test --btc-confirmation-depth 2
--chain-id chain-test
docker-compose up -d

# localnet-start will run a testnet with 4 nodes, a bitcoin instance, and a vigilante instance
# localnet-start will run a with 4 nodes with 4 nodes, a bitcoin instance, and a vigilante instance
localnet-start: localnet-stop localnet-build-env localnet-build-nodes

# localnet-start-test will start with 4 nodes with test confiuration and low
# epoch interval
localnet-start-test: localnet-stop localnet-build-env localnet-build-nodes-test

# localnet-debug will run a 4-node testnet locally in debug mode
# you can read more about the debug mode here: ./contrib/images/babylond-dlv/README.md
localnet-debug: localnet-stop localnet-build-dlv localnet-build-nodes
Expand Down
65 changes: 51 additions & 14 deletions cmd/babylond/cmd/testnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,20 @@ import (
)

var (
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagBtcNetwork = "btc-network"
flagBtcCheckpointTag = "btc-checkpoint-tag"
flagBtcConfirmationDepth = "btc-confirmation-depth"
flagBtcFinalizationTimeout = "btc-finalization-timeout"
flagEpochInterval = "epoch-interval"
flagBaseBtcHeaderHex = "btc-base-header"
flagBaseBtcHeaderHeight = "btc-base-header-height"
flagMaxActiveValidators = "max-active-validators"
flagNodeDirPrefix = "node-dir-prefix"
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagStartingIPAddress = "starting-ip-address"
flagBtcNetwork = "btc-network"
flagBtcCheckpointTag = "btc-checkpoint-tag"
flagBtcConfirmationDepth = "btc-confirmation-depth"
flagBtcFinalizationTimeout = "btc-finalization-timeout"
flagEpochInterval = "epoch-interval"
flagBaseBtcHeaderHex = "btc-base-header"
flagBaseBtcHeaderHeight = "btc-base-header-height"
flagMaxActiveValidators = "max-active-validators"
flagAdditionalSenderAccount = "additional-sender-account"
)

// get cmd to initialize all files for tendermint testnet and application
Expand Down Expand Up @@ -108,6 +109,7 @@ Example:
// btclightclient args
baseBtcHeaderHex, _ := cmd.Flags().GetString(flagBaseBtcHeaderHex)
baseBtcHeaderHeight, err := cmd.Flags().GetUint64(flagBaseBtcHeaderHeight)
additionalAccount, _ := cmd.Flags().GetBool(flagAdditionalSenderAccount)
if err != nil {
return errors.New("base Bitcoin header height should be a uint64")
}
Expand All @@ -116,7 +118,7 @@ Example:
clientCtx, cmd, config, mbm, genBalIterator, outputDir, chainID, minGasPrices,
nodeDirPrefix, nodeDaemonHome, startingIPAddress, keyringBackend, algo, numValidators,
maxActiveValidators, btcNetwork, btcCheckpointTag, btcConfirmationDepth, btcFinalizationTimeout,
epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight,
epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight, additionalAccount,
)
},
}
Expand All @@ -142,6 +144,7 @@ Example:
cmd.Flags().String(flagBaseBtcHeaderHex, "0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a45068653ffff7f2002000000", "Hex of the base Bitcoin header.")
cmd.Flags().Uint64(flagBaseBtcHeaderHeight, 0, "Height of the base Bitcoin header.")
cmd.Flags().Uint32(flagMaxActiveValidators, 10, "Maximum number of validators.")
cmd.Flags().Bool(flagAdditionalSenderAccount, false, "If there should be additional pre funded account per validator")

return cmd
}
Expand Down Expand Up @@ -172,6 +175,7 @@ func InitTestnet(
epochInterval uint64,
baseBtcHeaderHex string,
baseBtcHeaderHeight uint64,
additionalAccount bool,
) error {

if chainID == "" {
Expand Down Expand Up @@ -234,6 +238,7 @@ func InitTestnet(

// generate account key
kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, nodeDir, inBuf)

if err != nil {
return err
}
Expand Down Expand Up @@ -344,6 +349,38 @@ func InitTestnet(
}
}

if additionalAccount {
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)

// generate account key
kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, nodeDir, inBuf)

if err != nil {
return err
}
keyringAlgos, _ := kb.SupportedAlgorithms()
algo, err := keyring.NewSigningAlgoFromString(algoStr, keyringAlgos)
if err != nil {
return err
}
addr, _, err := testutil.GenerateSaveCoinKey(kb, "test-spending-key", "", true, algo)
if err != nil {
_ = os.RemoveAll(outputDir)
return err
}

coins := sdk.Coins{
sdk.NewCoin("testtoken", sdk.NewInt(1000000000)),
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(500000000)),
}

genBalances = append(genBalances, banktypes.Balance{Address: addr.String(), Coins: coins.Sort()})
genAccounts = append(genAccounts, authtypes.NewBaseAccount(addr, nil, 0, 0))
}
}

if err := initGenFiles(clientCtx, mbm, chainID, genAccounts, genBalances, genFiles,
genKeys, numValidators, maxActiveValidators, btcConfirmationDepth, btcFinalizationTimeout,
epochInterval, baseBtcHeaderHex, baseBtcHeaderHeight); err != nil {
Expand Down
162 changes: 34 additions & 128 deletions test/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,26 @@ func waitForBlock(clients []*grpc.ClientConn, blockNumber int64) {
return
}

<-time.After(2 * time.Second)
<-time.After(1 * time.Second)
}
}

func getCurrentEpoch(conn *grpc.ClientConn) uint64 {
epochingClient := epochingtypes.NewQueryClient(conn)

currentEpochResponse, err := epochingClient.CurrentEpoch(
context.Background(),
&epochingtypes.QueryCurrentEpochRequest{},
)

if err != nil {
errorString := fmt.Sprintf("Query failed, testnet not running. Error: %v", err)
panic(errorString)
}

return currentEpochResponse.CurrentEpoch
}

func TestMain(m *testing.M) {

// This is needed so that all address prefixes are in Babylon format
Expand Down Expand Up @@ -154,62 +170,19 @@ func TestBtcLightClientGenesis(t *testing.T) {
}

func TestNodeProgress(t *testing.T) {

// most probably nodes are after block 1 at this point, but to make sure we are waiting
// for block 1
// blocks 1-10 are epoch 1 blocks.
waitForBlock(clients, 1)
// Waiting for block 7, as tests are configured to run with epoch interval = 5,
// which means that at block 7 all clients will surely be in second epoch
waitForBlock(clients, 7)

for _, c := range clients {
epochingClient := epochingtypes.NewQueryClient(c)

currentEpochResponse, err := epochingClient.CurrentEpoch(
context.Background(),
&epochingtypes.QueryCurrentEpochRequest{},
)

if err != nil {
errorString := fmt.Sprintf("Query failed, testnet not running. Error: %v", err)
panic(errorString)
}

if currentEpochResponse.CurrentEpoch != 1 {
t.Fatalf("Initial epoch should equal 1. Current epoch %d", currentEpochResponse.CurrentEpoch)
}
}

// TODO default epoch interval is equal to 10, we should retrieve it from config
// block 11 is first block of epoch 2, so if all clients are after block 12, they
// should be at epoch 2
waitForBlock(clients, 12)

for _, c := range clients {
epochingClient := epochingtypes.NewQueryClient(c)

currentEpochResponse, err := epochingClient.CurrentEpoch(
context.Background(),
&epochingtypes.QueryCurrentEpochRequest{},
)

if err != nil {
errorString := fmt.Sprintf("Query failed, testnet not running. Error: %v", err)
panic(errorString)
}

if currentEpochResponse.CurrentEpoch != 2 {
t.Errorf("Epoch after 10 blocks, should equal 2. Curent epoch %d", currentEpochResponse.CurrentEpoch)
currentEpoch := getCurrentEpoch(c)
if currentEpoch != 2 {
t.Errorf("Epoch after 7 blocks, should equal 2. Current epoch %d", currentEpoch)
}
}
}

func TestSendTx(t *testing.T) {
// we are waiting for middle of the epoch to avoid race condidions with bls
// signer sending transaction and incrementing account sequence numbers
// which may cause header tx to fail.
// TODO: Create separate account for sending transactions to avoid race
// conditions with validator acounts.
waitForBlock(clients, 14)

// TODO fix hard coded paths
node0dataPath := "../.testnets/node0/babylond"
node0genesisPath := "../.testnets/node0/babylond/config/genesis.json"
Expand All @@ -219,31 +192,15 @@ func TestSendTx(t *testing.T) {
if err != nil {
panic("failed to init sender")
}
tip1 := sender.GetBtcTip()

tip1, err := sender.getBtcTip()

if err != nil {
t.Fatalf("Couldnot retrieve tip")
}

res, err := sender.insertNewEmptyHeader(tip1)
err = sender.insertNEmptyBTCHeaders(1)

if err != nil {
t.Fatalf("could not insert new btc header")
}

_, err = WaitBtcForHeight(sender.Conn, tip1.Height+1)

if err != nil {
t.Log(res.TxResponse)
t.Fatalf("failed waiting for btc lightclient block")
}

tip2, err := sender.getBtcTip()

if err != nil {
t.Fatalf("Couldnot retrieve tip")
}
tip2 := sender.GetBtcTip()

if tip2.Height != tip1.Height+1 {
t.Fatalf("Light client should progress by 1 one block")
Expand Down Expand Up @@ -300,41 +257,20 @@ func TestSubmitCheckpoint(t *testing.T) {
rawBtcCheckpoint,
)

currentTip, err := sender.getBtcTip()

if err != nil {
t.Fatalf("Could not retrieve btc tip")
}
currentTip := sender.GetBtcTip()

firstSubmission := datagen.CreateBlockWithTransaction(currentTip.Header.ToBlockHeader(), p1)

secondSubmission := datagen.CreateBlockWithTransaction(firstSubmission.HeaderBytes.ToBlockHeader(), p2)

// first insert all headers
hresp1, err := sender.insertNewHeader(firstSubmission.HeaderBytes)

if err != nil {
t.Fatalf("Could not insert first header")
}

_, err = WaitBtcForHeight(clients[0], currentTip.Height+1)

if err != nil {
t.Log(hresp1.TxResponse)
t.Fatalf("failed waiting for btc lightclient block")
}

hresp2, err := sender.insertNewHeader(secondSubmission.HeaderBytes)

if err != nil {
t.Fatalf("Could not insert second header")
}

_, err = WaitBtcForHeight(clients[0], currentTip.Height+2)
err = sender.insertBTCHeaders(
currentTip.Height,
[]bbn.BTCHeaderBytes{firstSubmission.HeaderBytes, secondSubmission.HeaderBytes},
)

if err != nil {
t.Log(hresp2.TxResponse)
t.Fatalf("failed waiting for btc lightclient block")
t.Fatalf("Could not insert two headers. Err: %s", err)
}

// At this point light client chain should be 3 long and inserting spv proofs
Expand Down Expand Up @@ -373,40 +309,10 @@ func TestConfirmCheckpoint(t *testing.T) {
panic("failed to init sender")
}

currentTip, err := sender.getBtcTip()

if err != nil {
t.Fatalf("Could not retrieve btc tip")
}

h1 := generateEmptyChildHeaderBytes(currentTip.Header.ToBlockHeader())
h2 := generateEmptyChildHeaderBytes(h1.ToBlockHeader())

// first insert 2 new headers,
hresp1, err := sender.insertNewHeader(h1)

if err != nil {
t.Fatalf("Could not insert first header")
}

_, err = WaitBtcForHeight(clients[0], currentTip.Height+1)

if err != nil {
t.Log(hresp1.TxResponse)
t.Fatalf("failed waiting for btc lightclient block")
}

hresp2, err := sender.insertNewHeader(h2)

if err != nil {
t.Fatalf("Could not insert second header")
}

_, err = WaitBtcForHeight(clients[0], currentTip.Height+2)
err = sender.insertNEmptyBTCHeaders(2)

if err != nil {
t.Log(hresp2.TxResponse)
t.Fatalf("failed waiting for btc lightclient block")
t.Fatalf("Could not insert two headers. Err: %s", err)
}

// Btc light client chain has been extended by 2 blocks, it means that our checkpoint
Expand Down
Loading