Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Multihop support #1

Merged
merged 93 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
7e6bc41
feat: parse hops out of chain registry config
Mar 14, 2023
d585c4c
feat: add hops to path processor
Mar 14, 2023
52b47a1
chore: upgrade ibc-go to ibcx
Mar 14, 2023
ce5da8b
feat: get intermediate chains in chains link and create channel
Mar 14, 2023
02c37a4
feat: add relay path ends to chains
Mar 14, 2023
dd7b033
feat: propagate hops to clients and connections via link command
Mar 14, 2023
d983ebe
feat: extract hop chains for channel open/close
Mar 14, 2023
f8da57c
feat: pass relay path ends to path processor
Mar 14, 2023
d6f1b36
feat: add hops to message processors
Mar 14, 2023
77ee009
chore: upgrade ibc-go
Mar 15, 2023
d53d414
feat: use connection hops from ibc events
Mar 15, 2023
705d28d
feat: set hops in channel info
Mar 15, 2023
802f172
chore: go back to keying by dot-separated connection IDs to match events
Mar 15, 2023
9795702
doc: put placeholders in messages that need a multihop proof
Mar 15, 2023
c57bd9d
feat: add method to add query providers to chain providers
Mar 16, 2023
c74b0b8
feat: split hops by direction so message assembly code can use the re…
Mar 16, 2023
e41e9d9
feat: implement AddQueryProvider()
Mar 16, 2023
ffbcd35
feat: first part of GenerateMultihopProof()
Mar 16, 2023
a29a42e
feat: consensus proofs
Mar 17, 2023
38beaa0
refactor: move consensus-specific proving code so queries can be shar…
Mar 17, 2023
6d40ee6
feat: generate connection proofs
Mar 17, 2023
695b79f
test: NewPathHops
Mar 17, 2023
99e9972
feat: add hops and query providers to packet proving code
Mar 18, 2023
4119106
feat: store connection hops in channel state cache
Mar 22, 2023
b2b6e74
feat: multihop for packet proofs
Mar 23, 2023
145bc6e
chore: plumbing for event based relay strategy
Mar 23, 2023
831619d
fix: tidy
Mar 23, 2023
7c8bd01
chore: port reversal of proofs from spec
Mar 23, 2023
1a15a1d
fix: path end constructor
Mar 24, 2023
be975df
fix: add src connection to connection hops
Mar 24, 2023
2d4eb0c
fix: use counterparty hops for chan open try
Mar 24, 2023
0d2871b
test: path hop and end to end
Mar 24, 2023
1338bd3
fix: upgrade ibc-go and reuse conn hops formatting
Mar 30, 2023
0a1f755
fix: set heighliner uid-gid for wasm image
Mar 31, 2023
774f40b
test: temporarily disable multihop
Mar 31, 2023
a24ce5e
fix: set gas adjustment for wasmd
Mar 31, 2023
2dced63
test: single hop test with wasm and osmosis
Apr 1, 2023
6dc3d57
feat: multihop support for paths new command
Apr 4, 2023
eb442e6
test: setup single hop clients/connections and multihop channel
Apr 4, 2023
d534e38
fix: lookup hop chains directly from config
Apr 4, 2023
3cb11a6
feat: find intermediate paths to populate clients and connections
Apr 5, 2023
3fb2479
fix: destination chain path end based on hop
Apr 5, 2023
f947454
test: explicit path creation for single hop
Apr 5, 2023
fa81952
doc: add note about multihop messages
Apr 6, 2023
d211176
fix: set client/conn IDs in paths new for multihop paths
Apr 7, 2023
a16761e
fix: check connection relevance by first hop
Apr 7, 2023
a5a916a
fix: skip client updates for multihop paths
Apr 7, 2023
07095e7
fix: filter connections for clients based on first connection hop
Apr 7, 2023
c687b2c
fix: name hop by its own chain ID
Apr 7, 2023
5d69a0c
fix: look for applicable chain providers in hops
Apr 7, 2023
d7528c3
fix: ensure event processors get chain processors for multipath hops
Apr 10, 2023
8a7db48
fix: add chain ID to query provider
Apr 11, 2023
e0e86ea
fix: restore client updates between the first 2 chains in any path
Apr 11, 2023
3e70713
feat: update clients on all hops
Apr 13, 2023
c8edb8f
fix: update trusted client state for hops
Apr 14, 2023
cedcee4
feat: handle incoming data for hop path ends
Apr 15, 2023
8029213
feat: add message processors for all pairs of path ends
Apr 16, 2023
9bad9f2
fix: make sure last hop to dst is processed
Apr 16, 2023
f80ddd4
fix: hop chain IDs
Apr 16, 2023
8ce91d4
fix: limit sync check to src and dst
Apr 16, 2023
bad3f11
fix: counterparty path end reference
Apr 17, 2023
6ad0b84
fix: order of hops in path processor
Apr 17, 2023
c2b7740
fix: expand misbehaviour check for multihop
Apr 17, 2023
ab428d7
fix: log chain ID in proof errors
Apr 17, 2023
9b121ed
chore: upgrade ibc-go to v7.1.x-ibcx-2
Apr 17, 2023
51e1eb5
feat: endpoint implementation for client/connections/consensus
Apr 18, 2023
643f615
chore: upgrade endpoint
Apr 18, 2023
da8ebc8
feat: merkle paths and proofs
Apr 18, 2023
85c0cd8
feat: client update via endpoint
Apr 18, 2023
128ede3
feat: proof generation code using endpoint
Apr 18, 2023
cfeba50
feat: instantiate chan paths on path processors, keep connection ID a…
Apr 19, 2023
6a56bfa
fix: client ID in client state query during client update for endpoint
Apr 20, 2023
52a5931
feat: add counterparty connection ID to channel cache
Apr 20, 2023
8a83b5d
fix: reverse client updates in channel proofs
Apr 20, 2023
0a05f9a
chore: remove client updates for intermediate hops
Apr 20, 2023
99a5c15
fix: use last hop height for proof height
Apr 21, 2023
893486d
fix: proof heights
Apr 21, 2023
bfdc477
fix: parse consensus height out of key
May 2, 2023
b6eeb02
test: client update
May 4, 2023
5faf70a
fix: add retries around client updates
May 4, 2023
e6688c8
chore: disable relayer-side proof verification check
May 4, 2023
7f3abae
debug: disable misbehavior as path end cache is unaware of updates ha…
May 4, 2023
3f57952
debug: adjust verbosity
May 4, 2023
0ff8054
feat: account for multiple connections in channels cache in processor
May 4, 2023
373eda2
test: include multihop in event tests
May 4, 2023
2c18521
test: enable token transfer test
May 5, 2023
64c882c
fix: do not expect chan paths for single hop
May 5, 2023
2a47081
fix: decouple client/conn/icq from channel/packets
May 5, 2023
f48bbe4
fix: do not make chain ID suffix look like revision
May 9, 2023
e1d2a7a
test: allow for more time checking acks
May 9, 2023
c1186e9
test: fix mock chain processor API
May 9, 2023
1d8b9c9
fix: formatting issue
May 9, 2023
8f693bd
fix: re-enable misbehavior for single hop
May 9, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ interchaintest-docker-events:
interchaintest-docker-legacy:
cd interchaintest && go test -race -v -run TestRelayerDockerLegacyProcessor .

interchaintest-events:
interchaintest-multihop:
cd interchaintest && go test -race -v -run TestRelayerMultihop .

interchaintest-events: interchaintest-multihop
cd interchaintest && go test -race -v -run TestRelayerEventProcessor .

interchaintest-legacy:
Expand Down
2 changes: 1 addition & 1 deletion cmd/appstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (a *appState) AddPathFromFile(ctx context.Context, stderr io.Writer, file,
// It returns any input or validation errors.
// If the path was successfully added, it returns nil.
func (a *appState) AddPathFromUserInput(ctx context.Context, stdin io.Reader, stderr io.Writer, src, dst, name string) error {
// TODO: confirm name is available before going through input.
// TODO: confirm name is available before going through input, add the ability to configure multi-hop paths

var (
value string
Expand Down
49 changes: 43 additions & 6 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,26 +401,63 @@ func (iw *ProviderConfigYAMLWrapper) UnmarshalYAML(n *yaml.Node) error {
}

// ChainsFromPath takes the path name and returns the properly configured chains
func (c *Config) ChainsFromPath(path string) (map[string]*relayer.Chain, string, string, error) {
func (c *Config) ChainsFromPath(path string) (map[string]*relayer.Chain, string, string, []*relayer.Chain, error) {
pth, err := c.Paths.Get(path)
if err != nil {
return nil, "", "", err
return nil, "", "", nil, err
}

src, dst := pth.Src.ChainID, pth.Dst.ChainID
chains, err := c.Chains.Gets(src, dst)
if err != nil {
return nil, "", "", err
return nil, "", "", nil, err
}

if err = chains[src].SetPath(pth.Src); err != nil {
return nil, "", "", err
return nil, "", "", nil, err
}
hops := []*relayer.Chain{}
lastChain := chains[src]
for i, hop := range pth.Hops {
hopChain, err := c.Chains.Get(hop.ChainID)
if err != nil {
return nil, "", "", nil, err
}
if err = hopChain.SetRelayPaths(hop.PathEnds); err != nil {
return nil, "", "", nil, err
}
hops = append(hops, hopChain)
// Find a path between adjacent chains and populate clients and connections
pthPrevToCurrHop := c.Paths.Find(lastChain.ChainID(), hopChain.ChainID())
if pthPrevToCurrHop != nil {
hopChain.RelayPathEnds[0].ClientID = pthPrevToCurrHop.Dst.ClientID
hopChain.RelayPathEnds[0].ConnectionID = pthPrevToCurrHop.Dst.ConnectionID
if i == 0 {
lastChain.PathEnd.ClientID = pthPrevToCurrHop.Src.ClientID
lastChain.PathEnd.ConnectionID = pthPrevToCurrHop.Src.ConnectionID
} else {
lastChain.RelayPathEnds[1].ClientID = pthPrevToCurrHop.Src.ClientID
lastChain.RelayPathEnds[1].ConnectionID = pthPrevToCurrHop.Src.ConnectionID
}
}
// Connect the last hop to the destination
if i == len(pth.Hops)-1 {
pthHopToDst := c.Paths.Find(hopChain.ChainID(), dst)
if pthHopToDst != nil {
hopChain.RelayPathEnds[1].ClientID = pthHopToDst.Src.ClientID
hopChain.RelayPathEnds[1].ConnectionID = pthHopToDst.Src.ConnectionID
pth.Dst.ClientID = pthHopToDst.Dst.ClientID
pth.Dst.ConnectionID = pthHopToDst.Dst.ConnectionID
}
}
chains[hop.ChainID] = hopChain
lastChain = hopChain
}
if err = chains[dst].SetPath(pth.Dst); err != nil {
return nil, "", "", err
return nil, "", "", nil, err
}

return chains, src, dst, nil
return chains, src, dst, hops, nil
}

// MustYAML returns the yaml string representation of the Paths
Expand Down
48 changes: 43 additions & 5 deletions cmd/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,15 +232,16 @@ $ %s config add-paths examples/demo/configs/paths`, appName)),

func pathsNewCmd(a *appState) *cobra.Command {
cmd := &cobra.Command{
Use: "new src_chain_id dst_chain_id path_name",
Use: "new src_chain_id dst_chain_id path_name [hop1_chain_id hop2_chain_id ... hopN_chain_id]",
Aliases: []string{"n"},
Short: "Create a new blank path to be used in generating a new path (connection & client) between two chains",
Args: withUsage(cobra.ExactArgs(3)),
Args: withUsage(cobra.MinimumNArgs(3)),
Example: strings.TrimSpace(fmt.Sprintf(`
$ %s paths new ibc-0 ibc-1 demo-path
$ %s pth n ibc-0 ibc-1 demo-path`, appName, appName)),
RunE: func(cmd *cobra.Command, args []string) error {
src, dst := args[0], args[1]
hops := args[3:]
_, err := a.Config.Chains.Gets(src, dst)
if err != nil {
return fmt.Errorf("chains need to be configured before paths to them can be added: %w", err)
Expand All @@ -250,7 +251,39 @@ $ %s pth n ibc-0 ibc-1 demo-path`, appName, appName)),
Src: &relayer.PathEnd{ChainID: src},
Dst: &relayer.PathEnd{ChainID: dst},
}

p.Hops = make([]*relayer.PathHop, len(hops))
lastChainID := p.Src.ChainID
for i, hop := range hops {
// TODO: this logic is similar to Config.ChainsFromPath(), look into consolidating
pthPrevToCurrHop := a.Config.Paths.Find(lastChainID, hop)
newHop := &relayer.PathHop{
ChainID: hop,
PathEnds: [2]*relayer.PathEnd{
{
ChainID: hop,
ClientID: pthPrevToCurrHop.Dst.ClientID,
ConnectionID: pthPrevToCurrHop.Dst.ConnectionID,
}, {},
},
}
if i == 0 {
p.Src.ClientID = pthPrevToCurrHop.Src.ClientID
p.Src.ConnectionID = pthPrevToCurrHop.Src.ConnectionID
} else {
p.Hops[i-1].PathEnds[1].ClientID = pthPrevToCurrHop.Src.ClientID
p.Hops[i-1].PathEnds[1].ConnectionID = pthPrevToCurrHop.Src.ConnectionID
}
if i == len(hops)-1 {
newHop.PathEnds[1].ChainID = hop
pthCurrHopToDst := a.Config.Paths.Find(hop, p.Dst.ChainID)
newHop.PathEnds[1].ClientID = pthCurrHopToDst.Src.ClientID
newHop.PathEnds[1].ConnectionID = pthCurrHopToDst.Src.ConnectionID
p.Dst.ClientID = pthCurrHopToDst.Dst.ClientID
p.Dst.ConnectionID = pthCurrHopToDst.Dst.ConnectionID
}
p.Hops[i] = newHop
lastChainID = newHop.ChainID
}
name := args[2]
if err = a.Config.Paths.Add(name, p); err != nil {
return err
Expand Down Expand Up @@ -433,9 +466,14 @@ $ %s pth fch`, appName, defaultHome, appName)),
ClientID: ibc.Chain2.ClientID,
ConnectionID: ibc.Chain2.ConnectionID,
}
hops, err := relayer.NewPathHops(ibc, srcPathEnd, dstPathEnd, &a.Config.Chains)
if err != nil {
return err
}
newPath := &relayer.Path{
Src: srcPathEnd,
Dst: dstPathEnd,
Src: srcPathEnd,
Dst: dstPathEnd,
Hops: hops,
}
client.Close()

Expand Down
6 changes: 6 additions & 0 deletions cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ $ %s start demo-path2 --max-tx-size 10`, appName, appName, appName, appName)),
// collect unique chain IDs
chains[path.Src.ChainID] = nil
chains[path.Dst.ChainID] = nil
for _, h := range path.Hops {
chains[h.ChainID] = nil
}
}
} else {
for n, path := range a.Config.Paths {
Expand All @@ -70,6 +73,9 @@ $ %s start demo-path2 --max-tx-size 10`, appName, appName, appName, appName)),
// collect unique chain IDs
chains[path.Src.ChainID] = nil
chains[path.Dst.ChainID] = nil
for _, h := range path.Hops {
chains[h.ChainID] = nil
}
}
}

Expand Down
80 changes: 52 additions & 28 deletions cmd/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func createClientsCmd(a *appState) *cobra.Command {

path := args[0]

c, src, dst, err := a.Config.ChainsFromPath(path)
c, src, dst, _, err := a.Config.ChainsFromPath(path)
if err != nil {
return err
}
Expand Down Expand Up @@ -245,7 +245,7 @@ corresponding update-client messages.`,
Args: withUsage(cobra.ExactArgs(1)),
Example: strings.TrimSpace(fmt.Sprintf(`$ %s transact update-clients demo-path`, appName)),
RunE: func(cmd *cobra.Command, args []string) error {
c, src, dst, err := a.Config.ChainsFromPath(args[0])
c, src, dst, _, err := a.Config.ChainsFromPath(args[0])
if err != nil {
return err
}
Expand All @@ -271,7 +271,7 @@ func upgradeClientsCmd(a *appState) *cobra.Command {
Short: "upgrades IBC clients between two configured chains with a configured path and chain-id",
Args: withUsage(cobra.ExactArgs(2)),
RunE: func(cmd *cobra.Command, args []string) error {
c, src, dst, err := a.Config.ChainsFromPath(args[0])
c, src, dst, _, err := a.Config.ChainsFromPath(args[0])
if err != nil {
return err
}
Expand Down Expand Up @@ -339,7 +339,7 @@ $ %s tx conn demo-path --timeout 5s`,

pathName := args[0]

c, src, dst, err := a.Config.ChainsFromPath(pathName)
c, src, dst, _, err := a.Config.ChainsFromPath(pathName)
if err != nil {
return err
}
Expand Down Expand Up @@ -426,7 +426,7 @@ $ %s tx chan demo-path --timeout 5s --max-retries 10`,

pathName := args[0]

c, src, dst, err := a.Config.ChainsFromPath(pathName)
c, src, dst, hops, err := a.Config.ChainsFromPath(pathName)
if err != nil {
return err
}
Expand Down Expand Up @@ -475,7 +475,7 @@ $ %s tx chan demo-path --timeout 5s --max-retries 10`,
}

// create channel if it isn't already created
return c[src].CreateOpenChannels(cmd.Context(), c[dst], retries, to, srcPort, dstPort, order, version, override, a.Config.memo(cmd), pathName)
return c[src].CreateOpenChannels(cmd.Context(), c[dst], hops, retries, to, srcPort, dstPort, order, version, override, a.Config.memo(cmd), pathName)
},
}

Expand All @@ -502,7 +502,7 @@ $ %s tx channel-close demo-path channel-0 transfer -o 3s`,
RunE: func(cmd *cobra.Command, args []string) error {
pathName := args[0]

c, src, dst, err := a.Config.ChainsFromPath(pathName)
c, src, dst, hops, err := a.Config.ChainsFromPath(pathName)
if err != nil {
return err
}
Expand Down Expand Up @@ -538,7 +538,7 @@ $ %s tx channel-close demo-path channel-0 transfer -o 3s`,
return err
}

return c[src].CloseChannel(cmd.Context(), c[dst], retries, to, channelID, portID, a.Config.memo(cmd), pathName)
return c[src].CloseChannel(cmd.Context(), c[dst], hops, retries, to, channelID, portID, a.Config.memo(cmd), pathName)
},
}

Expand Down Expand Up @@ -587,12 +587,23 @@ $ %s tx connect demo-path --src-port transfer --dst-port transfer --order unorde
}

src, dst := pth.Src.ChainID, pth.Dst.ChainID
c, err := a.Config.Chains.Gets(src, dst)
chainIDs := []string{src}
for _, hop := range pth.Hops {
chainIDs = append(chainIDs, hop.ChainID)
}
chainIDs = append(chainIDs, dst)
c, err := a.Config.Chains.Gets(chainIDs...)
if err != nil {
return err
}

c[src].PathEnd = pth.Src
hops := []*relayer.Chain{}
for _, hop := range pth.Hops {
hopChain := c[hop.ChainID]
c[hop.ChainID].RelayPathEnds = hop.PathEnds
hops = append(hops, hopChain)
}
c[dst].PathEnd = pth.Dst

srcPort, err := cmd.Flags().GetString(flagSrcPort)
Expand Down Expand Up @@ -645,30 +656,37 @@ $ %s tx connect demo-path --src-port transfer --dst-port transfer --order unorde
return err
}

// create clients if they aren't already created
clientSrc, clientDst, err := c[src].CreateClients(cmd.Context(), c[dst], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
if err != nil {
return fmt.Errorf("error creating clients: %w", err)
}
if clientSrc != "" || clientDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, clientSrc, clientDst, "", ""); err != nil {
return err
for i, srcChainID := range chainIDs {
if i == len(chainIDs)-1 {
// When we reach dst we already connected via the previous hop
break
}
}
dstChainID := chainIDs[i+1]

// create connection if it isn't already created
connectionSrc, connectionDst, err := c[src].CreateOpenConnections(cmd.Context(), c[dst], retries, to, memo, initialBlockHistory, pathName)
if err != nil {
return fmt.Errorf("error creating connections: %w", err)
}
if connectionSrc != "" || connectionDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, "", "", connectionSrc, connectionDst); err != nil {
return err
// create clients if they aren't already created
clientSrc, clientDst, err := c[srcChainID].CreateClients(cmd.Context(), c[dstChainID], allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour, override, customClientTrustingPeriod, memo)
if err != nil {
return fmt.Errorf("error creating clients: %w", err)
}
if clientSrc != "" || clientDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, clientSrc, clientDst, "", ""); err != nil {
return err
}
}
}

// create connection if it isn't already created
connectionSrc, connectionDst, err := c[srcChainID].CreateOpenConnections(cmd.Context(), c[dstChainID], retries, to, memo, initialBlockHistory, pathName)
if err != nil {
return fmt.Errorf("error creating connections: %w", err)
}
if connectionSrc != "" || connectionDst != "" {
if err := a.OverwriteConfigOnTheFly(cmd, pathName, "", "", connectionSrc, connectionDst); err != nil {
return err
}
}
}
// create channel if it isn't already created
return c[src].CreateOpenChannels(cmd.Context(), c[dst], retries, to, srcPort, dstPort, order, version, override, memo, pathName)
return c[src].CreateOpenChannels(cmd.Context(), c[dst], hops, retries, to, srcPort, dstPort, order, version, override, memo, pathName)
},
}
cmd = timeoutFlag(a.Viper, cmd)
Expand Down Expand Up @@ -752,6 +770,9 @@ $ %s tx flush demo-path channel-0`,
// collect unique chain IDs
chains[path.Src.ChainID] = nil
chains[path.Dst.ChainID] = nil
for _, h := range path.Hops {
chains[h.ChainID] = nil
}
} else {
for n, path := range a.Config.Paths {
paths = append(paths, relayer.NamedPath{
Expand All @@ -762,6 +783,9 @@ $ %s tx flush demo-path channel-0`,
// collect unique chain IDs
chains[path.Src.ChainID] = nil
chains[path.Dst.ChainID] = nil
for _, h := range path.Hops {
chains[h.ChainID] = nil
}
}
}

Expand Down
Loading