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

Add support for the Hermes relayer #396

Merged
merged 34 commits into from
Feb 22, 2023
Merged
Changes from 31 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
0072f44
adding some scaffolding for hermes relayer
chatton Feb 2, 2023
fedafd6
chore: updating interface to accept create connection options type
chatton Feb 9, 2023
a35487e
chore: wip
chatton Feb 9, 2023
a18bf66
wip: adding path map to hermes relayer type
chatton Feb 10, 2023
19930b0
writing mnemonic file
chatton Feb 10, 2023
e78de86
correctly reading toml config
chatton Feb 13, 2023
3def8eb
ibc test passing with hermes relayer
chatton Feb 13, 2023
be8adbf
learn ibc test passing with hermes relayer
chatton Feb 14, 2023
7a5160e
adding parse client and connection output
chatton Feb 14, 2023
f7ca984
adding hermes test cases
chatton Feb 14, 2023
5bbefaa
remove unused types
chatton Feb 14, 2023
a1e091e
undid import change
chatton Feb 14, 2023
5ce3a8d
reverted import change
chatton Feb 14, 2023
5f573c9
reverted some unintentional changes
chatton Feb 14, 2023
5326b10
Merge branch 'main' into add-hermes-relayer-support
chatton Feb 14, 2023
48d8562
fix linting error
chatton Feb 14, 2023
791b8f0
Merge branch 'add-hermes-relayer-support' of https://github.com/chatt…
chatton Feb 14, 2023
47af05d
adding hermes to conformance matrix
chatton Feb 15, 2023
6783734
adding default value for matrix file for CI
chatton Feb 16, 2023
1976b22
pass absolute value for matrix file
chatton Feb 16, 2023
a40eff6
removed extra part of path
chatton Feb 16, 2023
8194b65
adding hermes to Labels function
chatton Feb 16, 2023
cde37cb
add capabilities for hermes
chatton Feb 16, 2023
4dfd2a1
temporarily strip down number of tests to verify hermes relayer
chatton Feb 16, 2023
9adbf3b
fixing conformance tests
chatton Feb 16, 2023
83b0c5a
fixing channel tests in TestRelayerSetup
chatton Feb 16, 2023
5ad0cec
revert to go rly to test
chatton Feb 16, 2023
b26c8c2
bump hermes version
chatton Feb 16, 2023
0c9e8f8
extract json response correctly
chatton Feb 16, 2023
385369d
extract json result from stdout
chatton Feb 16, 2023
136f35f
correct channel parsing json stdout
chatton Feb 16, 2023
5366e6f
set field ClearOnStart to true
chatton Feb 17, 2023
e066e90
switch back to go relayer as default
chatton Feb 17, 2023
b7797b1
add hermes to the default relayers list
chatton Feb 17, 2023
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
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Don't commit the interchaintest.test file,
# regardless of where it was built.
interchaintest.test

/bin
.idea
/bin
vendor
2 changes: 1 addition & 1 deletion cmd/interchaintest/example_matrix.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"Relayers": ["rly"],
"Relayers": ["rly", "hermes"],

"ChainSets": [
[
21 changes: 20 additions & 1 deletion cmd/interchaintest/interchaintest_test.go
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import (
"math/rand"
"os"
"path/filepath"
"strings"
"testing"
"time"

@@ -24,6 +25,10 @@ import (
"go.uber.org/zap"
)

const (
defaultRelativeCIMatrixFile = "example_matrix.json"
)

func init() {
// Because we use the test binary, we use this hack to customize the help usage.
flag.Usage = func() {
@@ -94,16 +99,30 @@ func TestMain(m *testing.M) {
os.Exit(code)
}

// isRunningInCI returns true if this test is running in CI.
// Note: On Github, all runners are passed an environment variable of "CI" with a value of "true".
func isRunningInCI() bool {
return strings.ToLower(os.Getenv("CI")) == "true"
}

var extraFlags mainFlags

// setUpTestMatrix populates the testMatrix singleton with
// the parsed contents of the file referenced by the matrix flag,
// or with a small reasonable default of rly against one gaia-osmosis set.
func setUpTestMatrix() error {
//if extraFlags.MatrixFile == "" && isRunningInCI() {
// currentDir, err := os.Getwd()
// if err != nil {
// return err
// }
// extraFlags.MatrixFile = path.Join(currentDir, defaultRelativeCIMatrixFile)
//}

if extraFlags.MatrixFile == "" {
fmt.Fprintln(os.Stderr, "No matrix file provided, falling back to rly with gaia and osmosis")

testMatrix.Relayers = []string{"rly"}
testMatrix.Relayers = []string{"hermes"}
testMatrix.ChainSets = [][]*interchaintest.ChainSpec{
{
{Name: "gaia", Version: "v7.0.1"},
8 changes: 7 additions & 1 deletion conformance/flush.go
Original file line number Diff line number Diff line change
@@ -9,6 +9,7 @@ import (
interchaintest "github.com/strangelove-ventures/interchaintest/v6"
"github.com/strangelove-ventures/interchaintest/v6/ibc"
"github.com/strangelove-ventures/interchaintest/v6/relayer"
"github.com/strangelove-ventures/interchaintest/v6/relayer/hermes"
"github.com/strangelove-ventures/interchaintest/v6/testreporter"
"github.com/strangelove-ventures/interchaintest/v6/testutil"
"github.com/stretchr/testify/require"
@@ -100,9 +101,14 @@ func TestRelayerFlushing(t *testing.T, ctx context.Context, cf interchaintest.Ch
afterFlushHeight, err := c0.Height(ctx)
req.NoError(err)

//flush packets and flush acks are the same command in hermes and are not separated as in the go relayer
// Ack shouldn't happen yet.
_, err = testutil.PollForAck(ctx, c0, beforeTransferHeight, afterFlushHeight+2, tx.Packet)
req.ErrorIs(err, testutil.ErrNotFound)
if _, isHermes := r.(*hermes.Relayer); isHermes {
req.NoError(err)
} else {
req.ErrorIs(err, testutil.ErrNotFound)
}
})

t.Run("flush acks", func(t *testing.T) {
15 changes: 8 additions & 7 deletions conformance/relayersetup.go
Original file line number Diff line number Diff line change
@@ -5,13 +5,14 @@ import (
"fmt"
"testing"

conntypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types"
interchaintest "github.com/strangelove-ventures/interchaintest/v6"
"github.com/strangelove-ventures/interchaintest/v6/ibc"
"github.com/strangelove-ventures/interchaintest/v6/testreporter"
"github.com/strangelove-ventures/interchaintest/v6/testutil"
"github.com/stretchr/testify/require"
"golang.org/x/sync/errgroup"

conntypes "github.com/cosmos/ibc-go/v6/modules/core/03-connection/types"
)

// TestRelayerSetup contains a series of subtests that configure a relayer step-by-step.
@@ -102,7 +103,7 @@ func TestRelayerSetup(t *testing.T, ctx context.Context, cf interchaintest.Chain
conn0 := conns0[0]
req.NotEmpty(conn0.ID)
req.NotEmpty(conn0.ClientID)
req.Equal(conn0.State, conntypes.OPEN.String())
req.Subset([]string{conntypes.OPEN.String(), "Open"}, []string{conn0.State})

conns1, err := r.GetConnections(ctx, eRep, c1.Config().ChainID)
req.NoError(err)
@@ -111,7 +112,7 @@ func TestRelayerSetup(t *testing.T, ctx context.Context, cf interchaintest.Chain
conn1 := conns1[0]
req.NotEmpty(conn1.ID)
req.NotEmpty(conn1.ClientID)
req.Equal(conn1.State, conntypes.OPEN.String())
req.Subset([]string{conntypes.OPEN.String(), "Open"}, []string{conn1.State})

// Now validate counterparties.
req.Equal(conn0.Counterparty.ClientId, conn1.ClientID)
@@ -160,14 +161,14 @@ func TestRelayerSetup(t *testing.T, ctx context.Context, cf interchaintest.Chain

// Piecemeal assertions against each channel.
// Not asserting against ConnectionHops or ChannelID.
req.Equal(ch0.State, "STATE_OPEN")
req.Equal(ch0.Ordering, "ORDER_UNORDERED")
req.Subset([]string{"STATE_OPEN", "Open"}, []string{ch0.State})
req.Subset([]string{"ORDER_UNORDERED", "Unordered"}, []string{ch0.Ordering})
req.Equal(ch0.Counterparty, ibc.ChannelCounterparty{PortID: "transfer", ChannelID: ch1.ChannelID})
req.Equal(ch0.Version, "ics20-1")
req.Equal(ch0.PortID, "transfer")

req.Equal(ch1.State, "STATE_OPEN")
req.Equal(ch1.Ordering, "ORDER_UNORDERED")
req.Subset([]string{"STATE_OPEN", "Open"}, []string{ch1.State})
req.Subset([]string{"ORDER_UNORDERED", "Unordered"}, []string{ch1.Ordering})
req.Equal(ch1.Counterparty, ibc.ChannelCounterparty{PortID: "transfer", ChannelID: ch0.ChannelID})
req.Equal(ch1.Version, "ics20-1")
req.Equal(ch1.PortID, "transfer")
8 changes: 4 additions & 4 deletions examples/ibc/interchain_accounts_test.go
Original file line number Diff line number Diff line change
@@ -268,12 +268,12 @@ func TestInterchainAccounts(t *testing.T) {
chain1Chans, err := r.GetChannels(ctx, eRep, chain1.Config().ChainID)
require.NoError(t, err)
require.Equal(t, 1, len(chain1Chans))
require.Equal(t, "STATE_CLOSED", chain1Chans[0].State)
require.Subset(t, []string{"STATE_CLOSED", "Closed"}, []string{chain1Chans[0].State})

chain2Chans, err := r.GetChannels(ctx, eRep, chain2.Config().ChainID)
require.NoError(t, err)
require.Equal(t, 1, len(chain2Chans))
require.Equal(t, "STATE_CLOSED", chain2Chans[0].State)
require.Subset(t, []string{"STATE_CLOSED", "Closed"}, []string{chain2Chans[0].State})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the go relayer and the hermes relayer return different states, this just accounts for either of them


// Attempt to open another channel for the same ICA
_, _, err = chain1.Exec(ctx, registerICA, nil)
@@ -294,12 +294,12 @@ func TestInterchainAccounts(t *testing.T) {
chain1Chans, err = r.GetChannels(ctx, eRep, chain1.Config().ChainID)
require.NoError(t, err)
require.Equal(t, 2, len(chain1Chans))
require.Equal(t, "STATE_OPEN", chain1Chans[1].State)
require.Subset(t, []string{"STATE_OPEN", "Open"}, []string{chain1Chans[1].State})

chain2Chans, err = r.GetChannels(ctx, eRep, chain2.Config().ChainID)
require.NoError(t, err)
require.Equal(t, 2, len(chain2Chans))
require.Equal(t, "STATE_OPEN", chain2Chans[1].State)
require.Subset(t, []string{"STATE_OPEN", "Open"}, []string{chain2Chans[1].State})
}

// parseInterchainAccountField takes a slice of bytes which should be returned when querying for an ICA via
36 changes: 30 additions & 6 deletions interchain_test.go
Original file line number Diff line number Diff line change
@@ -26,7 +26,15 @@ import (
clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
)

func TestInterchain_DuplicateChain(t *testing.T) {
func TestInterchain_DuplicateChain_CosmosRly(t *testing.T) {
duplicateChainTest(t, ibc.CosmosRly)
}

func TestInterchain_DuplicateChain_HermesRelayer(t *testing.T) {
duplicateChainTest(t, ibc.Hermes)
}

func duplicateChainTest(t *testing.T, relayerImpl ibc.RelayerImplementation) {
if testing.Short() {
t.Skip("skipping in short mode")
}
@@ -46,7 +54,7 @@ func TestInterchain_DuplicateChain(t *testing.T) {

gaia0, gaia1 := chains[0], chains[1]

r := interchaintest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).Build(
r := interchaintest.NewBuiltinRelayerFactory(relayerImpl, zaptest.NewLogger(t)).Build(
t, client, network,
)

@@ -74,7 +82,15 @@ func TestInterchain_DuplicateChain(t *testing.T) {
_ = ic.Close()
}

func TestInterchain_GetRelayerWallets(t *testing.T) {
func TestInterchain_GetRelayerWallets_CosmosRly(t *testing.T) {
getRelayerWalletsTest(t, ibc.CosmosRly)
}

func TestInterchain_GetRelayerWallets_HermesRelayer(t *testing.T) {
getRelayerWalletsTest(t, ibc.Hermes)
}

func getRelayerWalletsTest(t *testing.T, relayerImpl ibc.RelayerImplementation) {
if testing.Short() {
t.Skip("skipping in short mode")
}
@@ -94,7 +110,7 @@ func TestInterchain_GetRelayerWallets(t *testing.T) {

gaia0, gaia1 := chains[0], chains[1]

r := interchaintest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).Build(
r := interchaintest.NewBuiltinRelayerFactory(relayerImpl, zaptest.NewLogger(t)).Build(
t, client, network,
)

@@ -230,7 +246,15 @@ func TestInterchain_CreateUser(t *testing.T) {
})
}

func TestCosmosChain_BroadcastTx(t *testing.T) {
func TestCosmosChain_BroadcastTx_CosmosRly(t *testing.T) {
broadcastTxCosmosChainTest(t, ibc.CosmosRly)
}

func TestCosmosChain_BroadcastTx_HermesRelayer(t *testing.T) {
broadcastTxCosmosChainTest(t, ibc.Hermes)
}

func broadcastTxCosmosChainTest(t *testing.T, relayerImpl ibc.RelayerImplementation) {
if testing.Short() {
t.Skip("skipping in short mode")
}
@@ -250,7 +274,7 @@ func TestCosmosChain_BroadcastTx(t *testing.T) {

gaia0, gaia1 := chains[0], chains[1]

r := interchaintest.NewBuiltinRelayerFactory(ibc.CosmosRly, zaptest.NewLogger(t)).Build(
r := interchaintest.NewBuiltinRelayerFactory(relayerImpl, zaptest.NewLogger(t)).Build(
t, client, network,
)

5 changes: 2 additions & 3 deletions internal/dockerutil/filewriter.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@ import (
"bytes"
"context"
"fmt"
"path"
"time"

"github.com/docker/docker/api/types"
@@ -48,10 +47,10 @@ func (w *FileWriter) WriteFile(ctx context.Context, volumeName, relPath string,
Cmd: []string{
// Take the uid and gid of the mount path,
// and set that as the owner of the new relative path.
`chown "$(stat -c '%u:%g' "$1")" "$2"`,
`chown -R "$(stat -c '%u:%g' "$1")" "$2"`,
"_", // Meaningless arg0 for sh -c with positional args.
mountPath,
path.Join(mountPath, relPath),
mountPath,
Comment on lines +50 to +53
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this change as the hermes relayer ended up making several files in other places in the home directory and was running into permissions issues. I thought it might be fine if we just set the home directory to be owned by the relayer user. If this is a problem we can figure something else out!

},

// Use root user to avoid permission issues when reading files from the volume.
27 changes: 26 additions & 1 deletion relayer/docker.go
Original file line number Diff line number Diff line change
@@ -20,6 +20,10 @@ import (
"go.uber.org/zap"
)

const (
defaultRlyHomeDirectory = "/home/relayer"
)

// DockerRelayer provides a common base for relayer implementations
// that run on Docker.
type DockerRelayer struct {
@@ -42,6 +46,8 @@ type DockerRelayer struct {

// wallets contains a mapping of chainID to relayer wallet
wallets map[string]ibc.Wallet

homeDir string
}

var _ ibc.Relayer = (*DockerRelayer)(nil)
@@ -64,12 +70,16 @@ func NewDockerRelayer(ctx context.Context, log *zap.Logger, testName string, cli
wallets: map[string]ibc.Wallet{},
}

r.homeDir = defaultRlyHomeDirectory

for _, opt := range options {
switch o := opt.(type) {
case RelayerOptionDockerImage:
r.customImage = &o.DockerImage
case RelayerOptionImagePull:
r.pullImage = o.Pull
case RelayerOptionHomeDir:
r.homeDir = o.HomeDir
}
}

@@ -122,6 +132,21 @@ func NewDockerRelayer(ctx context.Context, log *zap.Logger, testName string, cli
return &r, nil
}

// WriteFileToHomeDir writes the given contents to a file at the relative path specified. The file is relative
// to the home directory in the relayer container.
func (r *DockerRelayer) WriteFileToHomeDir(ctx context.Context, relativePath string, contents []byte) error {
fw := dockerutil.NewFileWriter(r.log, r.client, r.testName)
if err := fw.WriteFile(ctx, r.volumeName, relativePath, contents); err != nil {
return fmt.Errorf("failed to write file: %w", err)
}
return nil
}
Comment on lines +137 to +143
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this helper function as the hermes relayer required a few different files to be created.


// AddWallet adds a stores a wallet for the given chain ID.
func (r *DockerRelayer) AddWallet(chainID string, wallet ibc.Wallet) {
r.wallets[chainID] = wallet
}

func (r *DockerRelayer) AddChainConfiguration(ctx context.Context, rep ibc.RelayerExecReporter, chainConfig ibc.ChainConfig, keyName, rpcAddr, grpcAddr string) error {
// For rly this file is json, but the file extension should not matter.
// Using .config to avoid implying any particular format.
@@ -469,7 +494,7 @@ func (r *DockerRelayer) Bind() []string {

// HomeDir returns the home directory of the relayer on the underlying Docker container's filesystem.
func (r *DockerRelayer) HomeDir() string {
return "/home/relayer"
return r.homeDir
}

func (r *DockerRelayer) HostName(pathName string) string {
Loading