cosmos / relayer-archive Goto Github PK
View Code? Open in Web Editor NEWAn example of a server side IBC relayer to be used for Game of Zones and beyond
An example of a server side IBC relayer to be used for Game of Zones and beyond
Logging needs to be improved around:
The relayer anticipated setting one top level strategy and having all of paths relayed over by one command. After building out the functionality there seems to be a better way. Strategies
should be scoped to Paths
. They should also have Constraints
. The proposal is as follows:
// Path represents a pair of chains and the identifiers needed to
// relay over them
type Path struct {
Src *PathEnd `yaml:"src" json:"src"`
Dst *PathEnd `yaml:"dst" json:"dst"`
Strategy *StrategyCfg `yaml:"strategy" json:"strategy"`
Index int `yaml:"index,omitempty" json:"index,omitempty"`
}
// Strategy defines which relaying strategy to take for a given path
type Strategy struct {
Type string `json:"type" yaml:"type"`
Constraints []Constraint `json:"constraints" yaml:"constraints"`
}
// Constraint defines arguments for a strategies' execution
type Constraint struct {
Type string `json:"type" yaml:"type"`
Value string `json:"value" yaml:"value"`
}
Constraints will be things like "only relay msgs from this address or these addresses" etc..
Strategies will validate
We should move the Chain
struct and all associated code to its own package so that it could be used by other relayer implementations. Ideally we could then move it to the SDK once it has stabilized and us it to refactor CLIContext
with cleaner abstractions.
The following queries for IBC need to be implemented on the relayer. All of these queries should also return proofs. They will be mainly useful for use in tx
commands (as a way to query the chain for the necessary on-chain data) but should also be exposed to the user:
header [chain-id] [height]
- Query the header at a given heightnode-state [chain-id] [height]
- Query the node state at a given height or latest if height not passedclient [chain-id] [client-id]
- Query details for an individual clientclients [chain-id]
- Query the list of clients on a given chainconnection [chain-id] [connection-id]
- Query details for an individual connectionconnections [chain-id] [client-id]
- Query the list of connections associated with a clientchannel [chain-id] [connection-id] [channel-id]
- Query details for an individual channelchannels [chain-id] [connection-id]
- Query the list of channels associated with a clientseq-send [chain-id] [channel-id]
- Query the seq-send
for the configured key on a given chain and channelseq-recv [chain-id] [channel-id]
- Query the seq-recv
for the configured key on a given chain and channelpacket-commitment
packet-ack
packet-timeout
packet-data
- NOTE: This should be implemented by querying a full node with specific indices setupEach individual IBC transaction should be able to be run by the relayer individually as well as in logical groupings (channel
, connection
). These primitives can then be combined in strategies.go
in a number of ways.
The following are the necessary txs:
client [src-chain-id] [dst-chain-id] [client-id]
update-client [src-chain-id] [dst-chain-id] [client-id]
clients [src-chain-id] [dst-chain-id] [src-client-id] [dst-client-id]
connection [src-chain-id] [dst-chain-id] [src-client-id] [dst-client-id] [src-connection-id] [dst-connection-id]
connection-step [src-chain-id] [dst-chain-id] [src-client-id] [dst-client-id] [src-connection-id] [dst-connection-id]
channel [src-chain-id] [dst-chain-id] [src-connection-id] [dst-connection-id] [src-channel-id] [dst-channel-id] [src-port-id] [dst-port-id]
channel-step [src-chain-id] [dst-chain-id] [src-connection-id] [dst-connection-id] [src-channel-id] [dst-channel-id] [src-port-id] [dst-port-id]
flush-chan [src-chain-id] [dst-chain-id] [src-channel-id] [src-port-id]
raw
conn-init
conn-try
conn-ack
conn-confirm
chan-init
chan-try
chan-ack
chan-confirm
chan-close-init
chan-close-confirm
Currently there is an intermediate type that solely parses the config:
// ChainConfig describes the config necessary for an individual chain
// TODO: Are there additional parameters needed here
type ChainConfig struct {
Key string `yaml:"key" json:"key"`
ChainID string `yaml:"chain-id" json:"chain-id"`
RPCAddr string `yaml:"rpc-addr" json:"rpc-addr"`
AccountPrefix string `yaml:"account-prefix" json:"account-prefix"`
Gas uint64 `yaml:"gas,omitempty" json:"gas,omitempty"`
GasAdjustment float64 `yaml:"gas-adjustment,omitempty" json:"gas-adjustment,omitempty"`
GasPrices string `yaml:"gas-prices,omitempty" json:"gas-prices,omitempty"`
DefaultDenom string `yaml:"default-denom,omitempty" json:"default-denom,omitempty"`
Memo string `yaml:"memo,omitempty" json:"memo,omitempty"`
TrustingPeriod string `yaml:"trusting-period" json:"trusting-period"`
}
Right now it is doing a lot of initialization that needs to be refactored out. This should be done by looping over config.Chains
after parsing of the config file. Each chain would call an InitDBsAndClients
function that would substantially do what relayer.NewChain
does
// Chain represents the necessary data for connecting to and indentifying a chain and its counterparites
type Chain struct {
Key string `yaml:"key"`
ChainID string `yaml:"chain-id"`
RPCAddr string `yaml:"rpc-addr"`
AccountPrefix string `yaml:"account-prefix"`
Gas uint64 `yaml:"gas,omitempty"`
GasAdjustment float64 `yaml:"gas-adjustment,omitempty"`
GasPrices sdk.DecCoins `yaml:"gas-prices,omitempty"`
DefaultDenom string `yaml:"default-denom,omitempty"`
Memo string `yaml:"memo,omitempty"`
TrustingPeriod time.Duration `yaml:"trusting-period"`
HomePath string
PathEnd *PathEnd
Keybase keys.Keybase
Client *rpcclient.HTTP
Cdc *codec.Codec
address sdk.AccAddress
logger log.Logger
}
Currently all the msg creation functions are defined on the Chain
type. Initially this decision was made because I expected to have to query data during message construction. The architecture I've ended up with avoids this to allow for more flexibility in defining where proofs come from. We should redefine these functions as follows:
// Now
func (src *Chain) Msg*(dst *Chain, args...) sdk.Msg {}
// New
func (src PathEnd) Msg*(dst PathEnd, args...) sdk.Msg {}
The relayer should have some options for how to handle transactions that fail for insufficient fees. One idea is to provide an slack, telegram or other outputs for these alerts.
or somebody attacking one of the light clients of the relayer.
I'm considering changing the relayer config from the current format (where chains own their counterparties) to a format where relay paths are a separate and explicit field section.
// Config represents the config file for the relayer
type Config struct {
Global GlobalConfig `yaml:"global" json:"global"`
Chains []ChainConfig `yaml:"chains" json:"chains"`
c relayer.Chains
}
// GlobalConfig describes any global relayer settings
type GlobalConfig struct {
Strategy string `yaml:"strategy" json:"strategy"`
Timeout string `yaml:"timeout" json:"timeout"`
LiteCacheSize int `yaml:"lite-cache-size" json:"lite-cache-size"`
}
// ChainConfig describes the config necessary for an individual chain
// TODO: Are there additional parameters needed here
type ChainConfig struct {
Key string `yaml:"key" json:"key"`
ChainID string `yaml:"chain-id" json:"chain-id"`
RPCAddr string `yaml:"rpc-addr" json:"rpc-addr"`
AccountPrefix string `yaml:"account-prefix" json:"account-prefix"`
Counterparties []CounterpartyConfig `yaml:"counterparties" json:"counterparties"`
Gas uint64 `yaml:"gas,omitempty" json:"gas,omitempty"`
GasAdjustment float64 `yaml:"gas-adjustment,omitempty" json:"gas-adjustment,omitempty"`
GasPrices string `yaml:"gas-prices,omitempty" json:"gas-prices,omitempty"`
DefaultDenom string `yaml:"default-denom,omitempty" json:"default-denom,omitempty"`
Memo string `yaml:"memo,omitempty" json:"memo,omitempty"`
TrustingPeriod string `yaml:"trusting-period" json:"trusting-period"`
}
// CounterpartyConfig represents a chain's counterparty
type CounterpartyConfig struct {
ChainID string `yaml:"chain-id" json:"chain-id"`
ClientID string `yaml:"client-id" json:"client-id"`
}
// Config represents the config file for the relayer
type Config struct {
Global GlobalConfig `yaml:"global" json:"global"`
Chains []ChainConfig `yaml:"chains" json:"chains"`
Paths []Path `yaml:"paths" json:"paths"`
c relayer.Chains
}
// GlobalConfig describes any global relayer settings
type GlobalConfig struct {
Strategy string `yaml:"strategy" json:"strategy"`
Timeout string `yaml:"timeout" json:"timeout"`
LiteCacheSize int `yaml:"lite-cache-size" json:"lite-cache-size"`
}
// ChainConfig describes the config necessary for an individual chain
// TODO: Are there additional parameters needed here
type ChainConfig struct {
Key string `yaml:"key" json:"key"`
ChainID string `yaml:"chain-id" json:"chain-id"`
RPCAddr string `yaml:"rpc-addr" json:"rpc-addr"`
AccountPrefix string `yaml:"account-prefix" json:"account-prefix"`
Gas uint64 `yaml:"gas,omitempty" json:"gas,omitempty"`
GasAdjustment float64 `yaml:"gas-adjustment,omitempty" json:"gas-adjustment,omitempty"`
GasPrices string `yaml:"gas-prices,omitempty" json:"gas-prices,omitempty"`
DefaultDenom string `yaml:"default-denom,omitempty" json:"default-denom,omitempty"`
Memo string `yaml:"memo,omitempty" json:"memo,omitempty"`
TrustingPeriod string `yaml:"trusting-period" json:"trusting-period"`
}
type Path [2]PathEnd
// CounterpartyConfig represents a chain's counterparty
type PathEnd struct {
ChainID string `yaml:"chain-id" json:"chain-id"`
ClientID string `yaml:"client-id" json:"client-id"`
ConnectionID string `yaml:"connection-id" json:"connection-id"`
ChannelID string `yaml:"channel-id" json:"channel-id"`
PortID string `yaml:"port-id" json:"port-id"`
}
When creating another client for the same chain with a different ID there is an error. To reproduce:
$ relayer tx clients ibc0 ibc1 ibconeclient ibczeroclient
$ relayer tx clients ibc0 ibc1 otheridentone otheridentzero
{"height":"1534","txhash":"AAA41FDDB1657D0633BD93725DA8970D7EEA8C8A73DEDFF6EA8E7E310C6DD25C","codespace":"client","code":1,"raw_log":"internal error","gas_wanted":"200000","gas_used":"45751"}
{"height":"1535","txhash":"93F4DCD683CCFA9AD9AB602C09B1A558A0B05FCCF7482B9761C8E9240BB111F7","codespace":"client","code":1,"raw_log":"internal error","gas_wanted":"200000","gas_used":"45751"}
Use the github actions cache to cache build deps and speed up builds
updatePeriod is never used
var (
lcMap map[string]*lite.Client // chainID => client
trustedHash []byte
trustedHeight int64
trustingPeriod time.Duration
updatePeriod time.Duration
url string
)
Instead the update period for the lite client is set as lite.UpdatePeriod(c.TrustOptions.Get().Period))
where the trusted period is set here:
if trustingPeriod > 0 {
chain.TrustOptions.Period = trustingPeriod.String()
}
Currently unbonding time is hardcoded in the client creation command. We should have this be populated via the chain configuration.
When I followed the demo instructions to run a cross chain transfer, I found that the if the command rly tx transfer ibc0 ibc1 10000n0token true $(rly keys show ibc1 testkey)
failed, the balance in ibc0 will reduce and can't get rollbacked. Is there any atmoic swap guarantee mechanism in ibc now or any support in future plan?
Hello!
I tried setting two chains using gaia, and then use the relayer to do IBC transactions. The commands/instructions were taken from the Readme.md from the master branch.
The two chains launched successfully, and I was able to query the balances of the two accounts by using the rly executable.
When I execute rly tx full-path demo-path
, an error message channel capability not found
was given as output.
[2020-04-16|16:28:55.502] ✔ [ibc0]@{7} - msg(0:create_client) hash(2FFD0936A8B2987F65FD4315548274882866E2C01B5A2ED2AAD6FAD9FFA74682)
I[2020-04-16|16:29:00.517] ✔ [ibc1]@{8} - msg(0:create_client) hash(5F17BC7D8B0FF0CC94386986BDF6B71A5030EE9D18A48663AB613E392A47C097)
I[2020-04-16|16:29:00.517] ★ Clients created: [ibc0]client(ibconeclient) and [ibc1]client(ibczeroclient)
I[2020-04-16|16:29:05.534] ✔ [ibc0]@{9} - msg(0:connection_open_init) hash(A20240500D73B01855E93629A4728935FAAE91BEC9CD8CAFA34210F71ECF7968)
I[2020-04-16|16:29:15.571] ✘ [ibc0]@{11} - msg(0:connection_open_init) err(connection: connection already exists)
I[2020-04-16|16:29:20.588] ✔ [ibc1]@{12} - msg(0:update_client,1:connection_open_try) hash(B86B7FE51B987B2F84FC2C33DE84D10E010B4FDBF3A716A911E31B01AA3692E9)
I[2020-04-16|16:29:30.593] ✔ [ibc0]@{14} - msg(0:update_client,1:connection_open_ack) hash(13145B9303FC95DEACADE6DA8A31A14E951F8241CA21708B128E4133E25A6A2D)
I[2020-04-16|16:29:40.626] ✔ [ibc1]@{16} - msg(0:update_client,1:connection_open_confirm) hash(601D77195F83B634D2D505EB16A9864D23B1E244EB47F0BC1DF68F35E07CC006)
I[2020-04-16|16:29:40.628] ★ Connection created: [ibc0]client{ibconeclient}conn{ibconeconnection} -> [ibc1]client{ibczeroclient}conn{ibczeroconnection}
I[2020-04-16|16:29:45.647] codespace for port(3) not found in map
I[2020-04-16|16:29:45.647] ✘ [ibc0]@{17} - msg(0:channel_open_init) err(port: )
I[2020-04-16|16:29:55.648] ✘ [ibc0]@{19} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:05.675] ✘ [ibc0]@{21} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:10.690] ✘ [ibc0]@{22} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:20.731] ✘ [ibc0]@{24} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:30.734] ✘ [ibc0]@{26} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:40.762] ✘ [ibc0]@{28} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:30:50.759] ✘ [ibc0]@{30} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:31:00.785] ✘ [ibc0]@{32} - msg(0:channel_open_init) err(channels: channel capability not found)
I[2020-04-16|16:31:10.813] ✘ [ibc0]@{34} - msg(0:channel_open_init) err(channels: channel capability not found)
If I try to do an ibc transfer I get the following error.
$ rly tx transfer ibc0 ibc1 100n0token true $(rly keys show ibc1 testkey) -d
I[2020-04-16|16:32:58.676] - [ibc0] -> sending transaction:
[{"type":"ibc/transfer/MsgTransfer","value":{"source_port":"transfer","source_channel":"ibconexfer","dest_height":"55","amount":[{"denom":"transfer/ibczeroxfer/n0token","amount":"100"}],"sender":"cosmos19j5q2jk0w7e2al4n0dvrkq8th99ckkzf4z3zu0","receiver":"cosmos1efpetuadqethted77e2uytj4tgsn79378td5a7","source":true}}]
I[2020-04-16|16:32:58.676] ✘ [ibc0]@{0} - msg(0:transfer) err(sdk: unauthorized)
{"height":"0","txhash":"D82B327055FD9128784EAEA78FFDE24EF2BC7F30B5FA59DD70B86BA3733DA5DD","codespace":"sdk","code":4,"raw_log":"signature verification failed; verify correct account sequence and chain-id: unauthorized","gas_wanted":"200000","gas_used":"38995"}
Error: failed to send first transaction
Usage:
rly transactions transfer [src-chain-id] [dst-chain-id] [amount] [is-source] [dst-chain-addr] [flags]
Aliases:
transfer, xfer
Flags:
-h, --help help for transfer
-p, --path string specify the path to relay over
Global Flags:
--config string set config file (default "config.yaml")
-d, --debug debug output
--home string set home directory (default "/root/.relayer")
failed to send first transaction
Could this be some misconfiguration by my side?
Thanks a lot!
➜ relayer git:(master) ✗ make
running GolangCI-Lint...
cmd/flags.go:137:17: Error return value of `viper.BindPFlag` is not checked (errcheck)
viper.BindPFlag(flagURL, cmd.Flags().Lookup(flagURL))
^
cmd/raw.go:59:11: nilness: impossible condition: nil != nil (govet)
if err != nil {
^
make: *** [ci-lint] Error 1
Command rly query txs [chain-id] [events] [flags]
ignores --limit
, and --page
flags, and always uses defaults.
// PathEnd represents the local connection identifers for a relay path
// The path is set on the chain before performing operations
type PathEnd struct {
ChainID string `yaml:"chain-id,omitempty" json:"chain-id,omitempty"`
ClientID string `yaml:"client-id,omitempty" json:"client-id,omitempty"`
ConnectionID string `yaml:"connection-id,omitempty" json:"connection-id,omitempty"`
ChannelID string `yaml:"channel-id,omitempty" json:"channel-id,omitempty"`
PortID string `yaml:"port-id,omitempty" json:"port-id,omitempty"`
Order string `yaml:"order,omitempty" json:"order,omitempty"
}
This change also needs to be reflected in the configuration, validation and transactions. Likely we should default to ORDERED
if the prop is not passed in
Should we recreate a light client each time we need one, to avoid locking the database, or should we alternatively find some way of persisting a light client instance without having the light client lock the database (maybe we can make all our calls using the light client API)?
Lite client only has a primary provider but not the ability to add alternative providers for verifying headers.
The relayer start command is currently worse than a stub. The basic design is there, but there are many implementation details to be worked out. Also once the transactions and queries for the relayer are created, they can easily be composed into strategies. Some potential strategies:
The subscribe relayer strategy should be the primary mode that the relayer is run under. It will c.Client.Subscribe("ibc-events")
to each chain and then take the necessary actions to relay packets between chains.
This mode will Subscribe
to all chains in the Config
and error if all primitives in Paths
are not setup. This is necessary because the data for Packet
s are not stored in state and are best handled this way.
The relayer should also have a mode for querying against a node with certain indices setup to fetch this data.
➜ relayer git:(master) ✗ relayer q balance ibc1
query functionality for configured chains
Usage:
relayer query [command]
Aliases:
query, q
Available Commands:
account Use configured RPC client to fetch the account balance of the relayer account
channel Query the client for a counterparty chain
channels Query for all channels on a given chain
client Query the client for a counterparty chain
client-connections Query the client for a counterparty chain
clients Query the client for a counterparty chain
connection Query the client for a counterparty chain
connections Query for all connections on a given chain
header Use configured RPC client to fetch a header at a given height from a configured chain
node-state Query the consensus state of a client at a given height, or at latest height if height is not passed
packet-ack Query the commitment for a given packet
packet-commit Query the commitment for a given packet
seq-send Query the next sequence send for a given channel
Flags:
-h, --help help for query
Global Flags:
--config string set config file (default "config.yaml")
--home string set home directory (default "/Users/jiang/.relayer")
Use "relayer query [command] --help" for more information about a command.
subcommand is required
I observed that if I send a packet data or ack consisting of []byte{}
, then the relayer cannot relay it. Sorry, but I don't have exact logs here.
This is consistent with an observation I made a while ago. Amino, and Proto3 both can't round-trip an empty slice.
type MyStruct struct {
Data []byte
}
Marshalling and unmarshalling the following:
ms := MyStruct{
Data: []byte{},
}
Results in:
MyStruct{
Data: nil,
}
Special treatment is needed to accommodate these empty values (replacing nil
slices with empty slices before signing and after deserialising before verifying).
I don't know if I'll get to this for a while, but I thought I'd at least put it on people's radar.
Thanks,
Michael.
As a follow-on from cosmos/relayer#49, there are a couple of features I would like to see added to relayer chains add
.
relayer chains add --url [url]
- This would fetch the json and add the chain after verifying it. Think usage from a github repo (https://raw.githubusercontent.com/cosmos/relayer/tree/master/demo/ibc0.json)relayer chains add --cosmos [url]
- This would query the /genesis
endpoint to fetch most of the data and then would rely on sane defaults for gas
and gasPrices
based on that. This is basically figuring out how to unmarshal gaia based config....
ayer/relayer/verifier.go:310:7: hs.Lock undefined (type *heights has no field or method Lock) /root/project/relayer/relayer/verifier.go:312:7: hs.Unlock undefined (type *heights has no field or method Unlock) /root/project/relayer/relayer/path.go:6:2: "gopkg.in/yaml.v2" imported but not used]]
WARN [runner] Can't run linter unused: buildir: failed to load package runtime: could not load export data: no export data for "runtime"
ERRO Running error: buildir: failed to load package runtime: could not load export data: no export data for "runtime"
Makefile:49: recipe for target 'ci-lint' failed
make: *** [ci-lint] Error 3
There are currently a series of commands in cmd/lite.go
that need to be implemented. The logic should be implemented in relayer/verifier.go
and then wired up to the CLI in cmd/lite.go
.
cc @melekes
~/go/src/github.com/cosmos/relayer$ rly paths add ibc0 ibc1 demo-path -f demo/path.json
Error: channel must be either 'ORDERED' or 'UNORDERED' is ''
channel must be either 'ORDERED' or 'UNORDERED' is ''
Currently the channel and connection commands run on a timeout. They will continue to block until they are either exited, or have no more messages to create, at which point they break. This can be improved to:
open-confirm
message is successfulThis will likely involve moving the queries out of the ChannelStep
and ConnectionStep
functions or improving the error handling and returns there.
➜ ✗ relayer paths add --file demo/path.json
Error: accepts 2 arg(s), received 0
Usage:
relayer paths add [src-chain-id] [dst-chain-id] [flags]
Flags:
-f, --file string fetch json data from specified file
-h, --help help for add
Global Flags:
--config string set config file (default "config.yaml")
--home string set home directory (default "/Users/jiang/.relayer")
accepts 2 arg(s), received 0
Are users predominantly going to use the package through cli? How else will the package be used?
Blocked By: cosmos/cosmos-sdk#5588
The relayer should be able to implement this primarily in the *cobra.Command.Args
functions: https://github.com/spf13/cobra#positional-and-custom-arguments
This should help keep the code clean, encourage reuse, and provide more instructive error messages
Currently the relayer uses the file backend from 99deisgns/keyring
to store all key material. We should also look at the ability to use a ubihsm or other hardware key.
Lite client should not be initiated with the roots of trust from the configuration file but instead be initiated separately through the command line by either passing a header hash and height or a corresponding url. Each chain should have a non expired root of trust in order for the relayer between them to operate else an error should be thrown.
Note that the app hash stored at height n
is for height n - 1
. Ref https://github.com/cosmos/cosmos-sdk/pull/5711/files#r387563476.
There needs to be a release and versioning strategy for this repository. I propose to keep it in line withcosmos-sdk
versioning with an option for dev
releases. This should be able to be easily accomplished with github actions. Releases should contain built binaries for macos
and linux
and should be able to be triggered by v*
tag pushes. The built binaries should also be able to report their version through relayer version
Gaia and Rly checkouts b617e2b
& 2282f8b
I have a full "connected" status: chns(✔️) clnts(✔️) conn(✔️) chan(✔️) however all my rly transact raw update-client
calls end with code: 6.
I never had any other response, restarts or re-inits with -f do not help. Any ides ?
Here is example output:
{"height":"0","txhash":"29919AA27188D3295FD127B2CB6F6FDD47633F20F0BEF8B0EC3F880C9FB76880","codespace":"client","code":6,"gas_wanted":"200000","gas_used":"50898"}
Following the instructions in the readme, issuing the transfer command gives a "channel not found" error. Not sure how to debug or proceed.
$ rly tx transfer ibc0 ibc1 10000n0token true $(rly keys show ibc1 testkey -a)
I[2020-03-22|09:40:38.752] ✘ [ibc0]@{613} - msg(transfer) err(channels: channel not found)
Error: failed to send first transaction
$ rly version
version: 0.1.0-35-g4638dc5
commit: 4638dc5
cosmos-sdk: v0.34.4-0.20200318160616-b8295506615b
go: go1.14 linux/amd64
$ gaiad version
0.0.0-239-gfe439e5
When trying to update an existing client the following error is output
$ relayer tx clients ibc0 ibc1 ibconeclient ibczeroclient
$ relayer tx update-client ibc0 ibc1 ibconeclient
{"height":"0","txhash":"CCB5F99DA32E4B4273F1DED9DB0330F53C14B18E3F61CE763053FF1D0FE34E81","codespace":"client","code":9,"raw_log":"invalid block header: signedHeader belongs to another chain 'ibc1' not 'ibc0': cannot update client with ID ibconeclient","gas_wanted":"200000","gas_used":"46709"}
$ relayer tx update-client ibc1 ibc0 ibczeroclient
{"height":"0","txhash":"0DE65516AE1C960792D3C4D4E24F21BB62C372FB9A47D07E16ECCC1CE23C96BA","codespace":"client","code":9,"raw_log":"invalid block header: signedHeader belongs to another chain 'ibc0' not 'ibc1': cannot update client with ID ibczeroclient","gas_wanted":"200000","gas_used":"46722"}
Should a lite client for every chain specified in the config file be automatically generated upon startup of the relayer?
when rly tx link demo
I got error:
E[2020-10-09|16:59:51.815] - [ibc0] -> err(decoding bech32 failed: invalid character in string: '�': invalid request)
E[2020-10-09|16:59:51.818] - [ibc1] -> err(decoding bech32 failed: invalid character in string: '¦': invalid request)
ibconeclient: light client not found
How to debug it or fix it?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.