From 650bb76a9b43a607561cdf1cb5de74b4c43b70d2 Mon Sep 17 00:00:00 2001 From: Jack Zampolin Date: Wed, 4 Nov 2020 12:51:13 -0800 Subject: [PATCH 1/2] Refactor path generation and status --- Makefile | 1 - cmd/flags.go | 33 +++- cmd/light.go | 1 - cmd/paths.go | 456 +++++++++++++++++---------------------------- go.sum | 1 + relayer/path.go | 147 ++++++++++++++- relayer/pathEnd.go | 4 +- 7 files changed, 347 insertions(+), 296 deletions(-) diff --git a/Makefile b/Makefile index 355bca9d542..ec484d2fdbe 100644 --- a/Makefile +++ b/Makefile @@ -55,5 +55,4 @@ lint: .PHONY: install build lint coverage clean -# TODO: Port reproducable build scripts from gaia for relayer # TODO: Full tested and working releases diff --git a/cmd/flags.go b/cmd/flags.go index f139ab7a0ee..b6e184b9e79 100644 --- a/cmd/flags.go +++ b/cmd/flags.go @@ -12,11 +12,14 @@ var ( flagHash = "hash" flagURL = "url" flagForce = "force" + flagVersion = "version" + flagStrategy = "strategy" flagTimeout = "timeout" flagConfig = "config" flagJSON = "json" flagYAML = "yaml" flagFile = "file" + flagPort = "port" flagPath = "path" flagListenAddr = "listen" flagTx = "no-tx" @@ -78,6 +81,14 @@ func yamlFlag(cmd *cobra.Command) *cobra.Command { return cmd } +func portFlag(cmd *cobra.Command) *cobra.Command { + cmd.Flags().StringP(flagPort, "p", "transfer", "port to use when generating path") + if err := viper.BindPFlag(flagPort, cmd.Flags().Lookup(flagPort)); err != nil { + panic(err) + } + return cmd +} + func orderFlag(cmd *cobra.Command) *cobra.Command { cmd.Flags().BoolP(flagOrder, "o", true, "create an unordered channel") if err := viper.BindPFlag(flagOrder, cmd.Flags().Lookup(flagOrder)); err != nil { @@ -124,10 +135,14 @@ func pathFlag(cmd *cobra.Command) *cobra.Command { return cmd } -// TODO: add ability to set timeout height and time from flags -// Should be relative to current time and block height -// --timeout-height-offset=1000 -// --timeout-time-offset=2h +func pathStrategy(cmd *cobra.Command) *cobra.Command { + cmd.Flags().StringP(flagStrategy, "s", "naive", "specify strategy of path to generate") + if err := viper.BindPFlag(flagStrategy, cmd.Flags().Lookup(flagStrategy)); err != nil { + panic(err) + } + return cmd +} + func timeoutFlags(cmd *cobra.Command) *cobra.Command { cmd.Flags().Uint64P(flagTimeoutHeightOffset, "y", 0, "set timeout height offset for ") cmd.Flags().DurationP(flagTimeoutTimeOffset, "c", time.Duration(0), "specify the path to relay over") @@ -164,6 +179,14 @@ func timeoutFlag(cmd *cobra.Command) *cobra.Command { return cmd } +func versionFlag(cmd *cobra.Command) *cobra.Command { + cmd.Flags().StringP(flagVersion, "v", "ics20-1", "version of channel to create") + if err := viper.BindPFlag(flagVersion, cmd.Flags().Lookup(flagVersion)); err != nil { + panic(err) + } + return cmd +} + func forceFlag(cmd *cobra.Command) *cobra.Command { cmd.Flags().BoolP(flagForce, "f", false, "option to force non-standard behavior such as initialization of light client from configured chain or generation of new path") //nolint:lll if err := viper.BindPFlag(flagForce, cmd.Flags().Lookup(flagForce)); err != nil { @@ -189,7 +212,7 @@ func urlFlag(cmd *cobra.Command) *cobra.Command { } func strategyFlag(cmd *cobra.Command) *cobra.Command { - cmd.Flags().StringP(flagMaxTxSize, "s", "2", "maximum size (in MB) of the messages in a relay transaction") + cmd.Flags().StringP(flagMaxTxSize, "s", "2", "strategy of path to generate of the messages in a relay transaction") cmd.Flags().StringP(flagMaxMsgLength, "l", "5", "maximum number of messages in a relay transaction") if err := viper.BindPFlag(flagMaxTxSize, cmd.Flags().Lookup(flagMaxTxSize)); err != nil { panic(err) diff --git a/cmd/light.go b/cmd/light.go index e587ace4d39..1d1beff6c9e 100644 --- a/cmd/light.go +++ b/cmd/light.go @@ -120,7 +120,6 @@ func updateLightCmd() *cobra.Command { return err } - // TODO: more fun printing here like time deltas? fmt.Printf("Updated light client for %s from height %d -> height %d\n", args[0], bh.Header.Height, ah.Header.Height) return nil }, diff --git a/cmd/paths.go b/cmd/paths.go index 32c1e426f88..fba0552cb85 100644 --- a/cmd/paths.go +++ b/cmd/paths.go @@ -9,13 +9,14 @@ import ( clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" conntypes "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types" chantypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types" + "github.com/cosmos/cosmos-sdk/x/ibc/core/exported" + tmclient "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types" "github.com/cosmos/relayer/relayer" "github.com/spf13/cobra" + "golang.org/x/sync/errgroup" "gopkg.in/yaml.v2" ) -const OPEN = "OPEN" - func pathsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "paths", @@ -39,38 +40,35 @@ connection, and channel ids from both the source and destination chains as well func pathsGenCmd() *cobra.Command { cmd := &cobra.Command{ - Use: "generate [src-chain-id] [src-port] [dst-chain-id] [dst-port] [name]", + Use: "generate [src-chain-id] [dst-chain-id] [name]", Aliases: []string{"gen"}, Short: "generate identifiers for a new path between src and dst, reusing any that exist", - Args: cobra.ExactArgs(5), - RunE: func(cmd *cobra.Command, args []string) error { - src, srcPort, dst, dstPort := args[0], args[1], args[2], args[3] - path := &relayer.Path{ - Src: &relayer.PathEnd{ - ChainID: src, - PortID: srcPort, - Version: "ics20-1", - }, - Dst: &relayer.PathEnd{ - ChainID: dst, - PortID: dstPort, - Version: "ics20-1", - }, - Strategy: &relayer.StrategyCfg{ - Type: "naive", - }, - } - c, err := config.Chains.Gets(src, dst) - if err != nil { + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) (err error) { + var ( + src, dst, pth = args[0], args[1], args[2] + c map[string]*relayer.Chain + eg errgroup.Group + srcClients, dstClients *clienttypes.QueryClientStatesResponse + srcConns, dstConns *conntypes.QueryConnectionsResponse + srcCon, dstCon *conntypes.IdentifiedConnection + srcChans, dstChans *chantypes.QueryChannelsResponse + srcChan, dstChan *chantypes.IdentifiedChannel + ) + if c, err = config.Chains.Gets(src, dst); err != nil { return fmt.Errorf("chains need to be configured before paths to them can be added: %w", err) } - - unordered, err := cmd.Flags().GetBool(flagOrder) - if err != nil { - return err + version, _ := cmd.Flags().GetString(flagVersion) + strategy, _ := cmd.Flags().GetString(flagStrategy) + port, _ := cmd.Flags().GetString(flagPort) + path := &relayer.Path{ + Src: &relayer.PathEnd{ChainID: src, PortID: port, Version: version}, + Dst: &relayer.PathEnd{ChainID: dst, PortID: port, Version: version}, + Strategy: &relayer.StrategyCfg{Type: strategy}, } - if unordered { + // get desired order of the channel + if unordered, _ := cmd.Flags().GetBool(flagOrder); unordered { path.Src.Order = UNORDERED path.Dst.Order = UNORDERED } else { @@ -78,107 +76,130 @@ func pathsGenCmd() *cobra.Command { path.Dst.Order = ORDERED } - force, err := cmd.Flags().GetBool(flagForce) - if err != nil { - return err - } - - if force { - path.Dst.ClientID = relayer.RandLowerCaseLetterString(10) - path.Src.ClientID = relayer.RandLowerCaseLetterString(10) - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.AddForce(args[4], path); err != nil { + // if -f is passed, generate a random path between the two chains + if force, _ := cmd.Flags().GetBool(flagForce); force { + path.GenSrcClientID() + path.GenDstClientID() + path.GenSrcConnID() + path.GenDstConnID() + path.GenSrcChanID() + path.GenDstChanID() + // validate it... + if err = config.Paths.AddForce(pth, path); err != nil { return err } + logPathGen(pth) + // ...then add it to the config file return overWriteConfig(cmd, config) } - srcClients, err := c[src].QueryClients(1, 1000) - if err != nil { + // see if there are existing clients that can be reused + eg.Go(func() error { + srcClients, err = c[src].QueryClients(0, 1000) + return err + }) + eg.Go(func() error { + dstClients, err = c[dst].QueryClients(0, 1000) + return err + }) + if eg.Wait(); err != nil { return err } - for _, c := range srcClients.ClientStates { - // TODO: support other client types through a switch here as they become available - clnt, _ := clienttypes.UnpackClientState(c.ClientState) - if clnt != nil { - if relayer.MustGetHeight(clnt.GetLatestHeight()) != 0 && !clnt.IsFrozen() { - path.Src.ClientID = c.ClientId + for _, idCs := range srcClients.ClientStates { + var clnt exported.ClientState + if err = idCs.UnpackInterfaces(c[src].Encoding.Marshaler); err != nil { + return err + } + if clnt, err = clienttypes.UnpackClientState(idCs.ClientState); err != nil { + return err + } + switch cs := clnt.(type) { + case *tmclient.ClientState: + // if the client is an active tendermint client for the counterparty chain then we reuse it + if cs.ChainId == c[dst].ChainID && !cs.IsFrozen() { + path.Src.ClientID = idCs.ClientId } + default: } } - dstClients, err := c[dst].QueryClients(1, 1000) - if err != nil { - return err - } - - for _, c := range dstClients.ClientStates { - // TODO: support other client types through a switch here as they become available - clnt, _ := clienttypes.UnpackClientState(c.ClientState) - if clnt != nil { - if relayer.MustGetHeight(clnt.GetLatestHeight()) != 0 && !clnt.IsFrozen() { - path.Dst.ClientID = c.ClientId + for _, idCs := range dstClients.ClientStates { + var clnt exported.ClientState + if err = idCs.UnpackInterfaces(c[dst].Encoding.Marshaler); err != nil { + return err + } + if clnt, err = clienttypes.UnpackClientState(idCs.ClientState); err != nil { + return err + } + switch cs := clnt.(type) { + case *tmclient.ClientState: + // if the client is an active tendermint client for the counterparty chain then we reuse it + if cs.ChainId == c[src].ChainID && !cs.IsFrozen() { + path.Dst.ClientID = idCs.ClientId } + default: } } switch { + // If there aren't any matching clients between chains, generate case path.Src.ClientID == "" && path.Dst.ClientID == "": - path.Src.ClientID = relayer.RandLowerCaseLetterString(10) - path.Dst.ClientID = relayer.RandLowerCaseLetterString(10) - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenSrcClientID() + path.GenDstClientID() + path.GenSrcConnID() + path.GenSrcConnID() + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) case path.Src.ClientID == "" && path.Dst.ClientID != "": - path.Src.ClientID = relayer.RandLowerCaseLetterString(10) - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenSrcClientID() + path.GenSrcConnID() + path.GenSrcConnID() + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) case path.Dst.ClientID == "" && path.Src.ClientID != "": - path.Dst.ClientID = relayer.RandLowerCaseLetterString(10) - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenDstClientID() + path.GenSrcConnID() + path.GenSrcConnID() + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) } - srcConns, err := c[src].QueryConnections(1, 1000) - if err != nil { + // see if there are existing connections that can be reused + eg.Go(func() error { + srcConns, err = c[src].QueryConnections(0, 1000) + return err + }) + eg.Go(func() error { + dstConns, err = c[dst].QueryConnections(0, 1000) + return err + }) + if err = eg.Wait(); err != nil { return err } - var srcCon *conntypes.IdentifiedConnection + // find connections with the appropriate client id for _, c := range srcConns.Connections { if c.ClientId == path.Src.ClientID { srcCon = c path.Src.ConnectionID = c.Id } } - - dstConns, err := c[dst].QueryConnections(1, 1000) - if err != nil { - return err - } - - var dstCon *conntypes.IdentifiedConnection for _, c := range dstConns.Connections { if c.ClientId == path.Dst.ClientID { dstCon = c @@ -193,35 +214,43 @@ func pathsGenCmd() *cobra.Command { // we should generate a new connection identifier dstCpForSrc := srcCon.Counterparty.ConnectionId == dstCon.Id srcCpForDst := dstCon.Counterparty.ConnectionId == srcCon.Id - srcOpen := srcCon.State.String() == OPEN - dstOpen := dstCon.State.String() == OPEN + srcOpen := srcCon.State == conntypes.OPEN + dstOpen := dstCon.State == conntypes.OPEN if !(dstCpForSrc && srcCpForDst && srcOpen && dstOpen) { - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenSrcConnID() + path.GenDstConnID() + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) } default: - path.Src.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Dst.ConnectionID = relayer.RandLowerCaseLetterString(10) - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenSrcConnID() + path.GenDstConnID() + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) } - srcChans, err := c[src].QueryChannels(1, 1000) - if err != nil { + eg.Go(func() error { + srcChans, err = c[src].QueryChannels(0, 1000) + return err + }) + eg.Go(func() error { + dstChans, err = c[dst].QueryChannels(0, 1000) + return err + }) + if err = eg.Wait(); err != nil { return err } - var srcChan *chantypes.IdentifiedChannel for _, c := range srcChans.Channels { if c.ConnectionHops[0] == path.Src.ConnectionID { srcChan = c @@ -229,12 +258,6 @@ func pathsGenCmd() *cobra.Command { } } - dstChans, err := c[dst].QueryChannels(1, 1000) - if err != nil { - return err - } - - var dstChan *chantypes.IdentifiedChannel for _, c := range dstChans.Channels { if c.ConnectionHops[0] == path.Dst.ConnectionID { dstChan = c @@ -244,33 +267,44 @@ func pathsGenCmd() *cobra.Command { switch { case path.Src.ChannelID != "" && path.Dst.ChannelID != "": + // If we have identified a channel, make sure that each end is the + // other's counterparty and that the channel is open. In the failure case + // we should generate a new channel identifier dstCpForSrc := srcChan.Counterparty.ChannelId == dstChan.ChannelId srcCpForDst := dstChan.Counterparty.ChannelId == srcChan.ChannelId - srcOpen := srcChan.State.String() == OPEN - dstOpen := dstChan.State.String() == OPEN + srcOpen := srcChan.State == chantypes.OPEN + dstOpen := dstChan.State == chantypes.OPEN srcPort := srcChan.PortId == path.Src.PortID dstPort := dstChan.PortId == path.Dst.PortID - srcOrder := srcChan.Ordering.String() == path.Src.Order - dstOrder := dstChan.Ordering.String() == path.Dst.Order - if !(dstCpForSrc && srcCpForDst && srcOpen && dstOpen && srcPort && dstPort && srcOrder && dstOrder) { - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) + srcOrder := srcChan.Ordering == path.Src.GetOrder() + dstOrder := dstChan.Ordering == path.Dst.GetOrder() + srcVersion := srcChan.Version == path.Src.Version + dstVersion := dstChan.Version == path.Dst.Version + if !(dstCpForSrc && srcCpForDst && srcOpen && dstOpen && srcPort && dstPort && srcOrder && dstOrder && srcVersion && dstVersion) { + path.GenSrcChanID() + path.GenDstChanID() } - if err = config.Paths.Add(args[4], path); err != nil { + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) default: - path.Src.ChannelID = relayer.RandLowerCaseLetterString(10) - path.Dst.ChannelID = relayer.RandLowerCaseLetterString(10) - if err = config.Paths.Add(args[4], path); err != nil { + path.GenSrcChanID() + path.GenDstChanID() + if err = config.Paths.Add(pth, path); err != nil { return err } + logPathGen(pth) return overWriteConfig(cmd, config) } }, } - return forceFlag(orderFlag(cmd)) + return forceFlag(orderFlag(versionFlag(pathStrategy(portFlag(cmd))))) +} + +func logPathGen(pth string) { + fmt.Printf("Generated path(%s), run 'rly paths show %s --yaml' to see details\n", pth, pth) } func pathsDeleteCmd() *cobra.Command { @@ -297,14 +331,8 @@ func pathsListCmd() *cobra.Command { Aliases: []string{"l"}, Short: "print out configured paths", RunE: func(cmd *cobra.Command, args []string) error { - jsn, err := cmd.Flags().GetBool(flagJSON) - if err != nil { - return err - } - yml, err := cmd.Flags().GetBool(flagYAML) - if err != nil { - return err - } + jsn, _ := cmd.Flags().GetBool(flagJSON) + yml, _ := cmd.Flags().GetBool(flagYAML) switch { case yml && jsn: return fmt.Errorf("can't pass both --json and --yaml, must pick one") @@ -325,74 +353,12 @@ func pathsListCmd() *cobra.Command { default: i := 0 for k, pth := range config.Paths { - // TODO: replace this with relayer.QueryPathStatus - var ( - chains = xIcon - clients = xIcon - connection = xIcon - channel = xIcon - ) - src, dst := pth.Src.ChainID, pth.Dst.ChainID - ch, err := config.Chains.Gets(src, dst) - if err == nil { - chains = check - err = ch[src].SetPath(pth.Src) - if err != nil { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - err = ch[dst].SetPath(pth.Dst) - if err != nil { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - } else { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - - srcCs, err := ch[src].QueryClientState(0) - dstCs, _ := ch[dst].QueryClientState(0) - if err == nil && srcCs != nil && dstCs != nil { - clients = check - } else { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - - srch, err := ch[src].QueryLatestHeight() - dsth, _ := ch[dst].QueryLatestHeight() - if err != nil || srch == -1 || dsth == -1 { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - - srcConn, err := ch[src].QueryConnection(srch) - dstConn, _ := ch[dst].QueryConnection(dsth) - if err == nil && srcConn.Connection.State == conntypes.OPEN && dstConn.Connection.State == conntypes.OPEN { - connection = check - } else { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue - } - - srcChan, err := ch[src].QueryChannel(srch) - dstChan, _ := ch[dst].QueryChannel(dsth) - if err == nil && srcChan.Channel.State == chantypes.OPEN && dstChan.Channel.State == chantypes.OPEN { - channel = check - } else { - printPath(i, k, pth, chains, clients, connection, channel) - i++ - continue + chains, err := config.Chains.Gets(pth.Src.ChainID, pth.Dst.ChainID) + if err != nil { + return err } - - printPath(i, k, pth, chains, clients, connection, channel) + stat := pth.QueryPathStatus(chains[pth.Src.ChainID], chains[pth.Dst.ChainID]).Status + printPath(i, k, pth, checkmark(stat.Chains), checkmark(stat.Clients), checkmark(stat.Connection), checkmark(stat.Channel)) i++ } return nil @@ -407,18 +373,6 @@ func printPath(i int, k string, pth *relayer.Path, chains, clients, connection, i, k, chains, clients, connection, channel, pth.Src.ChainID, pth.Src.PortID, pth.Dst.ChainID, pth.Dst.PortID) } -type PathStatus struct { - Chains bool `yaml:"chains" json:"chains"` - Clients bool `yaml:"clients" json:"clients"` - Connection bool `yaml:"connection" json:"connection"` - Channel bool `yaml:"channel" json:"channel"` -} - -type PathWithStatus struct { - Path *relayer.Path `yaml:"path" json:"chains"` - Status PathStatus `yaml:"status" json:"status"` -} - func checkmark(status bool) string { if status { return check @@ -437,67 +391,16 @@ func pathsShowCmd() *cobra.Command { if err != nil { return err } - - jsn, err := cmd.Flags().GetBool(flagJSON) - if err != nil { - return err - } - yml, err := cmd.Flags().GetBool(flagYAML) + chains, err := config.Chains.Gets(path.Src.ChainID, path.Dst.ChainID) if err != nil { return err } - if yml && jsn { - return fmt.Errorf("can't pass both --json and --yaml, must pick one") - } - // TODO: transition this to use relayer.QueryPathStatus - var ( - chains = false - clients = false - connection = false - channel = false - srch, dsth int64 - ) - src, dst := path.Src.ChainID, path.Dst.ChainID - ch, err := config.Chains.Gets(src, dst) - if err == nil { - srch, err = ch[src].QueryLatestHeight() - dsth, _ = ch[dst].QueryLatestHeight() - if err == nil { - chains = true - _ = ch[src].SetPath(path.Src) - _ = ch[dst].SetPath(path.Dst) - } - } - - srcCs, err := ch[src].QueryClientState(srch) - dstCs, _ := ch[dst].QueryClientState(dsth) - if err == nil && srcCs != nil && dstCs != nil { - clients = true - } - - srcConn, err := ch[src].QueryConnection(srch) - dstConn, _ := ch[dst].QueryConnection(dsth) - if err == nil && srcConn.Connection.State == conntypes.OPEN && dstConn.Connection.State == conntypes.OPEN { - connection = true - } - - srcChan, err := ch[src].QueryChannel(srch) - dstChan, _ := ch[dst].QueryChannel(dsth) - if err == nil && srcChan.Channel.State == chantypes.OPEN && dstChan.Channel.State == chantypes.OPEN { - channel = true - } - - pathStatus := PathStatus{ - Chains: chains, - Clients: clients, - Connection: connection, - Channel: channel, - } - pathWithStatus := PathWithStatus{ - Path: path, - Status: pathStatus, - } + jsn, _ := cmd.Flags().GetBool(flagJSON) + yml, _ := cmd.Flags().GetBool(flagYAML) + pathWithStatus := path.QueryPathStatus(chains[path.Src.ChainID], chains[path.Dst.ChainID]) switch { + case yml && jsn: + return fmt.Errorf("can't pass both --json and --yaml, must pick one") case yml: out, err := yaml.Marshal(pathWithStatus) if err != nil { @@ -513,26 +416,7 @@ func pathsShowCmd() *cobra.Command { fmt.Println(string(out)) return nil default: - fmt.Printf(`Path "%s" strategy(%s): - SRC(%s) - ClientID: %s - ConnectionID: %s - ChannelID: %s - PortID: %s - DST(%s) - ClientID: %s - ConnectionID: %s - ChannelID: %s - PortID: %s - STATUS: - Chains: %s - Clients: %s - Connection: %s - Channel: %s -`, args[0], path.Strategy.Type, path.Src.ChainID, - path.Src.ClientID, path.Src.ConnectionID, path.Src.ChannelID, path.Src.PortID, - path.Dst.ChainID, path.Dst.ClientID, path.Dst.ConnectionID, path.Dst.ChannelID, path.Dst.PortID, - checkmark(chains), checkmark(clients), checkmark(connection), checkmark(channel)) + fmt.Println(pathWithStatus.PrintString(args[0])) } return nil diff --git a/go.sum b/go.sum index 38b8cb8e84a..cf2fd0ef907 100644 --- a/go.sum +++ b/go.sum @@ -740,6 +740,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/relayer/path.go b/relayer/path.go index cec4f49268d..c511d773b41 100644 --- a/relayer/path.go +++ b/relayer/path.go @@ -3,11 +3,19 @@ package relayer import ( "fmt" + "golang.org/x/sync/errgroup" "gopkg.in/yaml.v2" + clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types" + conntypes "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection/types" chantypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types" ) +const ( + check = "✔" + xIcon = "✘" +) + // Paths represent connection paths between chains type Paths map[string]*Path @@ -94,9 +102,27 @@ type Path struct { Strategy *StrategyCfg `yaml:"strategy" json:"strategy"` } +// GenSrcClientID generates the specififed identifier +func (p *Path) GenSrcClientID() { p.Src.ClientID = RandLowerCaseLetterString(10) } + +// GenDstClientID generates the specififed identifier +func (p *Path) GenDstClientID() { p.Dst.ClientID = RandLowerCaseLetterString(10) } + +// GenSrcConnID generates the specififed identifier +func (p *Path) GenSrcConnID() { p.Src.ConnectionID = RandLowerCaseLetterString(10) } + +// GenDstConnID generates the specififed identifier +func (p *Path) GenDstConnID() { p.Dst.ConnectionID = RandLowerCaseLetterString(10) } + +// GenSrcChanID generates the specififed identifier +func (p *Path) GenSrcChanID() { p.Src.ChannelID = RandLowerCaseLetterString(10) } + +// GenDstChanID generates the specififed identifier +func (p *Path) GenDstChanID() { p.Dst.ChannelID = RandLowerCaseLetterString(10) } + // Ordered returns true if the path is ordered and false if otherwise func (p *Path) Ordered() bool { - return p.Src.getOrder() == chantypes.ORDERED + return p.Src.GetOrder() == chantypes.ORDERED } // Validate checks that a path is valid @@ -162,3 +188,122 @@ func GenPath(srcChainID, dstChainID, srcPortID, dstPortID, order string, version }, } } + +// PathStatus holds the status of the primatives in the path +type PathStatus struct { + Chains bool `yaml:"chains" json:"chains"` + Clients bool `yaml:"clients" json:"clients"` + Connection bool `yaml:"connection" json:"connection"` + Channel bool `yaml:"channel" json:"channel"` +} + +// PathWithStatus is used for showing the status of the path +type PathWithStatus struct { + Path *Path `yaml:"path" json:"chains"` + Status PathStatus `yaml:"status" json:"status"` +} + +// QueryPathStatus returns an instance of the path struct with some attached data about +// the current status of the path +func (p *Path) QueryPathStatus(src, dst *Chain) *PathWithStatus { + // TODO: add sanity check for paths and chainIDs + var ( + err error + eg errgroup.Group + srch, dsth int64 + srcCs, dstCs *clienttypes.QueryClientStateResponse + srcConn, dstConn *conntypes.QueryConnectionResponse + srcChan, dstChan *chantypes.QueryChannelResponse + + out = &PathWithStatus{Path: p, Status: PathStatus{false, false, false, false}} + ) + eg.Go(func() error { + srch, err = src.QueryLatestHeight() + return err + }) + eg.Go(func() error { + dsth, err = dst.QueryLatestHeight() + return err + }) + if eg.Wait(); err != nil { + return out + } + out.Status.Chains = true + if err = src.SetPath(p.Src); err != nil { + return out + } + if err = dst.SetPath(p.Dst); err != nil { + return out + } + + eg.Go(func() error { + srcCs, err = src.QueryClientState(srch) + return err + }) + eg.Go(func() error { + dstCs, err = dst.QueryClientState(dsth) + return err + }) + if err = eg.Wait(); err != nil || srcCs == nil || dstCs == nil { + return out + } + out.Status.Clients = true + + eg.Go(func() error { + srcConn, err = src.QueryConnection(srch) + return err + }) + eg.Go(func() error { + dstConn, err = dst.QueryConnection(dsth) + return err + }) + if err = eg.Wait(); err != nil || srcConn.Connection.State != conntypes.OPEN || dstConn.Connection.State != conntypes.OPEN { + return out + } + out.Status.Connection = true + + eg.Go(func() error { + srcChan, err = src.QueryChannel(srch) + return err + }) + eg.Go(func() error { + dstChan, err = dst.QueryChannel(dsth) + return err + }) + if err = eg.Wait(); err != nil || srcChan.Channel.State != chantypes.OPEN || dstChan.Channel.State != chantypes.OPEN { + return out + } + out.Status.Channel = true + return out +} + +// PrintString prints a string representations of the path status +func (ps *PathWithStatus) PrintString(name string) string { + pth := ps.Path + return fmt.Sprintf(`Path "%s" strategy(%s): + SRC(%s) + ClientID: %s + ConnectionID: %s + ChannelID: %s + PortID: %s + DST(%s) + ClientID: %s + ConnectionID: %s + ChannelID: %s + PortID: %s + STATUS: + Chains: %s + Clients: %s + Connection: %s + Channel: %s`, name, pth.Strategy.Type, pth.Src.ChainID, + pth.Src.ClientID, pth.Src.ConnectionID, pth.Src.ChannelID, pth.Src.PortID, + pth.Dst.ChainID, pth.Dst.ClientID, pth.Dst.ConnectionID, pth.Dst.ChannelID, pth.Dst.PortID, + checkmark(ps.Status.Chains), checkmark(ps.Status.Clients), checkmark(ps.Status.Connection), checkmark(ps.Status.Channel)) +} + +func checkmark(status bool) string { + if status { + return check + } + return xIcon +} diff --git a/relayer/pathEnd.go b/relayer/pathEnd.go index 3b52ebdc83f..f59e949617f 100644 --- a/relayer/pathEnd.go +++ b/relayer/pathEnd.go @@ -43,7 +43,7 @@ func OrderFromString(order string) chantypes.Order { } } -func (pe *PathEnd) getOrder() chantypes.Order { +func (pe *PathEnd) GetOrder() chantypes.Order { return OrderFromString(strings.ToUpper(pe.Order)) } @@ -198,7 +198,7 @@ func (pe *PathEnd) ChanInit(dst *PathEnd, signer sdk.AccAddress) sdk.Msg { pe.PortID, pe.ChannelID, pe.Version, - pe.getOrder(), + pe.GetOrder(), []string{pe.ConnectionID}, dst.PortID, dst.ChannelID, From 3a3083926afd74a930dec7c955c1c4416b16b5c9 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Wed, 4 Nov 2020 14:56:47 -0600 Subject: [PATCH 2/2] Merge PR #274: feat: allow building a shared library --- Dockerfile | 31 +++++ Makefile | 4 + README.md | 36 +++--- clib/main.go | 130 ++++++++++++++++++++ cmd/start.go | 11 ++ cmd/tx.go | 21 ++++ configs/agoric/demo.json | 2 +- configs/agoric/ibc-0.json | 1 + configs/agoric/ibc-1.json | 1 + configs/agoric/ibc0.json | 1 - configs/agoric/ibc1.json | 1 - configs/akash/demo.json | 2 +- configs/akash/ibc-0.json | 1 + configs/akash/ibc-1.json | 1 + configs/akash/ibc0.json | 1 - configs/akash/ibc1.json | 1 - configs/demo/demo.json | 2 +- configs/demo/ibc-0.json | 1 + configs/demo/ibc-1.json | 1 + configs/demo/ibc0.json | 1 - configs/demo/ibc1.json | 1 - configs/four/ibc-0.json | 1 + configs/four/ibc-1.json | 1 + configs/four/ibc-2.json | 1 + configs/four/ibc-3.json | 1 + configs/four/ibc0.json | 1 - configs/four/ibc1.json | 1 - configs/four/ibc2.json | 1 - configs/four/ibc3.json | 1 - configs/four/onetwo.json | 2 +- configs/four/threezero.json | 2 +- configs/four/twothree.json | 2 +- configs/four/zeroone.json | 2 +- configs/gaia/demo.json | 2 +- configs/gaia/ibc-0.json | 1 + configs/gaia/ibc-1.json | 1 + configs/gaia/ibc0.json | 1 - configs/gaia/ibc1.json | 1 - configs/three/demo.json | 2 +- configs/three/demo2.json | 2 +- configs/three/ibc-0.json | 1 + configs/three/ibc-1.json | 1 + configs/three/ibc-2.json | 1 + configs/three/ibc0.json | 1 - configs/three/ibc1.json | 1 - configs/three/ibc2.json | 1 - dev-env | 4 +- docker-compose.yaml | 16 +-- docs/commands.md | 28 ++--- docs/testing.md | 24 ++-- relayer/channel-tx.go | 16 +-- relayer/client-tx.go | 4 +- relayer/connection-tx.go | 10 +- relayer/controller.go | 35 ++++++ relayer/naive-strategy.go | 6 +- relayer/packet-tx.go | 2 +- relayer/path.go | 5 + relayer/pathEnd.go | 17 +++ relayer/relayMsgs.go | 92 ++++++++++++-- scripts/config-relayer | 12 +- scripts/config-relayer-akash | 12 +- scripts/config-three | 18 +-- scripts/four-chainz | 24 ++-- scripts/nchainz | 7 +- scripts/three-chainz | 6 +- scripts/two-chainz | 4 +- scripts/two-chainz-akash | 4 +- test/relayer_gaia_test.go | 8 +- testnets/README.md | 19 +-- testnets/relayer-alpha-2/vitwitchain-1.json | 2 +- testnets/relayer-alpha/vitwitchain-1.json | 2 +- 71 files changed, 492 insertions(+), 168 deletions(-) create mode 100644 Dockerfile create mode 100644 clib/main.go create mode 100644 configs/agoric/ibc-0.json create mode 100644 configs/agoric/ibc-1.json delete mode 100644 configs/agoric/ibc0.json delete mode 100644 configs/agoric/ibc1.json create mode 100644 configs/akash/ibc-0.json create mode 100644 configs/akash/ibc-1.json delete mode 100644 configs/akash/ibc0.json delete mode 100644 configs/akash/ibc1.json create mode 100644 configs/demo/ibc-0.json create mode 100644 configs/demo/ibc-1.json delete mode 100644 configs/demo/ibc0.json delete mode 100644 configs/demo/ibc1.json create mode 100644 configs/four/ibc-0.json create mode 100644 configs/four/ibc-1.json create mode 100644 configs/four/ibc-2.json create mode 100644 configs/four/ibc-3.json delete mode 100644 configs/four/ibc0.json delete mode 100644 configs/four/ibc1.json delete mode 100644 configs/four/ibc2.json delete mode 100644 configs/four/ibc3.json create mode 100644 configs/gaia/ibc-0.json create mode 100644 configs/gaia/ibc-1.json delete mode 100644 configs/gaia/ibc0.json delete mode 100644 configs/gaia/ibc1.json create mode 100644 configs/three/ibc-0.json create mode 100644 configs/three/ibc-1.json create mode 100644 configs/three/ibc-2.json delete mode 100644 configs/three/ibc0.json delete mode 100644 configs/three/ibc1.json delete mode 100644 configs/three/ibc2.json create mode 100644 relayer/controller.go diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000000..c2d006efcab --- /dev/null +++ b/Dockerfile @@ -0,0 +1,31 @@ +FROM golang:alpine as BUILD + +WORKDIR /relayer + +# Copy the files from host +COPY . . + +# Update and install needed deps prioir to installing the binary. +RUN apk update && \ + apk --no-cache add make=4.2.1-r2 git=2.24.3-r0 && \ + make install + +FROM alpine:edge + +ENV RELAYER /relayer + +RUN addgroup rlyuser && \ + adduser -S -G rlyuser rlyuser -h "$RELAYER" + +USER rlyuser + +# Define working directory +WORKDIR $RELAYER + +# Copy binary from BUILD +COPY --from=BUILD /go/bin/rly /usr/bin/rly + +ENTRYPOINT ["/usr/bin/rly"] + +# Make config available ofr mutaitons +VOLUME [ $RELAYER ] diff --git a/Makefile b/Makefile index ec484d2fdbe..b134f4c65dd 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,10 @@ build-zip: go.sum @GOOS=windows GOARCH=amd64 go build -mod=readonly $(BUILD_FLAGS) -o build/windows-amd64-rly.exe main.go @tar -czvf release.tar.gz ./build +# Compile the relayer as a shared library to be linked into another program +compile-clib: + go build -v -mod=readonly -buildmode=c-shared -o librelayer.so ./clib + install: go.sum @echo "installing rly binary..." @go build -mod=readonly $(BUILD_FLAGS) -o $${GOBIN-$${GOPATH-$$HOME/go}/bin}/rly main.go diff --git a/README.md b/README.md index e5b504105a8..ee632b8d1fe 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The Cosmos IBC `relayer` package contains a basic relayer implementation that is meant for users wishing to relay packets/data between sets of IBC enabled chains. -In additon, it is well documented and intended as an example where anyone who is +In addition, it is well documented and intended as an example where anyone who is interested in building their own relayer can come for complete, working, examples. ### Security Notice @@ -15,13 +15,13 @@ If you would like to report a security critical bug related to the relayer repo, ## Code of Conduct -The iqlusion team is dedicated to providing an inclusive and harrassment free experience for contributors. Please visit [Code of Conduct](CODE_OF_CONDUCT.md) for more information. +The iqlusion team is dedicated to providing an inclusive and harassment free experience for contributors. Please visit [Code of Conduct](CODE_OF_CONDUCT.md) for more information. ## Testnet If you would like to join a relayer testnet, please [check out the instructions](./testnets/README.md). -### Compatability Table: +### Compatibility Table: > NOTE: @@ -61,16 +61,16 @@ $ rly cfg add-dir configs/demo/ $ cat ~/.relayer/config/config.yaml # Now, add the key seeds from each chain to the relayer to give it funds to work with -$ rly keys restore ibc0 testkey "$(jq -r '.mnemonic' data/ibc0/key_seed.json)" -$ rly k r ibc1 testkey "$(jq -r '.mnemonic' data/ibc1/key_seed.json)" +$ rly keys restore ibc-0 testkey "$(jq -r '.mnemonic' data/ibc-0/key_seed.json)" +$ rly k r ibc-1 testkey "$(jq -r '.mnemonic' data/ibc-1/key_seed.json)" # Then its time to initialize the relayer's light clients for each chain # All data moving forward is validated by these light clients. -$ rly light init ibc0 -f -$ rly l i ibc1 -f +$ rly light init ibc-0 -f +$ rly l i ibc-1 -f # At this point the relayer --home directory is ready for normal operations between -# ibc0 and ibc1. Looking at the folder structure of the relayer at this point is helpful +# ibc-0 and ibc-1. Looking at the folder structure of the relayer at this point is helpful $ tree ~/.relayer # See if the chains are ready to relay over @@ -80,24 +80,24 @@ $ rly chains list $ rly tx link demo -d -o 3s # Check the token balances on both chains -$ rly q balance ibc0 | jq -$ rly q bal ibc1 | jq +$ rly q balance ibc-0 | jq +$ rly q bal ibc-1 | jq # Then send some tokens between the chains -$ rly tx transfer ibc0 ibc1 1000000samoleans $(rly chains address ibc1) +$ rly tx transfer ibc-0 ibc-1 1000000samoleans $(rly chains address ibc-1) $ rly tx relay demo -d # See that the transfer has completed -$ rly q bal ibc0 | jq -$ rly q bal ibc1 | jq +$ rly q bal ibc-0 | jq +$ rly q bal ibc-1 | jq -# Send the tokens back to the account on ibc0 -$ rly tx xfer ibc1 ibc0 1000000transfer/ibczeroxfer/samoleans $(rly ch addr ibc0) +# Send the tokens back to the account on ibc-0 +$ rly tx xfer ibc-1 ibc-0 1000000transfer/ibczeroxfer/samoleans $(rly ch addr ibc-0) $ rly tx rly demo -d # See that the return trip has completed -$ rly q bal ibc0 | jq -$ rly q bal ibc1 | jq +$ rly q bal ibc-0 | jq +$ rly q bal ibc-1 | jq # NOTE: you will see the stake balances decreasing on each chain. This is to pay for fees # You can change the amount of fees you are paying on each chain in the configuration. @@ -105,7 +105,7 @@ $ rly q bal ibc1 | jq ## Setting up Developer Environment -Working with the relayer can frequently involve working with local developement branches of `gaia`, `cosmos-sdk` and the `relayer`. To setup your environment to point at the local versions of the code and reduce the amount of time in your read-eval-print loops try the following: +Working with the relayer can frequently involve working with local development branches of `gaia`, `cosmos-sdk` and the `relayer`. To setup your environment to point at the local versions of the code and reduce the amount of time in your read-eval-print loops try the following: 1. Set `replace github.com/cosmos/cosmos-sdk => /path/to/local/github.com/comsos/cosmos-sdk` at the end of the `go.mod` files for the `relayer` and `gaia`. This will force building from the local version of the `cosmos-sdk` when running the `./dev-env` script. 2. After `./dev-env` has run, you can use `go run main.go` for any relayer commands you are working on. This allows you make changes and immediately test them as long as there are no server side changes. diff --git a/clib/main.go b/clib/main.go new file mode 100644 index 00000000000..9ba36b6a3e3 --- /dev/null +++ b/clib/main.go @@ -0,0 +1,130 @@ +// This is the entry point for a shared library built around the relayer. +// It depends on cgo, unlike the rly binary. +// +// This library was used as the basis for the Agoric Smart Relay: +// https://github.com/Agoric/agoric-sdk/tree/goz-smart-relay/packages/smart-relay + +package main + +// /* These comments before the import "C" are included in the C output. */ +// #include +// typedef const char* Body; +// typedef int (*sendFunc)(int, int, Body); +// inline int invokeSendFunc(sendFunc send, int port, int reply, Body str) { +// return send(port, reply, str); +// } +import "C" +import ( + "encoding/json" + "errors" + "fmt" + "os" + + "github.com/cosmos/relayer/cmd" + "github.com/cosmos/relayer/relayer" +) + +type goReturn = struct { + str string + err error +} + +var clibPort = 0 +var replies = map[int]chan goReturn{} +var lastReply = 0 + +//export RunClib +func RunClib(nodePort C.int, toNode C.sendFunc, clibArgs []*C.char) C.int { + if relayer.SendToController == nil { + relayer.SendToController = func(needReply bool, str string) (string, error) { + var rPort int + if needReply { + lastReply++ + rPort = lastReply + replies[rPort] = make(chan goReturn) + } + // Send the message. + C.invokeSendFunc(toNode, nodePort, C.int(rPort), C.CString(str)) + if !needReply { + // Return immediately + return "", nil + } + + // Block the sending goroutine while we wait for the reply + ret := <-replies[rPort] + delete(replies, rPort) + return ret.str, ret.err + } + } + + args := make([]string, len(clibArgs)) + for i, s := range clibArgs { + args[i] = C.GoString(s) + } + // fmt.Println("Starting relayer with args", args) + go func() { + os.Args = args + cmd.Execute() + // fmt.Printf("exiting with nodePort %d\n", nodePort) + if nodePort == 0 { + os.Exit(0) + } + }() + + clibPort++ + return C.int(clibPort) +} + +//export ReplyToClib +func ReplyToClib(replyPort C.int, isError C.int, str C.Body) C.int { + goStr := C.GoString(str) + returnCh := replies[int(replyPort)] + if returnCh == nil { + return C.int(0) + } + ret := goReturn{} + if int(isError) == 0 { + ret.str = goStr + } else { + ret.err = errors.New(goStr) + } + returnCh <- ret + return C.int(0) +} + +//export SendToClib +func SendToClib(port C.int, str C.Body) C.Body { + goStr := C.GoString(str) + var action relayer.DeliverMsgsAction + err := json.Unmarshal([]byte(goStr), &action) + if err == nil { + switch action.Type { + case "RELAYER_SEND": + src := relayer.UnmarshalChain(action.Src) + dst := relayer.UnmarshalChain(action.Dst) + if src == nil || dst == nil { + return C.CString("false") + } + rm := relayer.RelayMsgs{ + Succeeded: action.Succeeded, + Last: action.Last, + } + rm.Src = relayer.DecodeMsgs(src, action.SrcMsgs) + rm.Dst = relayer.DecodeMsgs(dst, action.DstMsgs) + + rm.SendWithController(src, dst, false) + if !rm.Succeeded { + return C.CString("0") + } + return C.CString(fmt.Sprintf("%d", len(rm.Src)+len(rm.Dst))) + default: + fmt.Printf("failed action.Type %s\n", action.Type) + } + } else { + fmt.Printf("failed unmarshalling %s\n", err) + } + return C.CString("false") +} + +// Do nothing in main. +func main() {} diff --git a/cmd/start.go b/cmd/start.go index fb441062eeb..364f20244c3 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -49,6 +49,17 @@ func startCmd() *cobra.Command { return err } + if relayer.SendToController != nil { + action := relayer.PathAction{ + Path: path, + Type: "RELAYER_PATH_START", + } + cont, err := relayer.ControllerUpcall(&action) + if !cont { + return err + } + } + done, err := relayer.RunStrategy(c[src], c[dst], strategy) if err != nil { return err diff --git a/cmd/tx.go b/cmd/tx.go index e88b31c4766..e0ca59960f3 100644 --- a/cmd/tx.go +++ b/cmd/tx.go @@ -16,7 +16,9 @@ limitations under the License. package cmd import ( + "fmt" "strings" + "time" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/relayer/relayer" @@ -37,6 +39,7 @@ func transactionCmd() *cobra.Command { cmd.AddCommand( linkCmd(), + linkThenStartCmd(), relayMsgsCmd(), relayAcksCmd(), xfersend(), @@ -253,6 +256,24 @@ func linkCmd() *cobra.Command { return timeoutFlag(cmd) } +func linkThenStartCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "link-then-start [path-name]", + Short: "wait for a link to come up, then start relaying packets", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + lCmd := linkCmd() + for err := lCmd.RunE(cmd, args); err != nil; err = lCmd.RunE(cmd, args) { + fmt.Printf("retrying link: %s\n", err) + time.Sleep(1 * time.Second) + } + sCmd := startCmd() + return sCmd.RunE(cmd, args) + }, + } + return timeoutFlag(cmd) +} + func relayMsgsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "relay-packets [path-name]", diff --git a/configs/agoric/demo.json b/configs/agoric/demo.json index fc50e51f943..5f24ef6adde 100644 --- a/configs/agoric/demo.json +++ b/configs/agoric/demo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer"},"dst":{"chain-id":"ibc1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer"},"strategy":{"type":"naive"}} +{"src":{"chain-id":"ibc-0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} diff --git a/configs/agoric/ibc-0.json b/configs/agoric/ibc-0.json new file mode 100644 index 00000000000..3b78db7aef1 --- /dev/null +++ b/configs/agoric/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:26657","account-prefix":"agoric","gas":200000,"gas-adjustment":1.0,"gas-prices":"","default-denom":"uagstake","trusting-period":"336h"} diff --git a/configs/agoric/ibc-1.json b/configs/agoric/ibc-1.json new file mode 100644 index 00000000000..ddfaa36635c --- /dev/null +++ b/configs/agoric/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:26557","account-prefix":"agoric","gas":200000,"gas-adjustment":1.0,"gas-prices":"","default-denom":"uagstake","trusting-period":"336h"} diff --git a/configs/agoric/ibc0.json b/configs/agoric/ibc0.json deleted file mode 100644 index 858c7b5d3fa..00000000000 --- a/configs/agoric/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:26657","account-prefix":"agoric","gas":200000,"gas-adjustment":1.0,"gas-prices":"","default-denom":"uagstake","trusting-period":"336h"} diff --git a/configs/agoric/ibc1.json b/configs/agoric/ibc1.json deleted file mode 100644 index fb154423fac..00000000000 --- a/configs/agoric/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:26557","account-prefix":"agoric","gas":200000,"gas-adjustment":1.0,"gas-prices":"","default-denom":"uagstake","trusting-period":"336h"} diff --git a/configs/akash/demo.json b/configs/akash/demo.json index 027014e07d8..6f151123faa 100644 --- a/configs/akash/demo.json +++ b/configs/akash/demo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"unordered"},"dst":{"chain-id":"ibc1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"unordered"},"strategy":{"type":"naive"}} \ No newline at end of file +{"src":{"chain-id":"ibc-0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"unordered","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"unordered","version":"ics20-1"},"strategy":{"type":"naive"}} \ No newline at end of file diff --git a/configs/akash/ibc-0.json b/configs/akash/ibc-0.json new file mode 100644 index 00000000000..a5b51cead97 --- /dev/null +++ b/configs/akash/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake","trusting-period":"336h"} diff --git a/configs/akash/ibc-1.json b/configs/akash/ibc-1.json new file mode 100644 index 00000000000..50c8b91caf2 --- /dev/null +++ b/configs/akash/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:26557","account-prefix":"akash","gas-adjustment":1.5,"gas-prices":"0.025stake", "trusting-period":"336h"} diff --git a/configs/akash/ibc0.json b/configs/akash/ibc0.json deleted file mode 100644 index 390b3e83f2a..00000000000 --- a/configs/akash/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake","trusting-period":"336h"} diff --git a/configs/akash/ibc1.json b/configs/akash/ibc1.json deleted file mode 100644 index c8d5957474a..00000000000 --- a/configs/akash/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:26557","account-prefix":"akash","gas-adjustment":1.5,"gas-prices":"0.025stake", "trusting-period":"336h"} diff --git a/configs/demo/demo.json b/configs/demo/demo.json index 027014e07d8..6f151123faa 100644 --- a/configs/demo/demo.json +++ b/configs/demo/demo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"unordered"},"dst":{"chain-id":"ibc1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"unordered"},"strategy":{"type":"naive"}} \ No newline at end of file +{"src":{"chain-id":"ibc-0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"unordered","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"unordered","version":"ics20-1"},"strategy":{"type":"naive"}} \ No newline at end of file diff --git a/configs/demo/ibc-0.json b/configs/demo/ibc-0.json new file mode 100644 index 00000000000..a5b51cead97 --- /dev/null +++ b/configs/demo/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake","trusting-period":"336h"} diff --git a/configs/demo/ibc-1.json b/configs/demo/ibc-1.json new file mode 100644 index 00000000000..7386e3c3aea --- /dev/null +++ b/configs/demo/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake", "trusting-period":"336h"} diff --git a/configs/demo/ibc0.json b/configs/demo/ibc0.json deleted file mode 100644 index 390b3e83f2a..00000000000 --- a/configs/demo/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake","trusting-period":"336h"} diff --git a/configs/demo/ibc1.json b/configs/demo/ibc1.json deleted file mode 100644 index f0143d5786d..00000000000 --- a/configs/demo/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas-adjustment":1.5,"gas-prices":"0.025stake", "trusting-period":"336h"} diff --git a/configs/four/ibc-0.json b/configs/four/ibc-0.json new file mode 100644 index 00000000000..07f5e02b2c1 --- /dev/null +++ b/configs/four/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:46657","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/four/ibc-1.json b/configs/four/ibc-1.json new file mode 100644 index 00000000000..efef173093f --- /dev/null +++ b/configs/four/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:46658","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/ibc-2.json b/configs/four/ibc-2.json new file mode 100644 index 00000000000..d803e2ec2da --- /dev/null +++ b/configs/four/ibc-2.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-2","rpc-addr":"http://localhost:46659","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/ibc-3.json b/configs/four/ibc-3.json new file mode 100644 index 00000000000..27e6461aa6b --- /dev/null +++ b/configs/four/ibc-3.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-3","rpc-addr":"http://localhost:46660","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/ibc0.json b/configs/four/ibc0.json deleted file mode 100644 index 77580bdf510..00000000000 --- a/configs/four/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:46657","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/four/ibc1.json b/configs/four/ibc1.json deleted file mode 100644 index 7a94cc05248..00000000000 --- a/configs/four/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:46658","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/ibc2.json b/configs/four/ibc2.json deleted file mode 100644 index ea42ae32b56..00000000000 --- a/configs/four/ibc2.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc2","rpc-addr":"http://localhost:46659","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/ibc3.json b/configs/four/ibc3.json deleted file mode 100644 index 47e94345428..00000000000 --- a/configs/four/ibc3.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc3","rpc-addr":"http://localhost:46660","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} \ No newline at end of file diff --git a/configs/four/onetwo.json b/configs/four/onetwo.json index aa4b00678ef..2981c395f2e 100644 --- a/configs/four/onetwo.json +++ b/configs/four/onetwo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc1","client-id":"acvfuvmoyy","connection-id":"pvsadpxocj","channel-id":"gxigiquvdc","port-id":"transfer"},"dst":{"chain-id":"ibc2","client-id":"vnsqzxwsfs","connection-id":"ikmrjehlzn","channel-id":"kzeiryubgz","port-id":"transfer"},"strategy":{"type":"naive"}} +{"src":{"chain-id":"ibc-1","client-id":"acvfuvmoyy","connection-id":"pvsadpxocj","channel-id":"gxigiquvdc","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-2","client-id":"vnsqzxwsfs","connection-id":"ikmrjehlzn","channel-id":"kzeiryubgz","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} diff --git a/configs/four/threezero.json b/configs/four/threezero.json index 2bcc8073217..f52549dda8e 100644 --- a/configs/four/threezero.json +++ b/configs/four/threezero.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc3","client-id":"zjyshingti","connection-id":"kygrljuplq","channel-id":"hdiooxmgry","port-id":"transfer"},"dst":{"chain-id":"ibc0","client-id":"vddpwioaua","connection-id":"wmvxarvtdj","channel-id":"mytxyocvdk","port-id":"transfer"},"strategy":{"type":"naive"}} +{"src":{"chain-id":"ibc-3","client-id":"zjyshingti","connection-id":"kygrljuplq","channel-id":"hdiooxmgry","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-0","client-id":"vddpwioaua","connection-id":"wmvxarvtdj","channel-id":"mytxyocvdk","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} diff --git a/configs/four/twothree.json b/configs/four/twothree.json index 37ecc675080..e4565b5853c 100644 --- a/configs/four/twothree.json +++ b/configs/four/twothree.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc2","client-id":"jluiqkandb","connection-id":"mfyxyvmogc","channel-id":"ckcplvbklp","port-id":"transfer"},"dst":{"chain-id":"ibc3","client-id":"kvhumysqxf","connection-id":"kejwjeluuz","channel-id":"pcqmpcbqgi","port-id":"transfer"},"strategy":{"type":"naive"}} +{"src":{"chain-id":"ibc-2","client-id":"jluiqkandb","connection-id":"mfyxyvmogc","channel-id":"ckcplvbklp","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-3","client-id":"kvhumysqxf","connection-id":"kejwjeluuz","channel-id":"pcqmpcbqgi","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} diff --git a/configs/four/zeroone.json b/configs/four/zeroone.json index 96999aea424..7c83cac5090 100644 --- a/configs/four/zeroone.json +++ b/configs/four/zeroone.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ytwwxbikra","connection-id":"znruvklbwm","channel-id":"spqkreyyhp","port-id":"transfer"},"dst":{"chain-id":"ibc1","client-id":"unfkygnnyq","connection-id":"jighhjlxjf","channel-id":"dkqbmdcyuk","port-id":"transfer"},"strategy":{"type":"naive"}} +{"src":{"chain-id":"ibc-0","client-id":"ytwwxbikra","connection-id":"znruvklbwm","channel-id":"spqkreyyhp","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"unfkygnnyq","connection-id":"jighhjlxjf","channel-id":"dkqbmdcyuk","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} diff --git a/configs/gaia/demo.json b/configs/gaia/demo.json index 11e47621f91..4a3e5a43952 100644 --- a/configs/gaia/demo.json +++ b/configs/gaia/demo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer"},"dst":{"chain-id":"ibc1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer"},"strategy":{"type":"naive"}} \ No newline at end of file +{"src":{"chain-id":"ibc-0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","version":"ics20-1"},"strategy":{"type":"naive"}} \ No newline at end of file diff --git a/configs/gaia/ibc-0.json b/configs/gaia/ibc-0.json new file mode 100644 index 00000000000..87b599711f3 --- /dev/null +++ b/configs/gaia/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas":200000,"gas-adjustment":1.0,"gas-prices":"0.025stake","default-denom":"stake","trusting-period":"336h"} diff --git a/configs/gaia/ibc-1.json b/configs/gaia/ibc-1.json new file mode 100644 index 00000000000..23f84a4d8de --- /dev/null +++ b/configs/gaia/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas":200000,"gas-adjustment":1.0,"gas-prices":"0.025stake","default-denom":"stake","trusting-period":"336h"} diff --git a/configs/gaia/ibc0.json b/configs/gaia/ibc0.json deleted file mode 100644 index 1dc8110b24e..00000000000 --- a/configs/gaia/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas":200000,"gas-adjustment":1.0,"gas-prices":"0.025stake","default-denom":"stake","trusting-period":"336h"} diff --git a/configs/gaia/ibc1.json b/configs/gaia/ibc1.json deleted file mode 100644 index 28f5927c1f1..00000000000 --- a/configs/gaia/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas":200000,"gas-adjustment":1.0,"gas-prices":"0.025stake","default-denom":"stake","trusting-period":"336h"} diff --git a/configs/three/demo.json b/configs/three/demo.json index 070cf365590..ed5442a2525 100644 --- a/configs/three/demo.json +++ b/configs/three/demo.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"ordered"},"dst":{"chain-id":"ibc1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"ordered"},"strategy":{"type":"naive"}} \ No newline at end of file +{"src":{"chain-id":"ibc-0","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"ordered","version":"ics20-1"},"dst":{"chain-id":"ibc-1","client-id":"ibczeroclient","connection-id":"ibczeroconnection","channel-id":"ibczeroxfer","port-id":"transfer","order":"ordered","version":"ics20-1"},"strategy":{"type":"naive"}} \ No newline at end of file diff --git a/configs/three/demo2.json b/configs/three/demo2.json index 07ccfff572d..a482bf88d62 100644 --- a/configs/three/demo2.json +++ b/configs/three/demo2.json @@ -1 +1 @@ -{"src":{"chain-id":"ibc1","client-id":"ibctwoclient","connection-id":"ibctwoconnection","channel-id":"ibctwoxfer","port-id":"transfer","order":"ordered"},"dst":{"chain-id":"ibc2","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"ordered"},"strategy":{"type":"naive"}} \ No newline at end of file +{"src":{"chain-id":"ibc-1","client-id":"ibctwoclient","connection-id":"ibctwoconnection","channel-id":"ibctwoxfer","port-id":"transfer","order":"ordered","version":"ics20-1"},"dst":{"chain-id":"ibc-2","client-id":"ibconeclient","connection-id":"ibconeconnection","channel-id":"ibconexfer","port-id":"transfer","order":"ordered","version":"ics20-1"},"strategy":{"type":"naive"}} \ No newline at end of file diff --git a/configs/three/ibc-0.json b/configs/three/ibc-0.json new file mode 100644 index 00000000000..b0f394bdc4b --- /dev/null +++ b/configs/three/ibc-0.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/three/ibc-1.json b/configs/three/ibc-1.json new file mode 100644 index 00000000000..67a06796651 --- /dev/null +++ b/configs/three/ibc-1.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/three/ibc-2.json b/configs/three/ibc-2.json new file mode 100644 index 00000000000..f3d66bb91be --- /dev/null +++ b/configs/three/ibc-2.json @@ -0,0 +1 @@ +{"key":"testkey","chain-id":"ibc-2","rpc-addr":"http://localhost:25557","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/three/ibc0.json b/configs/three/ibc0.json deleted file mode 100644 index e1223cb44ab..00000000000 --- a/configs/three/ibc0.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc0","rpc-addr":"http://localhost:26657","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/three/ibc1.json b/configs/three/ibc1.json deleted file mode 100644 index be5d469e591..00000000000 --- a/configs/three/ibc1.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc1","rpc-addr":"http://localhost:26557","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/configs/three/ibc2.json b/configs/three/ibc2.json deleted file mode 100644 index 7caebe9b401..00000000000 --- a/configs/three/ibc2.json +++ /dev/null @@ -1 +0,0 @@ -{"key":"testkey","chain-id":"ibc2","rpc-addr":"http://localhost:25557","account-prefix":"cosmos","gas-adjustment":1.0,"trusting-period":"336h"} diff --git a/dev-env b/dev-env index 8bce9a17985..cf715419ce4 100755 --- a/dev-env +++ b/dev-env @@ -22,5 +22,5 @@ echo "waiting for blocks..." sleep 3 rly tx full-path demo -d -o 3s -rly tx txf ibc0 ibc1 100000samoleans $(rly ch addr ibc1) -rly tx txf ibc1 ibc0 100000samoleans $(rly ch addr ibc0) \ No newline at end of file +rly tx txf ibc-0 ibc-1 100000samoleans $(rly ch addr ibc-1) +rly tx txf ibc-1 ibc-0 100000samoleans $(rly ch addr ibc-0) \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 136f885c3db..064e7d19707 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,30 +1,30 @@ version: "3.7" services: - ibc0: + ibc-0: image: "jackzampolin/gaiatest:gaiav3.0" ports: - "46657:26657" command: - - "ibc0" + - "ibc-0" - "${IBC0ADDR}" - ibc1: + ibc-1: image: "jackzampolin/gaiatest:gaiav3.0" ports: - "46658:26657" command: - - "ibc1" + - "ibc-1" - "${IBC1ADDR}" - ibc2: + ibc-2: image: "jackzampolin/gaiatest:gaiav3.0" ports: - "46659:26657" command: - - "ibc2" + - "ibc-2" - "${IBC2ADDR}" - ibc3: + ibc-3: image: "jackzampolin/gaiatest:gaiav3.0" ports: - "46660:26657" command: - - "ibc3" + - "ibc-3" - "${IBC3ADDR}" diff --git a/docs/commands.md b/docs/commands.md index 341995b6437..b08c23d17ac 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -182,11 +182,9 @@ rly chains address [chain-id] ## rly chains delete -Deletes the chain cofiguration data (does not clear light client or close and channels) - ### Synopsis -Deletes the chain cofiguration data (does not clear light client or close and channels) +Deletes the chain configuration data (does not clear lite client or close and channels) ``` rly chains delete [chain-id] [flags] @@ -199,7 +197,7 @@ Edits chain configuration data ### Synopsis -Set chain confuguration key's value +Set chain configuration key's value ``` rly chains edit [chain-id] [key] [value] [flags] @@ -496,18 +494,16 @@ manage light clients held by the relayer for each chain ### Subcommands -* [rly light delete](#rly-light-delete) - wipe the light client database, forcing re-initialzation on the next run -* [rly light header](#rly-light-header) - Get header from the database. 0 returns last trusted header and all others return the header at that height if stored -* [rly light init](#rly-light-init) - Initiate the light client -* [rly light update](#rly-light-update) - Update the light client by providing a new root of trust +* [rly lite delete](#rly-lite-delete) - wipe the lite client database, forcing re-initialization on the next run +* [rly lite header](#rly-lite-header) - Get header from the database. 0 returns last trusted header and all others return the header at that height if stored +* [rly lite init](#rly-lite-init) - Initiate the light client +* [rly lite update](#rly-lite-update) - Update the light client by providing a new root of trust ## rly light delete -wipe the light client database, forcing re-initialzation on the next run - ### Synopsis -wipe the light client database, forcing re-initialzation on the next run +wipe the lite client database, forcing re-initialization on the next run ``` rly light delete [chain-id] [flags] @@ -705,7 +701,7 @@ IBC Query Commands ### Synopsis -Commands to query IBC primatives, and other useful data on configured chains. +Commands to query IBC primitives, and other useful data on configured chains. ### Subcommands @@ -722,7 +718,7 @@ Commands to query IBC primatives, and other useful data on configured chains. * [rly query full-path](#rly-query-full-path) - Query for the status of clients, connections, channels and packets on a path * [rly query header](#rly-query-header) - Query the header of a chain at a given height * [rly query node-state](#rly-query-node-state) - Query the consensus state of a client at a given height -* [rly query packet-ack](#rly-query-packet-ack) - Query for the packet acknoledgement given it's sequence and channel ids +* [rly query packet-ack](#rly-query-packet-ack) - Query for the packet acknowledgement given it's sequence and channel ids * [rly query packet-commit](#rly-query-packet-commit) - Query for the packet commitment given it's sequence and channel ids * [rly query seq-send](#rly-query-seq-send) - Query the next sequence send for a given channel * [rly query tx](#rly-query-tx) - Query transaction by transaction hash @@ -954,11 +950,11 @@ rly query node-state [chain-id] [height] [flags] ## rly query packet-ack -Query for the packet acknoledgement given it's sequence and channel ids +Query for the packet acknowledgement given it's sequence and channel ids ### Synopsis -Query for the packet acknoledgement given it's sequence and channel ids +Query for the packet acknowledgement given it's sequence and channel ids ``` rly query packet-ack [chain-id] [channel-id] [port-id] [seq] [flags] @@ -1438,7 +1434,7 @@ create a connection between chains, passing in identifiers ### Synopsis -This command creates the next handshake message given a specifc set of identifiers. If the command fails, you can safely run it again to repair an unfinished connection +This command creates the next handshake message given a specific set of identifiers. If the command fails, you can safely run it again to repair an unfinished connection ``` rly transact raw connection-step [src-chain-id] [dst-chain-id] [src-client-id] [dst-client-id] [src-connection-id] [dst-connection-id] [flags] diff --git a/docs/testing.md b/docs/testing.md index 2d04c36849f..8732e13b20a 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,23 +1,23 @@ # Testing -The relayer contains a testing framework designed to be used to test compatability between different cosmos-sdk based chains for IBC relaying. This will be especially useful during the period where IBC is under active development as it will provide a central integration test to ensure that the many different implemenations all work together. It will also be required if you are looking to participate with a custom zone in Game of Zones. +The relayer contains a testing framework designed to be used to test compatibility between different cosmos-sdk based chains for IBC relaying. This will be especially useful during the period where IBC is under active development as it will provide a central integration test to ensure that the many different implementations all work together. It will also be required if you are looking to participate with a custom zone in Game of Zones. ## Using the test framework -Because of the nature of the relayer (i.e. it is meant to run against different chains), mocking out the interfaces for unit tests would be prohibitively expensive from a resources point of view. Because of this, I've decided to go with a full integration testing framework that tests the user-critical paths of the relayer code for each chain to ensure compatability between the chains and a functional Game of Zones. To add your chain to the framework, follow the guide below: +Because of the nature of the relayer (i.e. it is meant to run against different chains), mocking out the interfaces for unit tests would be prohibitively expensive from a resources point of view. Because of this, I've decided to go with a full integration testing framework that tests the user-critical paths of the relayer code for each chain to ensure compatibility between the chains and a functional Game of Zones. To add your chain to the framework, follow the guide below: ### Overview -The test framework is built using `go test` and `docker`. What is happening for each test is that a number of independent chains of a specified type are spun up and the relayer runs a series of transactions and tests for the expected results. We are using the [`ory/dockertest`](https://github.com/ory/dockertest) to provide a nice interface for using docker programatically w/in the tests. +The test framework is built using `go test` and `docker`. What is happening for each test is that a number of independent chains of a specified type are spun up and the relayer runs a series of transactions and tests for the expected results. We are using the [`ory/dockertest`](https://github.com/ory/dockertest) to provide a nice interface for using docker programmatically w/in the tests. ### Step 1: Write a Dockerfile and publish an image for your chain -The testing framework expects your chain to have a `Dockerfile` with an `ENTRYPOINT` script that accepts two arguements: `chain-id`, which should be unique to the individual test, and `relayer-address`, an address to include in the genesis file so that the testing relayer has access to funds. This is normally best acomplished with an `./entrypoint.sh` script that performs the necessary chain bootstrapping. The `cosmos/gaia` repositories provide an example of both: +The testing framework expects your chain to have a `Dockerfile` with an `ENTRYPOINT` script that accepts two arguments: `chain-id`, which should be unique to the individual test, and `relayer-address`, an address to include in the genesis file so that the testing relayer has access to funds. This is normally best accomplished with an `./entrypoint.sh` script that performs the necessary chain bootstrapping. The `cosmos/gaia` repositories provide an example of both: - [`./entrypoint.sh`](https://github.com/cosmos/gaia/tree/master/contrib/single-node.sh) - [`Dockerfile.test`](https://github.com/cosmos/gaia/tree/master/contrib/Dockerfile.test) -Then you need to build and push your image to a public image repository. Having it tagged with the git sha and branch is best practice. See the build proceedure for the gaia image: +Then you need to build and push your image to a public image repository. Having it tagged with the git sha and branch is best practice. See the build procedure for the gaia image: - [`Makefile`](https://github.com/cosmos/gaia/blob/master/Makefile#L164) @@ -63,7 +63,7 @@ myChainTestConfig = testChainConfig { } ``` -> NOTE: If you do any custom encoding/decoding in your chain, you may want to import your codec and attach it here. To do this, `go get` the package your codec is in, include it in the `test/test_chains.go` `import` section and instantiate your codec. You may run into build errors due to incompatable tendermint or sdk versions. Please bring your chain up the relayer version to continue with a custom codec. +> NOTE: If you do any custom encoding/decoding in your chain, you may want to import your codec and attach it here. To do this, `go get` the package your codec is in, include it in the `test/test_chains.go` `import` section and instantiate your codec. You may run into build errors due to incompatible Tendermint or SDK versions. Please bring your chain up the relayer version to continue with a custom codec. ### Step 3: Write your tests! @@ -72,8 +72,8 @@ Now you can write tests! Create a new file named `test/relayer_{chain-type}_test ```go var ( gaiaChains = []testChain{ - {"ibc0", gaiaTestConfig}, - {"ibc1", gaiaTestConfig}, + {"ibc-0", gaiaTestConfig}, + {"ibc-1", gaiaTestConfig}, } ) @@ -81,12 +81,12 @@ func TestGaiaToGaiaBasicTransfer(t *testing.T) { t.Parallel() chains := spinUpTestChains(t, gaiaChains...) - _, err := genTestPathAndSet(chains.MustGet("ibc0"), chains.MustGet("ibc1"), "transfer", "transfer") + _, err := genTestPathAndSet(chains.MustGet("ibc-0"), chains.MustGet("ibc-1"), "transfer", "transfer") require.NoError(t, err) var ( - src = chains.MustGet("ibc0") - dst = chains.MustGet("ibc1") + src = chains.MustGet("ibc-0") + dst = chains.MustGet("ibc-1") testDenom = "samoleans" dstDenom = fmt.Sprintf("%s/%s/%s", dst.PathEnd.PortID, dst.PathEnd.ChannelID, testDenom) testCoin = sdk.NewCoin(testDenom, sdk.NewInt(1000)) @@ -166,4 +166,4 @@ jobs: run: make test-mychain ``` -3. Get the \ No newline at end of file +3. Get the diff --git a/relayer/channel-tx.go b/relayer/channel-tx.go index d8d35856c1f..3dc9c5a9e96 100644 --- a/relayer/channel-tx.go +++ b/relayer/channel-tx.go @@ -36,7 +36,7 @@ func (c *Chain) CreateChannel(dst *Chain, ordered bool, to time.Duration) error switch { // In the case of success and this being the last transaction // debug logging, log created connection and break - case chanSteps.success && chanSteps.last: + case chanSteps.Success() && chanSteps.Last: srch, dsth, err := GetLatestLightHeights(c, dst) if err != nil { return err @@ -53,11 +53,11 @@ func (c *Chain) CreateChannel(dst *Chain, ordered bool, to time.Duration) error dst.ChainID, dst.PathEnd.ChannelID, dst.PathEnd.PortID)) return nil // In the case of success, reset the failures counter - case chanSteps.success: + case chanSteps.Success(): failures = 0 continue // In the case of failure, increment the failures counter and exit if this is the 3rd failure - case !chanSteps.success: + case !chanSteps.Success(): failures++ c.Log(fmt.Sprintf("retrying transaction...")) time.Sleep(5 * time.Second) @@ -167,7 +167,7 @@ func (c *Chain) CreateChannelStep(dst *Chain, ordering chantypes.Order) (*RelayM c.PathEnd.UpdateClient(dstUpdateHeader, c.MustGetAddress()), c.PathEnd.ChanConfirm(dstChan, c.MustGetAddress()), ) - out.last = true + out.Last = true // Handshake has confirmed on src (3 steps done), relay `chanOpenConfirm` and `updateClient` to dst case srcChan.Channel.State == chantypes.OPEN && dstChan.Channel.State == chantypes.TRYOPEN: @@ -178,7 +178,7 @@ func (c *Chain) CreateChannelStep(dst *Chain, ordering chantypes.Order) (*RelayM dst.PathEnd.UpdateClient(srcUpdateHeader, dst.MustGetAddress()), dst.PathEnd.ChanConfirm(srcChan, dst.MustGetAddress()), ) - out.last = true + out.Last = true } return out, nil @@ -199,7 +199,7 @@ func (c *Chain) CloseChannel(dst *Chain, to time.Duration) error { break } - if closeSteps.Send(c, dst); closeSteps.success && closeSteps.last { + if closeSteps.Send(c, dst); closeSteps.Success() && closeSteps.Last { srcChan, dstChan, err := QueryChannelPair(c, dst, 0, 0) if err != nil { return err @@ -286,7 +286,7 @@ func (c *Chain) CloseChannelStep(dst *Chain) (*RelayMsgs, error) { dst.PathEnd.UpdateClient(srcUpdateHeader, dst.MustGetAddress()), dst.PathEnd.ChanCloseConfirm(srcChan, dst.MustGetAddress()), ) - out.last = true + out.Last = true } // Closing handshake has started on dst, relay `updateClient` and `chanCloseConfirm` to src @@ -299,7 +299,7 @@ func (c *Chain) CloseChannelStep(dst *Chain) (*RelayMsgs, error) { c.PathEnd.UpdateClient(dstUpdateHeader, c.MustGetAddress()), c.PathEnd.ChanCloseConfirm(dstChan, c.MustGetAddress()), ) - out.last = true + out.Last = true } } return out, nil diff --git a/relayer/client-tx.go b/relayer/client-tx.go index 29ce39ee37d..b678b37ac99 100644 --- a/relayer/client-tx.go +++ b/relayer/client-tx.go @@ -65,7 +65,7 @@ func (c *Chain) CreateClients(dst *Chain) (err error) { // Send msgs to both chains if clients.Ready() { - if clients.Send(c, dst); clients.success { + if clients.Send(c, dst); clients.Success() { c.Log(fmt.Sprintf("★ Clients created: [%s]client(%s) and [%s]client(%s)", c.ChainID, c.PathEnd.ClientID, dst.ChainID, dst.PathEnd.ClientID)) } @@ -93,7 +93,7 @@ func (c *Chain) UpdateClients(dst *Chain) (err error) { // Send msgs to both chains if clients.Ready() { - if clients.Send(c, dst); clients.success { + if clients.Send(c, dst); clients.Success() { c.Log(fmt.Sprintf("★ Clients updated: [%s]client(%s) {%d}->{%d} and [%s]client(%s) {%d}->{%d}", c.ChainID, c.PathEnd.ClientID, diff --git a/relayer/connection-tx.go b/relayer/connection-tx.go index 381e129b999..8c46f2010e4 100644 --- a/relayer/connection-tx.go +++ b/relayer/connection-tx.go @@ -32,7 +32,7 @@ func (c *Chain) CreateConnection(dst *Chain, to time.Duration) error { switch { // In the case of success and this being the last transaction // debug logging, log created connection and break - case connSteps.success && connSteps.last: + case connSteps.Success() && connSteps.Last: if c.debug { srcH, dstH, err := GetLatestLightHeights(c, dst) if err != nil { @@ -50,11 +50,11 @@ func (c *Chain) CreateConnection(dst *Chain, to time.Duration) error { dst.ChainID, dst.PathEnd.ClientID, dst.PathEnd.ConnectionID)) return nil // In the case of success, reset the failures counter - case connSteps.success: + case connSteps.Success(): failed = 0 continue // In the case of failure, increment the failures counter and exit if this is the 3rd failure - case !connSteps.success: + case !connSteps.Success(): failed++ c.Log(fmt.Sprintf("retrying transaction...")) time.Sleep(5 * time.Second) @@ -207,7 +207,7 @@ func (c *Chain) CreateConnectionStep(dst *Chain) (*RelayMsgs, error) { c.PathEnd.UpdateClient(dstUpdateHeader, c.MustGetAddress()), c.PathEnd.ConnConfirm(dstConn, c.MustGetAddress()), ) - out.last = true + out.Last = true // Handshake has confirmed on src (3 steps done), relay `connOpenConfirm` and `updateClient` to dst end case srcConn.Connection.State == conntypes.OPEN && dstConn.Connection.State == conntypes.TRYOPEN: @@ -218,7 +218,7 @@ func (c *Chain) CreateConnectionStep(dst *Chain) (*RelayMsgs, error) { dst.PathEnd.UpdateClient(srcUpdateHeader, dst.MustGetAddress()), dst.PathEnd.ConnConfirm(srcConn, dst.MustGetAddress()), ) - out.last = true + out.Last = true } return out, nil diff --git a/relayer/controller.go b/relayer/controller.go new file mode 100644 index 00000000000..7095f618527 --- /dev/null +++ b/relayer/controller.go @@ -0,0 +1,35 @@ +package relayer + +import ( + "encoding/json" +) + +var SendToController func(needReply bool, str string) (string, error) + +func ControllerUpcall(action interface{}) (bool, error) { + bz, err := json.Marshal(action) + if err != nil { + return false, err + } + ret, err := SendToController(true, string(bz)) + if err != nil { + return false, err + } + var vi interface{} + if err = json.Unmarshal([]byte(ret), &vi); err != nil { + return false, err + } + + truthy := vi != nil + if truthy { + switch v := vi.(type) { + case bool: + truthy = v + case float64: + truthy = v != 0 + case string: + truthy = v != "" + } + } + return truthy, nil +} diff --git a/relayer/naive-strategy.go b/relayer/naive-strategy.go index cb83363191e..1bfb8459827 100644 --- a/relayer/naive-strategy.go +++ b/relayer/naive-strategy.go @@ -373,7 +373,7 @@ func (nrs *NaiveStrategy) sendTxFromEventPackets(src, dst *Chain, rlyPackets []r txs.Src = append(txs.Src, msg) } - if txs.Send(src, dst); !txs.success { + if txs.Send(src, dst); !txs.Success() { return fmt.Errorf("failed to send packets, see above logs for details") } @@ -455,7 +455,7 @@ func (nrs *NaiveStrategy) RelayAcknowledgements(src, dst *Chain, sp *RelaySequen } // send messages to their respective chains - if msgs.Send(src, dst); msgs.success { + if msgs.Send(src, dst); msgs.Success() { if len(msgs.Dst) > 1 { dst.logPacketsRelayed(src, len(msgs.Dst)-1) } @@ -560,7 +560,7 @@ func (nrs *NaiveStrategy) RelayPackets(src, dst *Chain, sp *RelaySequences, sh * } // send messages to their respective chains - if msgs.Send(src, dst); msgs.success { + if msgs.Send(src, dst); msgs.Success() { if len(msgs.Dst) > 1 { dst.logPacketsRelayed(src, len(msgs.Dst)-1) } diff --git a/relayer/packet-tx.go b/relayer/packet-tx.go index 0daa62f1b14..f3efe45927e 100644 --- a/relayer/packet-tx.go +++ b/relayer/packet-tx.go @@ -50,7 +50,7 @@ func (c *Chain) SendTransferMsg(dst *Chain, amount sdk.Coin, dstAddr fmt.Stringe Dst: []sdk.Msg{}, } - if txs.Send(c, dst); !txs.success { + if txs.Send(c, dst); !txs.Success() { return fmt.Errorf("failed to send transfer message") } return nil diff --git a/relayer/path.go b/relayer/path.go index c511d773b41..f8174576367 100644 --- a/relayer/path.go +++ b/relayer/path.go @@ -94,6 +94,11 @@ func (p Paths) PathsFromChains(src, dst string) (Paths, error) { return out, nil } +type PathAction struct { + *Path + Type string `json:"type"` +} + // Path represents a pair of chains and the identifiers needed to // relay over them type Path struct { diff --git a/relayer/pathEnd.go b/relayer/pathEnd.go index f59e949617f..ba9d7ad3cd9 100644 --- a/relayer/pathEnd.go +++ b/relayer/pathEnd.go @@ -47,6 +47,23 @@ func (pe *PathEnd) GetOrder() chantypes.Order { return OrderFromString(strings.ToUpper(pe.Order)) } +var marshalledChains = map[PathEnd]*Chain{} + +func MarshalChain(c *Chain) PathEnd { + pe := *c.PathEnd + if _, ok := marshalledChains[pe]; !ok { + marshalledChains[pe] = c + } + return pe +} + +func UnmarshalChain(pe PathEnd) *Chain { + if c, ok := marshalledChains[pe]; ok { + return c + } + return nil +} + // UpdateClient creates an sdk.Msg to update the client on src with data pulled from dst func (pe *PathEnd) UpdateClient(dstHeader ibcexported.Header, signer sdk.AccAddress) sdk.Msg { if err := dstHeader.ValidateBasic(); err != nil { diff --git a/relayer/relayMsgs.go b/relayer/relayMsgs.go index fb106792ec3..a5b60cc627a 100644 --- a/relayer/relayMsgs.go +++ b/relayer/relayMsgs.go @@ -9,22 +9,32 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +type DeliverMsgsAction struct { + SrcMsgs []string `json:"src_msgs"` + Src PathEnd `json:"src"` + DstMsgs []string `json:"dst_msgs"` + Dst PathEnd `json:"dst"` + Last bool `json:"last"` + Succeeded bool `json:"succeeded"` + Type string `json:"type"` +} + // RelayMsgs contains the msgs that need to be sent to both a src and dst chain // after a given relay round. MaxTxSize and MaxMsgLength are ignored if they are // set to zero. type RelayMsgs struct { - Src []sdk.Msg - Dst []sdk.Msg - MaxTxSize uint64 // maximum permitted size of the msgs in a bundled relay transaction - MaxMsgLength uint64 // maximum amount of messages in a bundled relay transaction + Src []sdk.Msg `json:"src"` + Dst []sdk.Msg `json:"dst"` + MaxTxSize uint64 `json:"max_tx_size"` // maximum permitted size of the msgs in a bundled relay transaction + MaxMsgLength uint64 `json:"max_msg_length"` // maximum amount of messages in a bundled relay transaction - last bool - success bool + Last bool `json:"last"` + Succeeded bool `json:"success"` } // NewRelayMsgs returns an initialized version of relay messages func NewRelayMsgs() *RelayMsgs { - return &RelayMsgs{Src: []sdk.Msg{}, Dst: []sdk.Msg{}, last: false, success: false} + return &RelayMsgs{Src: []sdk.Msg{}, Dst: []sdk.Msg{}, Last: false, Succeeded: false} } // Ready returns true if there are messages to relay @@ -41,7 +51,7 @@ func (r *RelayMsgs) Ready() bool { // Success returns the success var func (r *RelayMsgs) Success() bool { - return r.success + return r.Succeeded } func (r *RelayMsgs) IsMaxTx(msgLen, txSize uint64) bool { @@ -52,13 +62,69 @@ func (r *RelayMsgs) IsMaxTx(msgLen, txSize uint64) bool { // Send sends the messages with appropriate output // TODO: Parallelize? Maybe? func (r *RelayMsgs) Send(src, dst *Chain) { + r.SendWithController(src, dst, true) +} + +func EncodeMsgs(c *Chain, msgs []sdk.Msg) []string { + outMsgs := make([]string, 0, len(msgs)) + for _, msg := range msgs { + bz, err := c.Encoding.Amino.MarshalJSON(msg) + if err != nil { + fmt.Println("Cannot marshal message", msg, err) + } else { + outMsgs = append(outMsgs, string(bz)) + } + } + return outMsgs +} + +func DecodeMsgs(c *Chain, msgs []string) []sdk.Msg { + outMsgs := make([]sdk.Msg, 0, len(msgs)) + for _, msg := range msgs { + var sm sdk.Msg + err := c.Encoding.Amino.UnmarshalJSON([]byte(msg), &sm) + if err != nil { + fmt.Println("Cannot unmarshal message", err) + } else { + outMsgs = append(outMsgs, sm) + } + } + return outMsgs +} + +func (r *RelayMsgs) SendWithController(src, dst *Chain, useController bool) { + if useController && SendToController != nil { + action := &DeliverMsgsAction{ + Src: MarshalChain(src), + Dst: MarshalChain(dst), + Last: r.Last, + Succeeded: r.Succeeded, + Type: "RELAYER_SEND", + } + + action.SrcMsgs = EncodeMsgs(src, r.Src) + action.DstMsgs = EncodeMsgs(dst, r.Dst) + + // Get the messages that are actually sent. + cont, err := ControllerUpcall(&action) + if !cont { + if err != nil { + fmt.Println("Error calling controller", err) + r.Succeeded = false + } else { + r.Succeeded = true + } + return + } + } + //nolint:prealloc // can not be pre allocated var ( msgLen, txSize uint64 msgs []sdk.Msg ) - r.success = true + r.Succeeded = true // submit batches of relay transactions for _, msg := range r.Src { @@ -72,7 +138,7 @@ func (r *RelayMsgs) Send(src, dst *Chain) { if r.IsMaxTx(msgLen, txSize) { // Submit the transactions to src chain and update its status - r.success = r.success && send(src, msgs) + r.Succeeded = r.Succeeded && send(src, msgs) // clear the current batch and reset variables msgLen, txSize = 1, uint64(len(bz)) @@ -83,7 +149,7 @@ func (r *RelayMsgs) Send(src, dst *Chain) { // submit leftover msgs if len(msgs) > 0 && !send(src, msgs) { - r.success = false + r.Succeeded = false } // reset variables @@ -101,7 +167,7 @@ func (r *RelayMsgs) Send(src, dst *Chain) { if r.IsMaxTx(msgLen, txSize) { // Submit the transaction to dst chain and update its status - r.success = r.success && send(dst, msgs) + r.Succeeded = r.Succeeded && send(dst, msgs) // clear the current batch and reset variables msgLen, txSize = 1, uint64(len(bz)) @@ -112,7 +178,7 @@ func (r *RelayMsgs) Send(src, dst *Chain) { // submit leftover msgs if len(msgs) > 0 && !send(dst, msgs) { - r.success = false + r.Succeeded = false } } diff --git a/scripts/config-relayer b/scripts/config-relayer index b6a912f48c9..7d6a9e17ca1 100755 --- a/scripts/config-relayer +++ b/scripts/config-relayer @@ -30,11 +30,11 @@ echo "Generating rly configurations..." rly config init rly config add-dir configs/demo/ -SEED0=$(jq -r '.mnemonic' $GAIA_CONF/ibc0/key_seed.json) -SEED1=$(jq -r '.mnemonic' $GAIA_CONF/ibc1/key_seed.json) -echo "Key $(rly keys restore ibc0 testkey "$SEED0") imported from ibc0 to relayer..." -echo "Key $(rly keys restore ibc1 testkey "$SEED1") imported from ibc1 to relayer..." +SEED0=$(jq -r '.mnemonic' $GAIA_CONF/ibc-0/key_seed.json) +SEED1=$(jq -r '.mnemonic' $GAIA_CONF/ibc-1/key_seed.json) +echo "Key $(rly keys restore ibc-0 testkey "$SEED0") imported from ibc-0 to relayer..." +echo "Key $(rly keys restore ibc-1 testkey "$SEED1") imported from ibc-1 to relayer..." echo "Creating light clients..." sleep 3 -rly light init ibc0 -f -rly light init ibc1 -f \ No newline at end of file +rly light init ibc-0 -f +rly light init ibc-1 -f \ No newline at end of file diff --git a/scripts/config-relayer-akash b/scripts/config-relayer-akash index 368e99b0526..53372ce5929 100755 --- a/scripts/config-relayer-akash +++ b/scripts/config-relayer-akash @@ -30,11 +30,11 @@ echo "Generating rly configurations..." rly config init rly config add-dir configs/akash/ -SEED0=$(jq -r '.mnemonic' $GAIA_CONF/ibc0/key_seed.json) -SEED1=$(jq -r '.mnemonic' $GAIA_CONF/ibc1/key_seed.json) -echo "Key $(rly keys restore ibc0 testkey "$SEED0") imported from ibc0 to relayer..." -echo "Key $(rly keys restore ibc1 testkey "$SEED1") imported from ibc1 to relayer..." +SEED0=$(jq -r '.mnemonic' $GAIA_CONF/ibc-0/key_seed.json) +SEED1=$(jq -r '.mnemonic' $GAIA_CONF/ibc-1/key_seed.json) +echo "Key $(rly keys restore ibc-0 testkey "$SEED0") imported from ibc-0 to relayer..." +echo "Key $(rly keys restore ibc-1 testkey "$SEED1") imported from ibc-1 to relayer..." echo "Creating light clients..." sleep 3 -rly light init ibc0 -f -rly light init ibc1 -f \ No newline at end of file +rly light init ibc-0 -f +rly light init ibc-1 -f \ No newline at end of file diff --git a/scripts/config-three b/scripts/config-three index e4a5b7b81fd..0ae461b68f3 100755 --- a/scripts/config-three +++ b/scripts/config-three @@ -30,17 +30,17 @@ echo "Generating rly configurations..." rly config init rly config add-dir configs/three/ -SEED0=$(jq -r '.secret' $GAIA_CONF/ibc0/n0/gaiacli/key_seed.json) -SEED1=$(jq -r '.secret' $GAIA_CONF/ibc1/n0/gaiacli/key_seed.json) -SEED2=$(jq -r '.secret' $GAIA_CONF/ibc2/n0/gaiacli/key_seed.json) +SEED0=$(jq -r '.secret' $GAIA_CONF/ibc-0/n0/gaiacli/key_seed.json) +SEED1=$(jq -r '.secret' $GAIA_CONF/ibc-1/n0/gaiacli/key_seed.json) +SEED2=$(jq -r '.secret' $GAIA_CONF/ibc-2/n0/gaiacli/key_seed.json) echo -echo "Key $(rly keys restore ibc0 testkey "$SEED0") imported from ibc0 to relayer..." -echo "Key $(rly keys restore ibc1 testkey "$SEED1") imported from ibc1 to relayer..." -echo "Key $(rly keys restore ibc2 testkey "$SEED2") imported from ibc2 to relayer..." +echo "Key $(rly keys restore ibc-0 testkey "$SEED0") imported from ibc-0 to relayer..." +echo "Key $(rly keys restore ibc-1 testkey "$SEED1") imported from ibc-1 to relayer..." +echo "Key $(rly keys restore ibc-2 testkey "$SEED2") imported from ibc-2 to relayer..." echo echo "Creating light clients..." echo sleep 3 -rly light init ibc0 -f -rly light init ibc1 -f -rly light init ibc2 -f \ No newline at end of file +rly light init ibc-0 -f +rly light init ibc-1 -f +rly light init ibc-2 -f \ No newline at end of file diff --git a/scripts/four-chainz b/scripts/four-chainz index 04fa11d81f8..3955fef44a5 100755 --- a/scripts/four-chainz +++ b/scripts/four-chainz @@ -44,10 +44,10 @@ echo "Adding configuration..." rly cfg ad configs/four/ &> /dev/null echo "Generating keys..." -echo "IBC0ADDR=$(rly k a ibc0 | jq -r '.address')" >> $ENV_FILE -echo "IBC1ADDR=$(rly k a ibc1 | jq -r '.address')" >> $ENV_FILE -echo "IBC2ADDR=$(rly k a ibc2 | jq -r '.address')" >> $ENV_FILE -echo "IBC3ADDR=$(rly k a ibc3 | jq -r '.address')" >> $ENV_FILE +echo "IBC0ADDR=$(rly k a ibc-0 | jq -r '.address')" >> $ENV_FILE +echo "IBC1ADDR=$(rly k a ibc-1 | jq -r '.address')" >> $ENV_FILE +echo "IBC2ADDR=$(rly k a ibc-2 | jq -r '.address')" >> $ENV_FILE +echo "IBC3ADDR=$(rly k a ibc-3 | jq -r '.address')" >> $ENV_FILE echo "Creating containers..." docker-compose up -d &> /dev/null @@ -56,21 +56,21 @@ echo "Waiting for blocks..." sleep 8 echo "Creating light clients for chains..." -rly light init ibc0 -f -rly light init ibc1 -f -rly light init ibc2 -f -rly light init ibc3 -f +rly light init ibc-0 -f +rly light init ibc-1 -f +rly light init ibc-2 -f +rly light init ibc-3 -f -echo "Starting 'rly tx link zeroone' (ibc0<>ibc1) logs in data/zeroone.log" +echo "Starting 'rly tx link zeroone' (ibc-0<>ibc-1) logs in data/zeroone.log" rly tx link zeroone -d -o 3s 2>&1 > data/zeroone.log & sleep 1 -echo "Starting 'rly tx link twothree' (ibc2<>ibc3) logs in data/twothree.log" +echo "Starting 'rly tx link twothree' (ibc-2<>ibc-3) logs in data/twothree.log" rly tx link twothree -d -o 3s 2>&1 > data/twothree.log & sleep 1 -echo "Starting 'rly tx link onetwo' (ibc1<>ibc2) logs in data/onetwo.log" +echo "Starting 'rly tx link onetwo' (ibc-1<>ibc-2) logs in data/onetwo.log" rly tx link onetwo -d -o 3s 2>&1 > data/onetwo.log & sleep 2 -echo "Starting 'rly tx link threezero' (ibc3<>ibc0) logs in data/threezero.log" +echo "Starting 'rly tx link threezero' (ibc-3<>ibc-0) logs in data/threezero.log" rly tx link threezero -d -o 3s 2>&1 > data/threezero.log & sleep 1 echo "Check the state of the connections using 'rly paths list' to see when they are ready to relay over..." diff --git a/scripts/nchainz b/scripts/nchainz index 5c52cc86583..ed5481608ed 100755 --- a/scripts/nchainz +++ b/scripts/nchainz @@ -284,6 +284,7 @@ while [[ $# -gt 0 ]]; do init) case "$1" in skip) SKIP=yes ;; + norun) SKIP=norun ;; *=*) CHAINS+=( "$1" ) ;; *:*) LINKS+=( "$1" ) ;; *) @@ -417,7 +418,7 @@ chains) ;; clients) source "$NCONFIG" - RELAYER_CONF="$HOME/.relayer" + RELAYER_CONF=$(rly config show-home 2>/dev/null || echo "$HOME/.relayer") set -e @@ -669,6 +670,10 @@ You can use: \`$progname [run|relay]' at any time. EOF +if [[ $SKIP == norun ]]; then + exit 0 +fi + if [[ $SKIP != yes ]]; then read -p "Do you wish to \`run', and \`relay' right now (y/N)? " -n 1 -r echo diff --git a/scripts/three-chainz b/scripts/three-chainz index 3a062c84004..71cbce23ab6 100755 --- a/scripts/three-chainz +++ b/scripts/three-chainz @@ -70,9 +70,9 @@ else echo "mkdir -p $(dirname $GAIA_REPO) && git clone git@github.com:cosmos/gaia $GAIA_REPO" fi -chainid0=ibc0 -chainid1=ibc1 -chainid2=ibc2 +chainid0=ibc-0 +chainid1=ibc-1 +chainid2=ibc-2 echo "Generating gaia configurations..." mkdir -p $GAIA_DATA && cd $GAIA_DATA && cd ../ diff --git a/scripts/two-chainz b/scripts/two-chainz index 4ae976b2b6b..7eb8f7d6f09 100755 --- a/scripts/two-chainz +++ b/scripts/two-chainz @@ -72,8 +72,8 @@ else echo "mkdir -p $(dirname $GAIA_REPO) && git clone git@github.com:cosmos/gaia $GAIA_REPO" fi -chainid0=ibc0 -chainid1=ibc1 +chainid0=ibc-0 +chainid1=ibc-1 echo "Generating gaia configurations..." mkdir -p $GAIA_DATA && cd $GAIA_DATA && cd ../ diff --git a/scripts/two-chainz-akash b/scripts/two-chainz-akash index 2d40bacee3d..fcc851e2169 100755 --- a/scripts/two-chainz-akash +++ b/scripts/two-chainz-akash @@ -115,8 +115,8 @@ else echo "mkdir -p $(dirname $AKASH_REPO) && git clone git@github.com:ovrclk/akash $AKASH_REPO" fi -chainid0=ibc0 -chainid1=ibc1 +chainid0=ibc-0 +chainid1=ibc-1 echo "Generating gaia configurations..." mkdir -p $GAIA_DATA && cd $GAIA_DATA && cd ../ diff --git a/test/relayer_gaia_test.go b/test/relayer_gaia_test.go index f4cf433786c..9e15d05ea2c 100644 --- a/test/relayer_gaia_test.go +++ b/test/relayer_gaia_test.go @@ -10,8 +10,8 @@ import ( var ( gaiaChains = []testChain{ - {"ibc0", gaiaTestConfig}, - {"ibc1", gaiaTestConfig}, + {"ibc-0", gaiaTestConfig}, + {"ibc-1", gaiaTestConfig}, } ) @@ -19,8 +19,8 @@ func TestGaiaToGaiaStreamingRelayer(t *testing.T) { chains := spinUpTestChains(t, gaiaChains...) var ( - src = chains.MustGet("ibc0") - dst = chains.MustGet("ibc1") + src = chains.MustGet("ibc-0") + dst = chains.MustGet("ibc-1") testDenom = "samoleans" testCoin = sdk.NewCoin(testDenom, sdk.NewInt(1000)) twoTestCoin = sdk.NewCoin(testDenom, sdk.NewInt(2000)) diff --git a/testnets/README.md b/testnets/README.md index 97ad2ca5681..54a673560d6 100644 --- a/testnets/README.md +++ b/testnets/README.md @@ -75,11 +75,11 @@ The following instructions have been tested and are working from a default insta ```bash # Update the system and install dependancies sudo apt update -sudo apt install build-essential jq -y +sudo apt install build-essential jq git -y # Install latest go version https://golang.org/doc/install -wget https://dl.google.com/go/go1.14.linux-amd64.tar.gz -sudo tar -C /usr/local -xzf go1.14.linux-amd64.tar.gz +wget https://dl.google.com/go/go1.15.2.linux-amd64.tar.gz +sudo tar -C /usr/local -xzf go1.15.2.linux-amd64.tar.gz # Add $GOPATH, $GOBIN and both to $PATH echo "" >> ~/.profile @@ -96,13 +96,16 @@ export DENOM=pylon export CHAINID=pylonchain export DOMAIN=shitcoincasinos.com export RLYKEY=faucet -export GAIASHA=50be36d +export GAIASHA=stargate-4 export ACCOUNT_PREFIX=cosmos # Start by downloading and installing both gaia and the relayer mkdir -p $(dirname $GAIA) && git clone https://github.com/cosmos/gaia $GAIA && cd $GAIA && git checkout $GAIASHA && make install mkdir -p $(dirname $RELAYER) && git clone https://github.com/cosmos/relayer $RELAYER && cd $RELAYER && make install +# Verify gaia version matches that of the latest testnet above +gaia version --long + # Now its time to configure both the relayer and gaia, start with the relayer cd rly config init @@ -114,15 +117,15 @@ rly keys add $CHAINID $RLYKEY # Move on to configuring gaia gaiad init --chain-id $CHAINID $CHAINID # NOTE: ensure that the gaia rpc is open to all connections -sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:26657#g' ~/.gaiad/config/config.toml -sed -i "s/\"stake\"/\"$DENOM\"/g" ~/.gaiad/config/genesis.json -sed -i 's/pruning = "syncable"/pruning = "nothing"/g' ~/.gaiad/config/app.toml +sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:26657#g' ~/.gaia/config/config.toml +sed -i "s/\"stake\"/\"$DENOM\"/g" ~/.gaia/config/genesis.json +sed -i 's/pruning = "syncable"/pruning = "nothing"/g' ~/.gaia/config/app.toml gaiad keys add validator # Now its time to construct the genesis file gaiad add-genesis-account $(gaiad keys show validator -a) 100000000000$DENOM,10000000samoleans gaiad add-genesis-account $(rly chains addr $CHAINID) 10000000000000$DENOM,10000000samoleans -gaiad gentx --name validator --amount 90000000000$DENOM +gaiad gentx validator --amount 90000000000$DENOM --chain-id $CHAINID gaiad collect-gentxs # Setup the service definitions diff --git a/testnets/relayer-alpha-2/vitwitchain-1.json b/testnets/relayer-alpha-2/vitwitchain-1.json index 564ce4bf3a1..eb7a708f1d5 100644 --- a/testnets/relayer-alpha-2/vitwitchain-1.json +++ b/testnets/relayer-alpha-2/vitwitchain-1.json @@ -1 +1 @@ -{"key":"faucetkey","chain-id":"vitwitchain-1","rpc-addr":"http://ibc1.vitwit.in:26657","account-prefix":"vitwit:","gas":200000,"gas-prices":"0.025vitcoin","default-denom":"vitcoin","trusting-period":"330h"} +{"key":"faucetkey","chain-id":"vitwitchain-1","rpc-addr":"http://ibc-1.vitwit.in:26657","account-prefix":"vitwit:","gas":200000,"gas-prices":"0.025vitcoin","default-denom":"vitcoin","trusting-period":"330h"} diff --git a/testnets/relayer-alpha/vitwitchain-1.json b/testnets/relayer-alpha/vitwitchain-1.json index 564ce4bf3a1..eb7a708f1d5 100644 --- a/testnets/relayer-alpha/vitwitchain-1.json +++ b/testnets/relayer-alpha/vitwitchain-1.json @@ -1 +1 @@ -{"key":"faucetkey","chain-id":"vitwitchain-1","rpc-addr":"http://ibc1.vitwit.in:26657","account-prefix":"vitwit:","gas":200000,"gas-prices":"0.025vitcoin","default-denom":"vitcoin","trusting-period":"330h"} +{"key":"faucetkey","chain-id":"vitwitchain-1","rpc-addr":"http://ibc-1.vitwit.in:26657","account-prefix":"vitwit:","gas":200000,"gas-prices":"0.025vitcoin","default-denom":"vitcoin","trusting-period":"330h"}