From 820152b87349032436c3fd017d82fb01c5e4ad12 Mon Sep 17 00:00:00 2001 From: mossid Date: Wed, 14 Mar 2018 16:14:04 +0100 Subject: [PATCH] relayer app --- x/ibc/commands/flags.go | 10 +++ x/ibc/commands/helpers.go | 61 ++++++++++++++ x/ibc/commands/relay.go | 171 ++++++++++++++++++++++++++++++++++++++ x/ibc/commands/send.go | 80 ++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 x/ibc/commands/flags.go create mode 100644 x/ibc/commands/helpers.go create mode 100644 x/ibc/commands/relay.go create mode 100644 x/ibc/commands/send.go diff --git a/x/ibc/commands/flags.go b/x/ibc/commands/flags.go new file mode 100644 index 0000000000..298f3e37db --- /dev/null +++ b/x/ibc/commands/flags.go @@ -0,0 +1,10 @@ +package commands + +const ( + flagTo = "to" + flagAmount = "amount" + flagChain = "chain" + flagChain1 = "chain1" + flagChain2 = "chain2" + flagSequence = "sequence" +) diff --git a/x/ibc/commands/helpers.go b/x/ibc/commands/helpers.go new file mode 100644 index 0000000000..83ae76a90b --- /dev/null +++ b/x/ibc/commands/helpers.go @@ -0,0 +1,61 @@ +package commands + +import ( + "fmt" + + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + wire "github.com/cosmos/cosmos-sdk/wire" +) + +func buildTx(cdc *wire.Codec, msg sdk.Msg) ([]byte, error) { + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + name := viper.GetString(client.FlagName) + + bz := msg.GetSignBytes() + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password to sign with '%s':", name) + passphrase, err := client.GetPassword(prompt, buf) + if err != nil { + return nil, err + } + sig, pubkey, err := keybase.Sign(name, passphrase, bz) + if err != nil { + return nil, err + } + sigs := []sdk.StdSignature{{ + PubKey: pubkey, + Signature: sig, + Sequence: viper.GetInt64(flagSequence), + }} + + tx := sdk.NewStdTx(msg, sigs) + + txBytes, err := cdc.MarshalBinary(tx) + if err != nil { + return nil, err + } + return txBytes, nil +} + +func getAddress() []byte { + keybase, err := keys.GetKeyBase() + if err != nil { + panic(err) + } + + name := viper.GetString(client.FlagName) + info, err := keybase.Get(name) + if err != nil { + panic(err) + } + + return info.Address() +} diff --git a/x/ibc/commands/relay.go b/x/ibc/commands/relay.go new file mode 100644 index 0000000000..5d1cf76ca4 --- /dev/null +++ b/x/ibc/commands/relay.go @@ -0,0 +1,171 @@ +package commands + +import ( + "fmt" + "time" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/builder" + + wire "github.com/cosmos/cosmos-sdk/wire" + + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +func IBCRelayCmd(cdc *wire.Codec) *cobra.Command { + cmdr := relayCommander{cdc, "ibc"} + + cmd := &cobra.Command{ + Use: "relay", + Run: cmdr.runIBCRelay, + } + cmd.Flags().String(flagTo, "", "Address to send coins") + cmd.Flags().String(flagAmount, "", "Amount of coins to send") + cmd.Flags().Int64(flagSequence, 0, "Sequence number to sign the tx") + return cmd +} + +type relayCommander struct { + cdc *wire.Codec + ibcStore string +} + +func (c relayCommander) runIBCRelay(cmd *cobra.Command, args []string) { + chain1 := viper.GetString(flagChain1) + chain2 := viper.GetString(flagChain2) + + go c.loop(chain1, chain2) + go c.loop(chain2, chain1) +} + +// https://github.com/cosmos/cosmos-sdk/blob/master/client/helpers.go using specified address + +func query(id string, key []byte, storeName string) (res []byte, err error) { + orig := viper.GetString(client.FlagNode) + viper.Set(client.FlagNode, id) + res, err = builder.Query(key, storeName) + viper.Set(client.FlagNode, orig) + return res, err +} + +func broadcastTx(id string, tx []byte) error { + orig := viper.GetString(client.FlagNode) + viper.Set(client.FlagNode, id) + _, err := builder.BroadcastTx(tx) + viper.Set(client.FlagNode, orig) + return err +} + +func (c relayCommander) refine(bz []byte, sequence int64) []byte { + var packet ibc.IBCPacket + if err := c.cdc.UnmarshalBinary(bz, &packet); err != nil { + panic(err) + } + address := getAddress() + msg := ibc.IBCReceiveMsg{ + IBCPacket: packet, + Relayer: address, + Sequence: sequence, + } + res, err := buildTx(c.cdc, msg) + if err != nil { + panic(err) + } + return res +} + +func (c relayCommander) loop(fromID, toID string) { + ingressKey := ibc.IngressKey(fromID) + + processedbz, err := query(toID, ingressKey, c.ibcStore) + if err != nil { + panic(err) + } + + var processed int64 + if err = c.cdc.UnmarshalBinary(processedbz, &processed); err != nil { + panic(err) + } + +OUTER: + for { + time.Sleep(time.Second) + + lengthKey := ibc.EgressLengthKey(toID) + egressLengthbz, err := query(fromID, lengthKey, c.ibcStore) + if err != nil { + fmt.Printf("Error querying outgoing packet list length: '%s'\n", err) + continue OUTER + } + var egressLength int64 + if err = c.cdc.UnmarshalBinary(egressLengthbz, &egressLength); err != nil { + panic(err) + } + + for i := processed; i < egressLength; i++ { + egressbz, err := query(fromID, ibc.EgressKey(toID, i), c.ibcStore) + if err != nil { + fmt.Printf("Error querying egress packet: '%s'\n", err) + continue OUTER + } + + err = broadcastTx(toID, c.refine(egressbz, i)) + if err != nil { + fmt.Printf("Error broadcasting ingress packet: '%s'\n", err) + continue OUTER + } + + fmt.Printf("Relayed packet: %d\n", i) + } + + processed = egressLength + } +} + +/* +func (c relayCommander) buildTx() ([]byte, error) { + keybase, err := keys.GetKeyBase() + if err != nil { + return nil, err + } + + name := viper.GetString(client.FlagName) + info, err := keybase.Get(name) + if err != nil { + return nil, fmt.Errorf("No key for: %s, name") + } + from := info.PubKey.Address() + + msg, err := buildMsg(from) + if err != nil { + return nil, err + } + + bz := msg.GetSignBytes() + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password to sign with '%s':", name) + passphrase, err := client.GetPassword(prompt, buf) + if err != nil { + return nil, err + } + sig, pubkey, err := keybase.Sign(name, passphrase, bz) + if err != nil { + return nil, err + } + sigs := []sdk.StdSignature{{ + PubKey: pubkey, + Signature: sig, + Sequence: viper.GetInt64(flagSequence), + }} + + tx := sdk.NewStdTx(msg, sigs) + + txBytes, err := c.cdc.MarshalBinary(tx) + if err != nil { + return nil, err + } + return txBytes, nil +}*/ diff --git a/x/ibc/commands/send.go b/x/ibc/commands/send.go new file mode 100644 index 0000000000..ab4be359c5 --- /dev/null +++ b/x/ibc/commands/send.go @@ -0,0 +1,80 @@ +package commands + +import ( + "encoding/hex" + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/builder" + + sdk "github.com/cosmos/cosmos-sdk/types" + wire "github.com/cosmos/cosmos-sdk/wire" + + "github.com/cosmos/cosmos-sdk/x/ibc" +) + +func IBCTransferCmd(cdc *wire.Codec) *cobra.Command { + cmdr := sendCommander{cdc} + + cmd := &cobra.Command{ + Use: "send", + RunE: cmdr.runIBCTransfer, + } + cmd.Flags().String(flagTo, "", "Address to send coins") + cmd.Flags().String(flagAmount, "", "Amount of coins to send") + cmd.Flags().String(flagChain, "", "Destination chain to send coins") + return cmd +} + +type sendCommander struct { + cdc *wire.Codec +} + +func (c sendCommander) runIBCTransfer(cmd *cobra.Command, args []string) error { + address := getAddress() + msg, err := buildMsg(address) + if err != nil { + return err + } + + txBytes, err := buildTx(c.cdc, msg) + if err != nil { + return err + } + + res, err := builder.BroadcastTx(txBytes) + if err != nil { + return err + } + + fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String()) + return nil +} + +func buildMsg(from sdk.Address) (sdk.Msg, error) { + amount := viper.GetString(flagAmount) + coins, err := sdk.ParseCoins(amount) + if err != nil { + return nil, err + } + + dest := viper.GetString(flagTo) + bz, err := hex.DecodeString(dest) + if err != nil { + return nil, err + } + to := sdk.Address(bz) + + return ibc.IBCTransferMsg{ + IBCPacket: ibc.IBCPacket{ + SrcAddr: from, + DestAddr: to, + Coins: coins, + SrcChain: viper.GetString(client.FlagNode), + DestChain: viper.GetString(flagChain), + }, + }, nil +}