Skip to content

Commit

Permalink
chore: refactor Hermes relayers setups and executions in the E2E tests (
Browse files Browse the repository at this point in the history
#2859)

* refactor hermes setup in e2e tests

* chore: appease linter

---------

Co-authored-by: MSalopek <[email protected]>
  • Loading branch information
sainoe and MSalopek authored Feb 8, 2024
1 parent 4131243 commit a92d206
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 422 deletions.
16 changes: 10 additions & 6 deletions tests/e2e/e2e_bypassminfee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ func (s *IntegrationTestSuite) testIBCBypassMsg() {
sdk.MsgTypeURL(&ibcclienttypes.MsgUpdateClient{}),
}, proposalCounter, submitter, standardFees.String())

// use hermes1 to test default ibc bypass-msg
//
// test 1: transaction only contains bypass-msgs, pass
s.testTxContainsOnlyIBCBypassMsg()
// test 2: test transactions contains both bypass and non-bypass msgs (sdk.MsgTypeURL(&ibcchanneltypes.MsgTimeout{})
Expand Down Expand Up @@ -145,7 +143,7 @@ func (s *IntegrationTestSuite) testTxContainsOnlyIBCBypassMsg() {

pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
s.Require().True(pass)
pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
pendingPacketsExist := s.hermesPendingPackets(s.chainA.id, transferChannel)
s.Require().False(pendingPacketsExist)

// confirm relayer wallets do not pay fees
Expand All @@ -161,12 +159,18 @@ func (s *IntegrationTestSuite) testTxContainsMixBypassNonBypassMsg() {
s.Require().True(ok)
// make sure that the transaction is timeout
time.Sleep(3 * time.Second)
pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
pendingPacketsExist := s.hermesPendingPackets(s.chainA.id, transferChannel)
s.Require().True(pendingPacketsExist)

// attempt to relay packets without paying fees
pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
s.Require().False(pass)
// clear packets with paying fee, to not influence the next transaction

// assert that packets were not relayed
pendingPacketsExist = s.hermesPendingPackets(s.chainA.id, transferChannel)
s.Require().True(pendingPacketsExist)

// clear packets with paying fees
pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel)
s.Require().True(pass)
}
Expand All @@ -178,7 +182,7 @@ func (s *IntegrationTestSuite) testBypassMsgsExceedMaxBypassGasLimit() {
pass := s.hermesClearPacket(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
s.Require().False(pass)

pendingPacketsExist := s.hermesPendingPackets(hermesConfigNoGasPrices, s.chainA.id, transferChannel)
pendingPacketsExist := s.hermesPendingPackets(s.chainA.id, transferChannel)
s.Require().True(pendingPacketsExist)

pass = s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel)
Expand Down
36 changes: 26 additions & 10 deletions tests/e2e/e2e_exec_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package e2e

import (
"bufio"
"bytes"
"context"
"encoding/json"
Expand Down Expand Up @@ -712,16 +713,13 @@ func (s *IntegrationTestSuite) executeGaiaTxCommand(ctx context.Context, c *chai
}
}

func (s *IntegrationTestSuite) executeHermesCommand(ctx context.Context, hermesCmd []string) ([]byte, []byte) {
var (
outBuf bytes.Buffer
errBuf bytes.Buffer
)
func (s *IntegrationTestSuite) executeHermesCommand(ctx context.Context, hermesCmd []string) ([]byte, error) {
var outBuf bytes.Buffer
exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{
Context: ctx,
AttachStdout: true,
AttachStderr: true,
Container: s.hermesResource1.Container.ID,
Container: s.hermesResource.Container.ID,
User: "root",
Cmd: hermesCmd,
})
Expand All @@ -731,14 +729,32 @@ func (s *IntegrationTestSuite) executeHermesCommand(ctx context.Context, hermesC
Context: ctx,
Detach: false,
OutputStream: &outBuf,
ErrorStream: &errBuf,
})
s.Require().NoError(err)

stdOut := outBuf.Bytes()
stdErr := errBuf.Bytes()
// Check that the stdout output contains the expected status
// and look for errors, e.g "insufficient fees"
stdOut := []byte{}
scanner := bufio.NewScanner(&outBuf)
for scanner.Scan() {
stdOut = scanner.Bytes()
var out map[string]interface{}
err = json.Unmarshal(stdOut, &out)
s.Require().NoError(err)
if err != nil {
return nil, fmt.Errorf("hermes relayer command returned failed with error: %s", err)
}
// errors are catched by observing the logs level in the stderr output
if lvl := out["level"]; lvl != nil && strings.ToLower(lvl.(string)) == "error" {
errMsg := out["fields"].(map[string]interface{})["message"]
return nil, fmt.Errorf("hermes relayer command failed: %s", errMsg)
}
if s := out["status"]; s != nil && s != "success" {
return nil, fmt.Errorf("hermes relayer command returned failed with status: %s", s)
}
}

return stdOut, stdErr
return stdOut, nil
}

func (s *IntegrationTestSuite) expectErrExecValidation(chain *chain, valIdx int, expectErr bool) func([]byte, []byte) bool {
Expand Down
144 changes: 48 additions & 96 deletions tests/e2e/e2e_ibc_test.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package e2e

import (
"bufio"
"bytes"
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"

"github.com/ory/dockertest/v3/docker"

"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand Down Expand Up @@ -65,6 +61,7 @@ func (s *IntegrationTestSuite) hermesTransfer(configPath, srcChainID, dstChainID

hermesCmd := []string{
hermesBinary,
"--json",
fmt.Sprintf("--config=%s", configPath),
"tx",
"ft-transfer",
Expand All @@ -78,8 +75,7 @@ func (s *IntegrationTestSuite) hermesTransfer(configPath, srcChainID, dstChainID
fmt.Sprintf("--number-msgs=%v", numMsg),
}

stdout, stderr := s.executeHermesCommand(ctx, hermesCmd)
if strings.Contains(string(stdout), "ERROR") || strings.Contains(string(stderr), "ERROR") {
if _, err := s.executeHermesCommand(ctx, hermesCmd); err != nil {
return false
}

Expand All @@ -92,6 +88,7 @@ func (s *IntegrationTestSuite) hermesClearPacket(configPath, chainID, channelID

hermesCmd := []string{
hermesBinary,
"--json",
fmt.Sprintf("--config=%s", configPath),
"clear",
"packets",
Expand All @@ -100,9 +97,7 @@ func (s *IntegrationTestSuite) hermesClearPacket(configPath, chainID, channelID
fmt.Sprintf("--port=%s", "transfer"),
}

stdout, stderr := s.executeHermesCommand(ctx, hermesCmd)

if strings.Contains(string(stdout), "ERROR") || strings.Contains(string(stderr), "ERROR") {
if _, err := s.executeHermesCommand(ctx, hermesCmd); err != nil {
return false
}

Expand All @@ -121,13 +116,12 @@ type RelayerPacketsOutput struct {
Status string `json:"status"`
}

func (s *IntegrationTestSuite) hermesPendingPackets(configPath, chainID, channelID string) (pendingPackets bool) {
func (s *IntegrationTestSuite) hermesPendingPackets(chainID, channelID string) (pendingPackets bool) { //nolint:unparam
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
hermesCmd := []string{
hermesBinary,
"--json",
fmt.Sprintf("--config=%s", configPath),
"query",
"packet",
"pending",
Expand All @@ -136,34 +130,28 @@ func (s *IntegrationTestSuite) hermesPendingPackets(configPath, chainID, channel
fmt.Sprintf("--port=%s", "transfer"),
}

stdout, _ := s.executeHermesCommand(ctx, hermesCmd)
reader := bytes.NewReader(stdout)
sc := bufio.NewScanner(reader)
stdout, err := s.executeHermesCommand(ctx, hermesCmd)
s.Require().NoError(err)

var relayerPacketsOutput RelayerPacketsOutput

// TODO: check why no error is never returned
// works atm because the last line of stdout is always the query output
for sc.Scan() {
sc.Bytes()
_ = json.Unmarshal(sc.Bytes(), &relayerPacketsOutput)
}
err = json.Unmarshal(stdout, &relayerPacketsOutput)
s.Require().NoError(err)

// Check if "unreceived_packets" exists in "src"
return len(relayerPacketsOutput.Result.Src.UnreceivedPackets) != 0
}

func (s *IntegrationTestSuite) queryRelayerWalletsBalances() (sdk.Coin, sdk.Coin) {
chainAAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainA.id][0].GetHostPort("1317/tcp"))
acctAddrChainA, _ := s.chainA.genesisAccounts[relayerAccountIndexHermes1].keyInfo.GetAddress()
acctAddrChainA, _ := s.chainA.genesisAccounts[relayerAccountIndexHermes].keyInfo.GetAddress()
scrRelayerBalance, err := getSpecificBalance(
chainAAPIEndpoint,
acctAddrChainA.String(),
uatomDenom)
s.Require().NoError(err)

chainBAPIEndpoint := fmt.Sprintf("http://%s", s.valResources[s.chainB.id][0].GetHostPort("1317/tcp"))
acctAddrChainB, _ := s.chainB.genesisAccounts[relayerAccountIndexHermes1].keyInfo.GetAddress()
acctAddrChainB, _ := s.chainB.genesisAccounts[relayerAccountIndexHermes].keyInfo.GetAddress()
dstRelayerBalance, err := getSpecificBalance(
chainBAPIEndpoint,
acctAddrChainB.String(),
Expand All @@ -179,90 +167,45 @@ func (s *IntegrationTestSuite) createConnection() {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{
Context: ctx,
AttachStdout: true,
AttachStderr: true,
Container: s.hermesResource0.Container.ID,
User: "root",
Cmd: []string{
"hermes",
"create",
"connection",
"--a-chain",
s.chainA.id,
"--b-chain",
s.chainB.id,
},
})
s.Require().NoError(err)

var (
outBuf bytes.Buffer
errBuf bytes.Buffer
)
hermesCmd := []string{
hermesBinary,
"--json",
"create",
"connection",
"--a-chain",
s.chainA.id,
"--b-chain",
s.chainB.id,
}

err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{
Context: ctx,
Detach: false,
OutputStream: &outBuf,
ErrorStream: &errBuf,
})
s.Require().NoErrorf(
err,
"failed connect chains; stdout: %s, stderr: %s", outBuf.String(), errBuf.String(),
)
_, err := s.executeHermesCommand(ctx, hermesCmd)
s.Require().NoError(err, "failed to connect chains: %s", err)

s.T().Logf("connected %s and %s chains via IBC", s.chainA.id, s.chainB.id)
}

func (s *IntegrationTestSuite) createChannel() {
s.T().Logf("connecting %s and %s chains via IBC", s.chainA.id, s.chainB.id)
s.T().Logf("creating IBC transfer channel created between chains %s and %s", s.chainA.id, s.chainB.id)

ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
hermesCmd := []string{
hermesBinary,
"--json",
"create",
"channel",
"--a-chain", s.chainA.id,
"--a-connection", "connection-0",
"--a-port", "transfer",
"--b-port", "transfer",
"--channel-version", "ics20-1",
"--order", "unordered",
}

exec, err := s.dkrPool.Client.CreateExec(docker.CreateExecOptions{
Context: ctx,
AttachStdout: true,
AttachStderr: true,
Container: s.hermesResource0.Container.ID,
User: "root",
Cmd: []string{
"hermes",
txCommand,
"chan-open-init",
"--dst-chain",
s.chainA.id,
"--src-chain",
s.chainB.id,
"--dst-connection",
"connection-0",
"--src-port=transfer",
"--dst-port=transfer",
},
})

s.Require().NoError(err)

var (
outBuf bytes.Buffer
errBuf bytes.Buffer
)

err = s.dkrPool.Client.StartExec(exec.ID, docker.StartExecOptions{
Context: ctx,
Detach: false,
OutputStream: &outBuf,
ErrorStream: &errBuf,
})

s.Require().NoErrorf(
err,
"failed connect chains; stdout: %s, stderr: %s", outBuf.String(), errBuf.String(),
)
_, err := s.executeHermesCommand(ctx, hermesCmd)
s.Require().NoError(err, "failed to create IBC transfer channel between chains: %s", err)

s.T().Logf("connected %s and %s chains via IBC", s.chainA.id, s.chainB.id)
s.T().Logf("IBC transfer channel created between chains %s and %s", s.chainA.id, s.chainB.id)
}

func (s *IntegrationTestSuite) testIBCTokenTransfer() {
Expand Down Expand Up @@ -302,6 +245,9 @@ func (s *IntegrationTestSuite) testIBCTokenTransfer() {
tokenAmt := 3300000000
s.sendIBC(s.chainA, 0, sender, recipient, strconv.Itoa(tokenAmt)+uatomDenom, standardFees.String(), "")

pass := s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel)
s.Require().True(pass)

s.Require().Eventually(
func() bool {
balances, err = queryGaiaAllBalances(chainBAPIEndpoint, recipient)
Expand Down Expand Up @@ -392,6 +338,9 @@ func (s *IntegrationTestSuite) testMultihopIBCTokenTransfer() {

s.sendIBC(s.chainA, 0, sender, middlehop, strconv.Itoa(tokenAmt)+uatomDenom, standardFees.String(), string(memo))

pass := s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel)
s.Require().True(pass)

s.Require().Eventually(
func() bool {
afterSenderUAtomBalance, err := getSpecificBalance(chainAAPIEndpoint, sender, uatomDenom)
Expand Down Expand Up @@ -478,6 +427,9 @@ func (s *IntegrationTestSuite) testFailedMultihopIBCTokenTransfer() {
1*time.Second,
)

pass := s.hermesClearPacket(hermesConfigWithGasPrices, s.chainA.id, transferChannel)
s.Require().True(pass)

// since the forward receiving account is invalid, it should be refunded to the original sender (minus the original fee)
s.Require().Eventually(
func() bool {
Expand Down
Loading

0 comments on commit a92d206

Please sign in to comment.